mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
245 lines
6.6 KiB
245 lines
6.6 KiB
============= |
|
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_DESTROY. |
|
*/ |
|
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_DESTROY. |
|
*/ |
|
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_DESTROY. |
|
*/ |
|
sleep(1); |
|
|
|
ioctl(fd, UI_DEV_DESTROY); |
|
|
|
close(fd); |
|
return 0; |
|
} |
|
|
|
|