kernel/Documentation/input/uinput.rst

Introduction

uinput是一个内核模块,能够从用户空间模仿输出设施。通过写入/dev/uinput(或 /dev/input/uinport)设施,过程能够创立具备特定性能的虚构输出设施。一旦创立了这个虚构设施,过程就能够通过它发送事件,这些事件将传递给用户空间和内核中事件消费者。

Interface

linux/uinput.h

uinpu t头定义 ioctl 来创立、设置和销毁虚构设施。

libevdev

libevdev 是 evdev设施的包装库,它提供了创立 uinput设施和发送事件的接口。libevdev比间接拜访uinput 更不容易出错,新软件应该思考应用此形式。

无关 libevdev 的示例和更多信息: https://www.freedesktop.org/s...

Examples

Keyboard events

第一个示例演示了如何创立新的虚构设施,以及如何发送要害事件。为了简略起见,删除了所有默认导入和谬误处理程序。

   #include <linux/uinput.h>   void emit(int fd, int type, int code, int val)   {      struct input_event ie;      ie.type = type;      ie.code = code;      ie.value = val;      /* timestamp values below are ignored */      ie.time.tv_sec = 0;      ie.time.tv_usec = 0;      write(fd, &ie, sizeof(ie));   }   int main(void)   {      struct uinput_setup usetup;      int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);      /*       * The ioctls below will enable the device that is about to be       * created, to pass key events, in this case the space key.       */      ioctl(fd, UI_SET_EVBIT, EV_KEY);      ioctl(fd, UI_SET_KEYBIT, KEY_SPACE);      memset(&usetup, 0, sizeof(usetup));      usetup.id.bustype = BUS_USB;      usetup.id.vendor = 0x1234; /* sample vendor */      usetup.id.product = 0x5678; /* sample product */      strcpy(usetup.name, "Example device");      ioctl(fd, UI_DEV_SETUP, &usetup);      ioctl(fd, UI_DEV_CREATE);      /*       * On UI_DEV_CREATE the kernel will create the device node for this       * device. We are inserting a pause here so that userspace has time       * to detect, initialize the new device, and can start listening to       * the event, otherwise it will not notice the event we are about       * to send. This pause is only needed in our example code!       */      sleep(1);      /* Key press, report the event, send key release, and report again */      emit(fd, EV_KEY, KEY_SPACE, 1);      emit(fd, EV_SYN, SYN_REPORT, 0);      emit(fd, EV_KEY, KEY_SPACE, 0);      emit(fd, EV_SYN, SYN_REPORT, 0);      /*       * Give userspace some time to read the events before we destroy the       * device with UI_DEV_DESTROY.       */      sleep(1);      ioctl(fd, UI_DEV_DESTROY);      close(fd);      return 0;   }       

Mouse movements

这个例子展现了如何创立一个行为相似于物理鼠标的虚构设施。

   #include <linux/uinput.h>   /* emit function is identical to of the first example */   int main(void)   {      struct uinput_setup usetup;      int i = 50;      int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);      /* enable mouse button left and relative events */      ioctl(fd, UI_SET_EVBIT, EV_KEY);      ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);      ioctl(fd, UI_SET_EVBIT, EV_REL);      ioctl(fd, UI_SET_RELBIT, REL_X);      ioctl(fd, UI_SET_RELBIT, REL_Y);      memset(&usetup, 0, sizeof(usetup));      usetup.id.bustype = BUS_USB;      usetup.id.vendor = 0x1234; /* sample vendor */      usetup.id.product = 0x5678; /* sample product */      strcpy(usetup.name, "Example device");      ioctl(fd, UI_DEV_SETUP, &usetup);      ioctl(fd, UI_DEV_CREATE);      /*       * On UI_DEV_CREATE the kernel will create the device node for this       * device. We are inserting a pause here so that userspace has time       * to detect, initialize the new device, and can start listening to       * the event, otherwise it will not notice the event we are about       * to send. This pause is only needed in our example code!       */      sleep(1);      /* Move the mouse diagonally, 5 units per axis */      while (i--) {         emit(fd, EV_REL, REL_X, 5);         emit(fd, EV_REL, REL_Y, 5);         emit(fd, EV_SYN, SYN_REPORT, 0);         usleep(15000);      }      /*       * Give userspace some time to read the events before we destroy the       * device with UI_DEV_DESTROY.       */      sleep(1);      ioctl(fd, UI_DEV_DESTROY);      close(fd);      return 0;   }   

uinput old interface

在 uinput 版本5之前,没有专门的 ioctl 来设置虚构设施。较旧版本的 uinput接口须要填充 uinput_user_dev 构造,并将其写入uinput文件描述符以配置新的 uinport设施。新代码不应该应用旧接口,而是通过 ioctl 调用与uinput交互,或者应用 libevdev。

   #include <linux/uinput.h>   /* emit function is identical to of the first example */   int main(void)   {      struct uinput_user_dev uud;      int version, rc, fd;      fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);      rc = ioctl(fd, UI_GET_VERSION, &version);      if (rc == 0 && version >= 5) {         /* use UI_DEV_SETUP */         return 0;      }      /*       * The ioctls below will enable the device that is about to be       * created, to pass key events, in this case the space key.       */      ioctl(fd, UI_SET_EVBIT, EV_KEY);      ioctl(fd, UI_SET_KEYBIT, KEY_SPACE);      memset(&uud, 0, sizeof(uud));      snprintf(uud.name, UINPUT_MAX_NAME_SIZE, "uinput old interface");      write(fd, &uud, sizeof(uud));             ioctl(fd, UI_DEV_CREATE);      /*       * On UI_DEV_CREATE the kernel will create the device node for this       * device. We are inserting a pause here so that userspace has time       * to detect, initialize the new device, and can start listening to       * the event, otherwise it will not notice the event we are about       * to send. This pause is only needed in our example code!       */      sleep(1);      /* Key press, report the event, send key release, and report again */      emit(fd, EV_KEY, KEY_SPACE, 1);      emit(fd, EV_SYN, SYN_REPORT, 0);      emit(fd, EV_KEY, KEY_SPACE, 0);      emit(fd, EV_SYN, SYN_REPORT, 0);      /*       * Give userspace some time to read the events before we destroy the       * device with UI_DEV_DESTROY.       */      sleep(1);      ioctl(fd, UI_DEV_DESTROY);      close(fd);      return 0;   }