Mimic Keyboard for Weston

I’m trying to wrote a simple program (in C) that mimics a keypress to Weston.
For example: If I plug in a keyboard and press the letter b, while I’m running a Weston container I get this output - torizon-weston-1 | [1897942.998] → wl_keyboard@17.key(14, 14026873, 48, 1)

I want to write a program that when executed ( ie ./keypress) will trigger the same output from Weston. I thought I had to write to /dev/uinput. There is a couple of c/c++ example to do that. But the uinput is not writable from inside the container.

What other ways can I accomplish this, either in code or via the command line.

Hi, I’m the Toradex AI Assistant. The Toradex Support team will follow up with you shortly!

Did you like my answer?

:+1: :-1:


To mimic a keypress to Weston from within a container, you are correct that /dev/uinput is typically used for simulating input events. However, since /dev/uinput is not writable from inside the container, you have a couple of options to work around this limitation:

Option 1: Modify Container Permissions

You can modify the container’s permissions to allow access to /dev/uinput. This involves running the container with additional privileges and explicitly mapping the device.

  1. Run the container with --privileged flag:
    This flag gives the container extended privileges, which includes access to /dev/uinput.

    docker run --privileged -v /dev/uinput:/dev/uinput <your-container-image>
    
  2. Ensure /dev/uinput is available inside the container:
    You can verify this by checking the device inside the container.

    docker exec -it <container-id> ls -l /dev/uinput
    

Option 2: Use Host System to Inject Events

If modifying the container permissions is not feasible, you can run a program on the host system that injects the keypress events into the container.

  1. Write a program on the host system to simulate keypress events:
    You can use a C/C++ program that writes to /dev/uinput on the host system.

  2. Communicate with the container:
    Use a mechanism like a socket or a shared file to trigger the keypress event from the container. The container can send a signal to the host program to simulate the keypress.

Example C Program to Simulate Keypress

Here is a simple example of a C program that simulates a keypress using /dev/uinput:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/uinput.h>

int main() {
    int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
    if (fd < 0) {
        perror("open");
        return 1;
    }

    struct uinput_setup usetup;
    ioctl(fd, UI_SET_EVBIT, EV_KEY);
    ioctl(fd, UI_SET_KEYBIT, KEY_B);

    memset(&usetup, 0, sizeof(usetup));
    snprintf(usetup.name, UINPUT_MAX_NAME_SIZE, "uinput-keyboard");
    usetup.id.bustype = BUS_USB;
    usetup.id.vendor = 0x1234;
    usetup.id.product = 0x5678;
    usetup.id.version = 1;

    ioctl(fd, UI_DEV_SETUP, &usetup);
    ioctl(fd, UI_DEV_CREATE);

    sleep(1);

    struct input_event ev;
    memset(&ev, 0, sizeof(ev));
    ev.type = EV_KEY;
    ev.code = KEY_B;
    ev.value = 1;
    write(fd, &ev, sizeof(ev));

    ev.type = EV_SYN;
    ev.code = SYN_REPORT;
    ev.value = 0;
    write(fd, &ev, sizeof(ev));

    ev.type = EV_KEY;
    ev.code = KEY_B;
    ev.value = 0;
    write(fd, &ev, sizeof(ev));

    ev.type = EV_SYN;
    ev.code = SYN_REPORT;
    ev.value = 0;
    write(fd, &ev, sizeof(ev));

    sleep(1);
    ioctl(fd, UI_DEV_DESTROY);
    close(fd);

    return 0;
}

Running the Program

  1. Compile the program:

    gcc -o keypress keypress.c
    
  2. Run the program on the host system:

    sudo ./keypress
    

This program will simulate pressing and releasing the ‘b’ key. You can adapt this approach to communicate with your container and trigger the keypress event as needed.

If you need further assistance or specific details about your setup, please provide more context or details about your environment.

Please, also check if these links can help you solve your problem:

Weston-keyboard not working.

The AI actually helped. I got it working. I’ll document and send it along for reference.

Hey @jeffbelz,

Glad to hear it! Still looking into your other question regarding weston.

-Eric

The AI actually helped. I got it working. I’ll document and send it along for reference.

Just a little extra suggestion. The AI suggested to use the --privileged flag to get around the permission issues inside the container. This does work, though some people find using the --privileged flag not ideal since it gives the container a lot of access/power.

As an alternative you can instead use the following cgroup with your container --device-cgroup-rule='c 10:223 rmw'. On a quick test this allows allows use of /dev/uninput inside the container. Though whatever application is doing the accessing will need to be done by the root user in the container, since /dev/uinput is owned by root. You might be able to do a udev rule or something to change ownership of /dev/uninput if you don’t want to run things as root.

If you don’t mind using --privileged though, then you can disregard all this.

Best Regards,
Jeremias