Linux UINPUT: простой пример?

У меня проблемы с получением обеих сторон кода с помощью uinput за работой.

Основано на Приступая к работе с uinput: подсистема ввода пользовательского уровня [dead link; заархивировал ] я собрал следующий писатель (минус обработка ошибок):

int main(int ac, char **av)
{
    int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
    int ret = ioctl(fd, UI_SET_EVBIT, EV_ABS);
    ret = ioctl(fd, UI_SET_ABSBIT, ABS_X);

    struct uinput_user_dev uidev = {0};
    snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-rotary");
    uidev.absmin[ABS_X] = 0;
    uidev.absmax[ABS_X] = 255;
    ret = write(fd, &uidev, sizeof(uidev));
    ret = ioctl(fd, UI_DEV_CREATE);

    struct input_event ev = {0};
    ev.type = EV_ABS;
    ev.code = ABS_X;
    ev.value = 42;

    ret = write(fd, &ev, sizeof(ev));

    getchar();

    ret = ioctl(fd, UI_DEV_DESTROY);
    return EXIT_SUCCESS;
}

Это, кажется, работает, по крайней мере, полный input_event структура, кажется, написана.

Затем я написал самый наивный читатель событий, которые я мог придумать:

int main(int ac, char **av)
{
    int fd = open(av[1], O_RDONLY);

    char name[256] = "unknown";
    ioctl(fd, EVIOCGNAME(sizeof(name)), name);
    printf("reading from %s\n", name);

    struct input_event ev = {0};
    int ret = read(fd, &ev, sizeof(ev));
    printf("Read an event! %i\n", ret);
    printf("ev.time.tv_sec: %li\n", ev.time.tv_sec);
    printf("ev.time.tv_usec: %li\n", ev.time.tv_usec);
    printf("ev.type: %hi\n", ev.type);
    printf("ev.code: %hi\n", ev.code);
    printf("ev.value: %li\n", ev.value);

    return EXIT_SUCCESS;
}

К сожалению, читательская сторона вообще не работает; только удается прочитать 8 байтов каждый раз, что не является почти полным input_event состав.

Какую глупую ошибку я делаю?

2 ответа

Решение

Вы также должны писать событие синхронизации после фактического события. В вашем коде стороны писателя:

struct input_event ev = {0};
ev.type = EV_ABS;
ev.code = ABS_X;
ev.value = 42;

usleep(1500);

memset(&ev, 0, sizeof(ev));
ev.type = EV_SYN;
ev.code = 0;
ev.value = 0;

ret = write(fd, &ev, sizeof(ev));

getchar();

TL;DR: ядро ​​ожидает события кода, потому что отдельные события могут быть сгруппированы вместе, т. Е. Когда они происходят в один и тот же момент времени.


Вы можете думать об этом как о ядре, интерпретирующем группу событий, а не отдельные события, как указано в. Событие ограничивает эти группы событий кодом, т. Е. Это обеспечивает механизм группировки для сигнализации событий, которые происходят одновременно.

Например, представьте, что вы касаетесь пальцем поверхности тачпада:

Учитывая определение in linux/input.h:

      struct input_event {
/* ... */
__u16 type;   /* e.g., EV_ABS, EV_REL */
__u16 code;   /* e.g., ABS_X for EV_ABS */
__s32 value;  /* e.g., the value of the x coordinate for ABS_X */
};

Невозможно создать одно событие, которое может содержать как коды и, так и значения для указания координат x и y соответственно - есть только одно codeчлен в 1 .

Вместо этого будут созданы два события 2 :

  • Один с кодом и координатой x как.
  • Другой с кодом и координатой y как value.

Было бы не совсем правильно интерпретировать эти два события как два события, разделенных во времени, то есть одно, которое указывает на изменение координаты x, а другое, которое происходит позже во времени и указывает на изменение координаты y.

Вместо двух событий, разделенных по времени, эти события должны быть сгруппированы вместе и интерпретированы ядром как единая единица изменения входных данных, которая указывает на изменение координат x и y одновременно . Вот почему существует описанный выше механизм: генерируя один EV_SYN мероприятие с SYN_REPORT код сразу после этих двух EV_ABS события (т. е. ABS_X а также ABS_Y), мы можем сгруппировать их как единое целое.


1 Это напрямую связано с тем, что struct input_event имеет фиксированный размер и не может увеличиваться произвольно.

2 Технически может быть создано больше событий. Например, другое событие типа EV_KEY с кодом BTN_TOUCHскорее всего будет создан. Однако это не имеет отношения к тому, о чем я хочу сказать.

Другие вопросы по тегам