forked from Minki/linux
Input: add uinput documentation
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>
This commit is contained in:
parent
1613976bbd
commit
aea415b1d1
@ -18,4 +18,5 @@ Linux Input Subsystem userspace API
|
||||
gamepad
|
||||
ff
|
||||
joydev/index
|
||||
uinput
|
||||
userio
|
||||
|
245
Documentation/input/uinput.rst
Normal file
245
Documentation/input/uinput.rst
Normal file
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user