Difference between revisions of "Uinput"

From Ilianko
 
(23 intermediate revisions by the same user not shown)
Line 1: Line 1:
<!--Getting started with uinput: the user level input subsystem -->
+
==Вход от потрeбителско ниво==
Вход от потрeбителско ниво
 
  
<!-- uinput is a linux kernel module that allows to handle the input subsystem from user land. It can be used to create and to handle input devices from an application. It creates a character device in /dev/input directory. The device is a virtual interface, it doesn't belong to a physical device.
+
Uinput е модул за linux ядрото, който позволява управление на системата за входни данни от приложения работещи на потребителско ниво. Модулът uinput създава виртуално входно устройство.  
  
In this document, we will see how to create a such input device and how it can be used. -->
+
===Създаване на входно устройство===
  
uinput е модул за linux ядрото, който позволява управление на системата за входни данни от приложения работещи на потребителско ниво. Модулът uinput създава виртуално входно устройство.  
+
След инсталиране на модула uinput (чрез modprobe или insmod) се създава устройство от буквен тип с име /dev/input/uinput (или /dev/uinput). Това устройство представлява интерфейса между приложението и системата за входни данни на ядрото.
  
 
+
За да се използва uinput, то устройството трябва трябва да се отвори само за запис и в неблокиращ режим.
1. Създаване на входно устройство.
 
 
 
След инсталиране на модула uinput (чрез modprobe или insmod) се създава устройство от буквен тип с име /dev/input/uinput (или /dev/uinput). Това устройство представлява интерфейса между риложението и системата за входни данни на ядрото.
 
 
 
За да се използва uinput, то устройство трябва трябва да се отвори само за запис и в неблокиращ режим.
 
  
 
  #include <linux/input.h>
 
  #include <linux/input.h>
 
  #include <linux/uinput.h>
 
  #include <linux/uinput.h>
 
  ...
 
  ...
 
+
 
  int fd;
 
  int fd;
 
   
 
   
Line 27: Line 21:
 
  }
 
  }
  
След като е отворено устройството трябва да се конфигурира.
 
Now the device is opened, we will configure our input device. First, we need to inform the input subsystem which types of input event we want to use. Types of events are defined in /usr/include/linux/input.h:
 
  
/usr/include/linux/input.h
+
===Дефиниране на входни събития===
...
+
След като е отворено устройството трябва да се конфигурира. Първо трябва да се инициализират типовете входни събития, които ще се ползват. Типовете събития са дефинирани в /usr/include/linux/input.h.
#define EV_KEY          0x01
 
#define EV_REL          0x02
 
#define EV_ABS          0x03
 
...
 
EV_KEY type represents key press and release events,
 
EV_REL type represents relative axis events (such as mouse movements),
 
EV_ABS type represents absolute axis events (such as touchscreen movements),
 
 
The ioctl request UI_SET_EVBIT applied on the uinput file descriptor is used to enable a type of event. The two following lines enable key press/release and synchronization events.
 
  
ret = ioctl(fd, UI_SET_EVBIT, EV_KEY);
+
Активиране на събития чрез [http://en.wikipedia.org/wiki/Ioctl ioctl]. Следните редове активират събития натискане/отпускане на бутон и синхронизация.
...
 
ret = ioctl(fd, UI_SET_EVBIT, EV_SYN);
 
When enabling EV_KEY events, we need to describe which keycodes are allowed to be sent via the input subsystem.
 
  
As linux/input.h defines the 'd' key as KEY_D, we can enable the keycode representing the 'd' key by using:
 
  
ret = ioctl(fd, UI_SET_KEYBIT, KEY_D);
+
*EV_KEY събитие за натиснат или отпуснат бутон от клавиатурата,
...
+
*EV_REL събитие за относително отместване (преместване на мишка),
Now some basic features have been enabled, we need to finish the configuration by using the struct uinput_user_dev from linux/uinput.h. This structure is defined as:
+
*EV_ABS събитие за абсолютно отместване  (позиция от сензорен екран).
 +
*EV_SYN синхронизиращо събитие (изпраща се винаги след движение по относителни координати (мишка)
 +
*EV_REP повтаряне на бутон ???
  
/usr/include/linux/uinput.h
+
ioctl(fd, UI_SET_EVBIT, EV_KEY);
#define UINPUT_MAX_NAME_SIZE    80
+
ioctl(fd, UI_SET_EVBIT, EV_SYN);
struct uinput_user_dev {
+
ioctl(fd, UI_SET_EVBIT, EV_ABS);  
    char name[UINPUT_MAX_NAME_SIZE];
+
ioctl(fd, UI_SET_EVBIT, EV_REL);
    struct input_id id;
+
ioctl(fd, UI_SET_EVBIT, EV_REP);
        int ff_effects_max;
 
        int absmax[ABS_MAX + 1];
 
        int absmin[ABS_MAX + 1];
 
        int absfuzz[ABS_MAX + 1];
 
        int absflat[ABS_MAX + 1];
 
};
 
The most important fields are:
 
  
name is the given name to the input device we will create,
+
===Дефиниране на състояния на събитие===
id is a linux internal structure that describes the device bustype, vendor id, product id and version,
 
absmin and absmax are integer array that defines mininal and maximal values for an absolute axis (i.e absmin[ABS_X] = 0, absmax[ABS_X] = 1024 for the X axis on a touchscreen device).
 
Now, we can fill this structure with appropriate values:
 
  
struct uinput_user_dev uidev;
+
====EV_KEY====
 +
При активиране на ЕV_KEY събитие, трябва да се опишат и възможните бутони, които ще бъдат изпращани. За 'd' се дефинира по следния начин:
 +
 +
ioctl(fd, UI_SET_KEYBIT, KEY_D);
  
memset(&uidev, 0, sizeof(uidev));
+
Дефиниране на поддръжка на всички възможни бутони
 +
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);
  
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-sample");
+
====EV_ABS====
uidev.id.bustype = BUS_USB;
+
Дефиниране на отместване по абсолютни координати. Може да работи или относително или абсолютно отместванепо.
uidev.id.vendor = 0x1234;
+
ioctl(fd, UI_SET_ABSBIT, ABS_X)
uidev.id.product = 0xfedc;
+
ioctl(fd, UI_SET_ABSBIT, ABS_Y)
uidev.id.version = 1;
+
  ioctl(fd, UI_SET_ABSBIT, 0)
Then, we write this structure in the uinput file descriptor.
 
  
ret = write(fd, &uidev, sizeof(uidev));
+
===Допълнително конфигуриране===
Last step is to request the creation of the device via the UI_DEV_CREATE ioctl request on the file descriptor:
+
Задават се:
 +
*Име на входното устойство
 +
*id - описва типа на шината, ...
 +
*absmin and absmax цели числа описващи минимална и максимална координати.
  
ret = ioctl(fd, UI_DEV_CREATE);
+
struct uinput_user_dev udev
Now, the file descriptor fd represents the end-point file descriptor of the new input device.
 
  
2. Injecting events in the input subsystem
+
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;
  
The following block code injects a key press event in the input subsystem. The input_event structure contains 3 important fields:
+
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)
  
type: is an event type (EV_KEY, EV_ABS, EV_REL, ...),
+
===Създаване на устройството===
code: could be either a key code when using EV_KEY, or an axis for EV_ABS and EV_REL,
+
value: may be 1 (press) or 0 (release) for EV_KEY, or any values for others (positive integer for EV_ABS, signed integer for EV_REL, etc…).
+
ioctl(fd, UI_DEV_CREATE);
To inject a press event on the 'd' key:
 
 
 
struct input_event ev;
 
 
 
memset(&ev, 0, sizeof(ev));
 
 
 
ev.type = EV_KEY;
 
ev.code = KEY_D;
 
ev.value = 1;
 
 
 
ret = write(fd, &ev, sizeof(ev));
 
3. Destroying an input device
 
 
 
ret = ioctl(fd, UI_DEV_DESTROY);
 
4. Handling absolute axis events
 
 
 
If we want to inject absolute events, we first need to activate EV_ABS event and the desired axes support with ioctl requests. The following ioctl requests enable X and Y absolute axes:
 
 
 
ret = ioctl(fd, UI_SET_EVBIT, EV_ABS);
 
...
 
  
ret = ioctl(fd, UI_SET_ABSBIT, ABS_X);
+
===Генериране на събитие===
...
 
ret = ioctl(fd, UI_SET_ABSBIT, ABS_Y);
 
Then we need to defined a range of values for each axis with absmin and absmax fields from the uinput_user_dev structure:
 
  
uidev.absmin[ABS_X] = 0;
 
uidev.absmax[ABS_X] = 1023;
 
Event injection follows the same method as for any other events.
 
  
struct input_event ev[2];
+
*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.
  
memset(ev, 0, sizeof(ev));
+
Инжектиране:
 +
  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)
  
ev[0].type = EV_ABS;
+
!! След събитие за отнисително движение се изпраща, събитие за синхронизация
ev[0].code = ABS_X;
+
!! След събитие за натискане на бутон, трябва да се изпрати събитие за отпускане
ev[0].value = 1023;
 
ev[1].type = EV_ABS;
 
ev[1].code = ABS_Y;
 
ev[1].value = 767;
 
  
ret = write(fd, ev, sizeof(ev));
+
=== Затваряне на устройството ===
 +
ioctl(fd, UI_DEV_DESTROY);
  
== Виртуална мишка ==
+
== Виртуално устройство ==
  
 
<code><pre>
 
<code><pre>
 
#include <stdio.h>
 
#include <stdio.h>
 +
#include <string.h>
 
#include <stdlib.h>
 
#include <stdlib.h>
#include <string.h>
 
 
#include <unistd.h>
 
#include <unistd.h>
 
#include <fcntl.h>
 
#include <fcntl.h>
#include <errno.h>
 
#include <linux/input.h>
 
 
#include <linux/uinput.h>
 
#include <linux/uinput.h>
 +
#include <stdint.h>
  
#define die(str, args...) do { \
+
int suinput_write(int uinput_fd, uint16_t type, uint16_t code, int32_t value)
        perror(str); \
 
        exit(EXIT_FAILURE); \
 
    } while(0)
 
 
 
int
 
main(void)
 
 
{
 
{
     int                    fd;
+
     //генериране на събитие
     struct uinput_user_dev uidev;
+
    struct input_event event;
     struct input_event     ev;
+
     memset(&event, 0, sizeof(event));
     int                    dx, dy;
+
    gettimeofday(&event.time, 0); /* This should not be able to fail ever.. */
     int                    i;
+
    event.type = type;
 +
     event.code = code;
 +
     event.value = value;
 +
     if (write(uinput_fd, &event, sizeof(event)) != sizeof(event))
 +
        return -1;
 +
     return 0;
 +
}
  
    fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
+
int suinput_write_syn(int uinput_fd,
     if(fd < 0)
+
                            uint16_t type, uint16_t code, int32_t value)
         die("error: open");
+
{ // синхронизиращо събитир
 +
     if (suinput_write(uinput_fd, type, code, value))
 +
         return -1;
 +
    return suinput_write(uinput_fd, EV_SYN, SYN_REPORT, 0);
 +
}
  
    if(ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0)
+
int suinput_move_pointer(int uinput_fd, int32_t x, int32_t y)
        die("error: ioctl");
+
{ //относително отместване
     if(ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) < 0)
+
     if (suinput_write(uinput_fd, EV_REL, REL_X, x))
         die("error: ioctl");
+
         return -1;
 +
    return suinput_write_syn(uinput_fd, EV_REL, REL_Y, y);
 +
}
  
    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));
+
int suinput_open(const char* device_name, int abs)
  snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-sample");
+
{
 +
//създаване на устройство
 +
  int fd, i;
 +
  struct uinput_user_dev uidev;
 +
 +
  fd = open( device_name, O_WRONLY | O_NONBLOCK);
 +
  if (fd == -1)
 +
        exit(1);
 +
 
 +
  memset(&uidev, 0, sizeof(uidev));
 +
    snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-sample");
 
     uidev.id.bustype = BUS_USB;
 
     uidev.id.bustype = BUS_USB;
 
     uidev.id.vendor  = 0x1;
 
     uidev.id.vendor  = 0x1;
 
     uidev.id.product = 0x1;
 
     uidev.id.product = 0x1;
 
     uidev.id.version = 1;
 
     uidev.id.version = 1;
 +
  /* Set device to handle following types of events: */
 +
 +
  /* Key and button events */
 +
  if (ioctl(fd, UI_SET_EVBIT, EV_KEY) == -1)
 +
      exit(2);
 +
 +
  /* Key and button repetition events */
 +
  if (ioctl(fd, UI_SET_EVBIT, EV_REP) == -1)
 +
      exit(3);
 +
 
 +
  /* Synchronization events, this is probably set implicitely too. */
 +
    if (ioctl(fd, UI_SET_EVBIT, EV_SYN) == -1)
 +
        exit(3);
 +
 +
if (abs)
 +
{
 +
if (ioctl(fd, UI_SET_EVBIT, EV_REL) == -1)
 +
        exit(3);
 +
 +
/* Configure device to handle relative x and y axis. */
 +
if (ioctl(fd, UI_SET_RELBIT, REL_X) == -1)
 +
exit(3);
 +
   
 +
if (ioctl(fd, UI_SET_RELBIT, REL_Y) == -1)
 +
exit(3);
 +
 +
}
 +
else
 +
{/* Configure device to handle absolute x and y axis. */
 +
if (ioctl(fd, UI_SET_EVBIT, EV_ABS) == -1)
 +
exit(4);
 +
 +
if (ioctl(fd, UI_SET_ABSBIT, ABS_X) == -1)
 +
exit(4);
 +
if (ioctl(fd, UI_SET_ABSBIT, ABS_Y) == -1)
 +
        exit(4);
 +
if (ioctl(fd, UI_SET_ABSBIT, 0) == -1)
 +
exit(4);
 +
 +
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;
 +
}
 +
 +
    /* Configure device to handle all keys, see linux/input.h. */
 +
    for (i = 0; i < KEY_MAX; i++) {
 +
        if (ioctl(fd, UI_SET_KEYBIT, i) == -1)
 +
            exit(11);
 +
    }
  
 
     if(write(fd, &uidev, sizeof(uidev)) < 0)
 
     if(write(fd, &uidev, sizeof(uidev)) < 0)
         die("error: write");
+
         exit(10);
 +
   
 +
    if(ioctl(fd, UI_DEV_CREATE) < 0)
 +
        exit(12);
 +
   
 +
    /*
 +
  The reason for generating a small delay is that creating succesfully
 +
  an uinput device does not guarantee that the device is ready to process
 +
  input events. It's probably due the asynchronous nature of the udev.
 +
  However, my experiments show that the device is not ready to process input
 +
  events even after a device creation event is received from udev.
 +
  */
 +
    sleep(2);    return fd;
 +
}
  
    if(ioctl(fd, UI_DEV_CREATE) < 0)
+
int suinput_press(int uinput_fd, uint16_t code)
        die("error: ioctl");
+
{
 +
    return suinput_write(uinput_fd, EV_KEY, code, 1);
 +
}
  
     sleep(20);
+
int suinput_release(int uinput_fd, uint16_t code)
 +
{
 +
     return suinput_write_syn(uinput_fd, EV_KEY, code, 0);
 +
}
  
   
 
 
 
            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));
+
int suinput_set_pointer(int uinput_fd, int32_t x, int32_t y)
            ev.type = EV_REL;
+
{
            ev.code = REL_Y;
+
    if (suinput_write(uinput_fd, EV_ABS, ABS_X, x))
            ev.value = dy;
+
        return -1;
            if(write(fd, &ev, sizeof(struct input_event)) < 0)
+
    return suinput_write_syn(uinput_fd, EV_ABS, ABS_Y, y);
                die("error: write");
+
}
  
            memset(&ev, 0, sizeof(struct input_event));
+
int suinput_click(int uinput_fd, uint16_t code)
            ev.type = EV_SYN;
+
{
            ev.code = 0;
+
    if (suinput_press(uinput_fd, code))
            ev.value = 0;
+
        return -1;
            if(write(fd, &ev, sizeof(struct input_event)) < 0)
+
    return suinput_release(uinput_fd, code);
                die("error: write");
+
}
  
            usleep(15000);
+
int suinput_close(int uinput_fd)
     
+
{
 +
    /*
 +
    Sleep before destroying the device because there still can be some
 +
    unprocessed events. This is not the right way, but I am still
 +
    looking for better ways. The question is: how to know whether there
 +
    are any unprocessed uinput events?
 +
  */
 +
    //sleep(2);
  
     if(ioctl(fd, UI_DEV_DESTROY) < 0)
+
     if (ioctl(uinput_fd, UI_DEV_DESTROY) == -1) {
         die("error: ioctl");
+
         close(uinput_fd);
 +
        return -1;
 +
    }
  
     close(fd);
+
     if (close(uinput_fd) == -1)
 +
        return -1;
  
 
     return 0;
 
     return 0;
 
}
 
}
  
 +
 +
int main(void)
 +
{
 +
     
 +
  int  fd;
 +
  fd = suinput_open("/dev/uinput", 0); // 0 - absolute , 1 relative
 +
     
 +
     
 +
  //suinput_move_pointer(fd, 130,130);
 +
  suinput_set_pointer(fd, 60, 60);
 +
 
 +
  suinput_press(fd, 2);
 +
  suinput_release(fd, 2);
 +
  usleep(10000);
 +
  suinput_click(fd,  BTN_LEFT);
 +
 
 +
  usleep(10000);
 +
 
 +
  // suinput_click(fd,  BTN_RIGHT);
 +
  suinput_set_pointer(fd, -60, -60);
 +
  usleep(10000);
 +
 
 +
  suinput_click(fd,  BTN_LEFT);
 +
     
 +
  suinput_press(fd, 3);
 +
  suinput_press(fd, 5);
 +
     
 +
  suinput_close(fd);
 +
 
 +
  return 0;
 +
}
 
</pre></code>
 
</pre></code>
  
 +
 +
== Да се създаде виртуална мишка, която да се управлява чрез стрелките ==
 +
 +
Използвайте директен достъп до клавитурата:
 
<code><pre>
 
<code><pre>
 
#include <linux/input.h>
 
#include <linux/input.h>
Line 266: Line 360:
 
</pre></code>
 
</pre></code>
  
== chmod ==
 
 
~$ sudo chmod 777 /dev/input/event3
 
~$ sudo chmod 777 /dev/uinput
 
  
 +
==Връзки==
 +
*[http://thiemonge.org/getting-started-with-uinput Getting started with uinput: the user level input subsystem]
 +
*http://remoteroid.googlecode.com/svn-history/r277/trunk/android/jni/suinput.cpp
  
http://web.me.com/haroldsoh/tutorials/technical-skills/using-optical-mice-for-othe-2/
 
 
[[Category:Компютърна периферия]]
 
[[Category:Компютърна периферия]]

Latest revision as of 10:11, 31 March 2013

Вход от потр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 синхронизиращо събитие (изпраща се винаги след движение по относителни координати (мишка)
  • EV_REP повтаряне на бутон ???
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);
ioctl(fd, UI_SET_EVBIT, EV_REP);

Дефиниране на състояния на събитие

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 <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/uinput.h>
#include <stdint.h>

int suinput_write(int uinput_fd, uint16_t type, uint16_t code, int32_t value)
{
    //генериране на събитие
    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;
    if (write(uinput_fd, &event, sizeof(event)) != sizeof(event))
        return -1;
    return 0;
}

int suinput_write_syn(int uinput_fd, 
                             uint16_t type, uint16_t code, int32_t value)
{	// синхронизиращо събитир
    if (suinput_write(uinput_fd, type, code, value))
        return -1;
    return suinput_write(uinput_fd, EV_SYN, SYN_REPORT, 0);
}

int suinput_move_pointer(int uinput_fd, int32_t x, int32_t y)
{	//относително отместване
    if (suinput_write(uinput_fd, EV_REL, REL_X, x))
        return -1;
    return suinput_write_syn(uinput_fd, EV_REL, REL_Y, y);
}


int suinput_open(const char* device_name, int abs)
{	
	//създаване на устройство
   int fd, i;
   struct uinput_user_dev uidev;
 
   fd = open( device_name, O_WRONLY | O_NONBLOCK);
   if (fd == -1)
        exit(1);
   
   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;
   /* Set device to handle following types of events: */

   /* Key and button events */
   if (ioctl(fd, UI_SET_EVBIT, EV_KEY) == -1)
       exit(2);

   /* Key and button repetition events */
   if (ioctl(fd, UI_SET_EVBIT, EV_REP) == -1)
       exit(3);
  
   /* Synchronization events, this is probably set implicitely too. */
    if (ioctl(fd, UI_SET_EVBIT, EV_SYN) == -1)
        exit(3);

	if (abs)
	{
		if (ioctl(fd, UI_SET_EVBIT, EV_REL) == -1)
        exit(3);

		/* Configure device to handle relative x and y axis. */
		if (ioctl(fd, UI_SET_RELBIT, REL_X) == -1)
		exit(3);
     
		if (ioctl(fd, UI_SET_RELBIT, REL_Y) == -1)
		exit(3);
	
	}
	else
	{/* Configure device to handle absolute x and y axis. */
		if (ioctl(fd, UI_SET_EVBIT, EV_ABS) == -1)
		exit(4);
		
		if (ioctl(fd, UI_SET_ABSBIT, ABS_X) == -1)
		exit(4);
		if (ioctl(fd, UI_SET_ABSBIT, ABS_Y) == -1)
        exit(4);
		if (ioctl(fd, UI_SET_ABSBIT, 0) == -1)
		exit(4);
	
		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;	
	}

    /* Configure device to handle all keys, see linux/input.h. */
    for (i = 0; i < KEY_MAX; i++) {
        if (ioctl(fd, UI_SET_KEYBIT, i) == -1)
            exit(11);
    }

    if(write(fd, &uidev, sizeof(uidev)) < 0)
        exit(10);
    
    if(ioctl(fd, UI_DEV_CREATE) < 0)
        exit(12);
    
    /*
  The reason for generating a small delay is that creating succesfully
  an uinput device does not guarantee that the device is ready to process
  input events. It's probably due the asynchronous nature of the udev.
  However, my experiments show that the device is not ready to process input
  events even after a device creation event is received from udev.
  */
    sleep(2);    return fd;
}

int suinput_press(int uinput_fd, uint16_t code)
{
    return suinput_write(uinput_fd, EV_KEY, code, 1);
}

int suinput_release(int uinput_fd, uint16_t code)
{
    return suinput_write_syn(uinput_fd, EV_KEY, code, 0);
}


int suinput_set_pointer(int uinput_fd, int32_t x, int32_t y)
{
    if (suinput_write(uinput_fd, EV_ABS, ABS_X, x))
        return -1;
    return suinput_write_syn(uinput_fd, EV_ABS, ABS_Y, y);
}

int suinput_click(int uinput_fd, uint16_t code)
{
    if (suinput_press(uinput_fd, code))
        return -1;
    return suinput_release(uinput_fd, code);
}

int suinput_close(int uinput_fd)
{
    /*
    Sleep before destroying the device because there still can be some
    unprocessed events. This is not the right way, but I am still
    looking for better ways. The question is: how to know whether there
    are any unprocessed uinput events?
   */
    //sleep(2);

    if (ioctl(uinput_fd, UI_DEV_DESTROY) == -1) {
        close(uinput_fd);
        return -1;
    }

    if (close(uinput_fd) == -1)
        return -1;

    return 0;
}


int main(void)
{
      
   int  fd;
   fd = suinput_open("/dev/uinput", 0); // 0 - absolute , 1 relative
      
      
   //suinput_move_pointer(fd, 130,130);
   suinput_set_pointer(fd, 60, 60);
   
   suinput_press(fd, 2);
   suinput_release(fd, 2);
   usleep(10000);
   suinput_click(fd,  BTN_LEFT);
   
   usleep(10000);
   
  // suinput_click(fd,  BTN_RIGHT);
   suinput_set_pointer(fd, -60, -60);
   usleep(10000);
   
   suinput_click(fd,  BTN_LEFT);
       
   suinput_press(fd, 3);
   suinput_press(fd, 5);
      
   suinput_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);

    }
}


Връзки