6db4831e98
Android 14
246 lines
6.6 KiB
ReStructuredText
246 lines
6.6 KiB
ReStructuredText
=============
|
|
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;
|
|
}
|
|
|