6

我在使用工作时遇到一些问题uinput

基于uinput 入门:用户级输入子系统[死链接;archived ]我将以下编写器放在一起减去错误处理):

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结构。

我犯了什么愚蠢的错误?

4

2 回答 2

6

您还应该在实际事件之后编写同步事件。在您的作家端代码中:

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();
于 2014-11-27T08:51:51.077 回答
0

TL;DR:内核期望EV_SYN代码事件,SYN_REPORT因为单个事件可以组合在一起,即,当它们发生在同一时间点时。


您可以将其视为解释一组事件的内核,而不是struct input_event. 一个EV_SYN事件用SYN_REPORTas 代码分隔这些事件组,即,这为同时发生的事件提供了一种分组机制。

例如,假设您用手指触摸触摸板的表面:

触摸板

给定struct input_eventin的定义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 */
};

不可能创建一个可以同时保存代码和的单个EV_ABS事件,以及分别用于指定xy坐标的值 - 1中只有一个成员。ABS_XABS_Ycodestruct input_event

相反,将创建两个 EV_ABS事件2 :

  • 一个代码ABS_Xx坐标为value
  • 另一个代码ABS_Yy坐标为value

将这两个事件解释为时间上分开的两个事件是不完全正确的,即一个表示 x 坐标的变化,另一个表示时间较晚并表示 y 坐标的变化。

而不是两个在时间上分离的事件,这些事件应该组合在一起并由内核解释为单个输入数据变化单元,它指示xy坐标同时发生变化。这就是存在上述机制的原因:通过在这两个事件(即和)之后使用代码EV_SYN生成一个EV_SYN事件,我们能够将它们组合为一个单元。SYN_REPORTEV_ABSABS_XABS_Y


1这与astruct input_event的大小固定,不能任意增长直接相关。

2从技术上讲,可能会创建更多事件。例如,可能会创建另一个EV_KEY带有代码的类型的事件。BTN_TOUCH然而,这与我想表达的观点无关。

于 2021-10-11T18:17:41.090 回答