Uinput
Вход от потрeбителско ниво
Uinput е модул за linux ядрото, който позволява управление на системата за входни данни от приложения работещи на потребителско ниво. Модулът uinput създава виртуално входно устройство.
Създаване на входно устройство
След инсталиране на модула uinput (чрез modprobe или insmod) се създава устройство от буквен тип с име /dev/input/uinput (или /dev/uinput). Това устройство представлява интерфейса между приложението и системата за входни данни на ядрото.
За да се използва uinput, то устройството трябва трябва да се отвори само за запис и в неблокиращ режим.
#include <linux/input.h> #include <linux/uinput.h> ... int fd; fd = open("/dev/input/uinput", O_WRONLY | O_NONBLOCK); if(fd < 0) { ... exit(EXIT_FAILURE); }
Дефиниране на входни събития
След като е отворено устройството трябва да се конфигурира. Първо трябва да се инициализират типовете входни събития, които ще се ползват. Типовете събития са дефинирани в /usr/include/linux/input.h.
Активиране на събития чрез ioctl. Следните редове активират събития натискане/отпускане на бутон и синхронизация.
- EV_KEY събитие за натиснат или отпуснат бутон от клавиатурата,
- EV_REL събитие за относително отместване (преместване на мишка),
- EV_ABS събитие за абсолютно отместване (позиция от сензорен екран).
- EV_SYN синхронизиращо събитие (изпраща се винаги след движение по относителни координати (мишка)
ioctl(fd, UI_SET_EVBIT, EV_KEY); ioctl(fd, UI_SET_EVBIT, EV_SYN); ioctl(fd, UI_SET_EVBIT, EV_ABS) ioctl(fd, UI_SET_EVBIT, EV_REL);
Дефиниране на състояния на събитие
EV_KEY
При активиране на ЕV_KEY събитие, трябва да се опишат и възможните бутони, които ще бъдат изпращани. За 'd' се дефинира по следния начин:
ioctl(fd, UI_SET_KEYBIT, KEY_D);
Дефиниране на поддръжка на всички възможни бутони
for (i = 0; i < KEY_MAX; i++) { if (ioctl(fd, UI_SET_KEYBIT, i) == -1) exit(11); }
EV_REL
Дефиниране на отместване по x i y.
ioctl(fd, UI_SET_RELBIT, REL_X); ioctl(fd, UI_SET_RELBIT, REL_Y);
EV_ABS
Дефиниране на отместване по абсолютни координати. Може да работи или относително или абсолютно отместванепо.
ioctl(fd, UI_SET_ABSBIT, ABS_X) ioctl(fd, UI_SET_ABSBIT, ABS_Y) ioctl(fd, UI_SET_ABSBIT, 0)
Допълнително конфигуриране
Задават се:
- Име на входното устойство
- id - описва типа на шината, ...
- absmin and absmax цели числа описващи минимална и максимална координати.
struct uinput_user_dev udev
memset(&uidev, 0, sizeof(uidev)); snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-sample"); uidev.id.bustype = BUS_USB; uidev.id.vendor = 0x1; uidev.id.product = 0x1; uidev.id.version = 1; /* необходими само ако се работи с абсолютни координати uidev.absmin[ABS_X] = -600; //Минимална координата uidev.absmax[ABS_X] = 600; uidev.absfuzz[ABS_X] = 0; uidev.absflat[ABS_X] = 0;
uidev.absmin[ABS_Y] = -400; uidev.absmax[ABS_Y] = 400; uidev.absfuzz[ABS_Y] = 0; uidev.absflat[ABS_Y] = 0; */ write(fd, &uidev, sizeof(uidev)
Създаване на устройството
ioctl(fd, UI_DEV_CREATE);
Генериране на събитие
- type: EV_KEY, EV_ABS, EV_REL, EV_SYN;
- code: EV_KEY, EV_ABS, EV_REL, SYN_REPORT;
- value: 1 (натискане), 0 (отпускане), (2) задаържане за EV_KEY, или цели числа за EV_ABS и EV_REL.
Инжектиране:
struct input_event event; memset(&event, 0, sizeof(event)); gettimeofday(&event.time, 0); /* This should not be able to fail ever.. */ event.type = type; event.code = code; event.value = value; write(uinput_fd, &event, sizeof(event)
!! След събитие за отнисително движение се изпраща, събитие за синхронизация !! След събитие за натискане на бутон, трябва да се изпрати събитие за отпускане
Затваряне на устройството
ioctl(fd, UI_DEV_DESTROY);
Виртуална мишка
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/uinput.h>
#define die(str, args...) do { \
perror(str); \
exit(EXIT_FAILURE); \
} while(0)
int
main(void)
{
int fd;
struct uinput_user_dev uidev;
struct input_event ev;
int dx, dy;
int i;
fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if(fd < 0)
die("error: open");
if(ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_EVBIT, EV_REL) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_RELBIT, REL_X) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_RELBIT, REL_Y) < 0)
die("error: ioctl");
memset(&uidev, 0, sizeof(uidev));
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-sample");
uidev.id.bustype = BUS_USB;
uidev.id.vendor = 0x1;
uidev.id.product = 0x1;
uidev.id.version = 1;
if(write(fd, &uidev, sizeof(uidev)) < 0)
die("error: write");
if(ioctl(fd, UI_DEV_CREATE) < 0)
die("error: ioctl");
sleep(2);
dx = -100;
dy = -10;
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_REL;
ev.code = REL_X;
ev.value = dx;
if(write(fd, &ev, sizeof(struct input_event)) < 0)
die("error: write");
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_REL;
ev.code = REL_Y;
ev.value = dy;
if(write(fd, &ev, sizeof(struct input_event)) < 0)
die("error: write");
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_SYN;
ev.code = 0;
ev.value = 0;
if(write(fd, &ev, sizeof(struct input_event)) < 0)
die("error: write");
usleep(15000);
if(ioctl(fd, UI_DEV_DESTROY) < 0)
die("error: ioctl");
close(fd);
return 0;
}
#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int fd;
struct input_event ev;
fd = open("/dev/input/event3", O_RDONLY);
if(fd < 0) {
printf("error openning");
return 1;
}
while (1)
{
read(fd, &ev, sizeof(struct input_event));
if(ev.type == 1)
printf("key %i state %i\n", ev.code, ev.value);
}
}