Input: add uinput documentation
authorMarcos Paulo de Souza <marcos.souza.org@gmail.com>
Mon, 24 Apr 2017 23:19:49 +0000 (16:19 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Mon, 24 Apr 2017 23:50:37 +0000 (16:50 -0700)
Add description of uinput module with a few examples.

Signed-off-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Documentation/input/input_uapi.rst
Documentation/input/uinput.rst [new file with mode: 0644]

index 12ef8974a773b80c44fc2c02e3bee48f8e189793..4a0391609327a1d4931382d438e532ce75cf3305 100644 (file)
@@ -18,4 +18,5 @@ Linux Input Subsystem userspace API
    gamepad
    ff
    joydev/index
+   uinput
    userio
diff --git a/Documentation/input/uinput.rst b/Documentation/input/uinput.rst
new file mode 100644 (file)
index 0000000..b8e90b6
--- /dev/null
@@ -0,0 +1,245 @@
+=============
+uinput module
+=============
+
+Introduction
+============
+
+uinput is a kernel module that makes it possible to emulate input devices
+from userspace. By writing to /dev/uinput (or /dev/input/uinput) device, a
+process can create a virtual input device with specific capabilities. Once
+this virtual device is created, the process can send events through it,
+that will be delivered to userspace and in-kernel consumers.
+
+Interface
+=========
+
+::
+
+  linux/uinput.h
+
+The uinput header defines ioctls to create, set up, and destroy virtual
+devices.
+
+libevdev
+========
+
+libevdev is a wrapper library for evdev devices that provides interfaces to
+create uinput devices and send events. libevdev is less error-prone than
+accessing uinput directly, and should be considered for new software.
+
+For examples and more information about libevdev:
+https://www.freedesktop.org/software/libevdev/doc/latest/
+
+Examples
+========
+
+Keyboard events
+---------------
+
+This first example shows how to create a new virtual device, and how to
+send a key event. All default imports and error handlers were removed for
+the sake of simplicity.
+
+.. code-block:: c
+
+   #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_DESTOY.
+       */
+      sleep(1);
+
+      ioctl(fd, UI_DEV_DESTROY);
+      close(fd);
+
+      return 0;
+   }
+
+Mouse movements
+---------------
+
+This example shows how to create a virtual device that behaves like a physical
+mouse.
+
+.. code-block:: c
+
+   #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_DESTOY.
+       */
+      sleep(1);
+
+      ioctl(fd, UI_DEV_DESTROY);
+      close(fd);
+
+      return 0;
+   }
+
+
+uinput old interface
+--------------------
+
+Before uinput version 5, there wasn't a dedicated ioctl to set up a virtual
+device. Programs supportinf older versions of uinput interface need to fill
+a uinput_user_dev structure and write it to the uinput file descriptor to
+configure the new uinput device. New code should not use the old interface
+but interact with uinput via ioctl calls, or use libevdev.
+
+.. code-block:: c
+
+   #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_DESTOY.
+       */
+      sleep(1);
+
+      ioctl(fd, UI_DEV_DESTROY);
+
+      close(fd);
+      return 0;
+   }
+