uinput可在以下情况大显身手:
1) 不需要自己写驱动
2) 用户态向/dev/input/eventX写入事件,即用户向Kernel注入数据
APP:
char *dev = "/dev/uinput“; open(dev, O_WRONLY | O_NDELAY);
static int uinput_open(struct inode *inode, struct file *file)
参数inode对应的是 主设备为10,子设备为223的node(即位用户态的dev)
参数file对应打开的文件。
动作:
创建了newdev-- uinput_device结构。
newdev->state = UIST_NEW_DEVICE;
file->private_data = newdev;
APP:
ioctl(fd, UI_SET_EVBIT, EV_KEY);
Kernel:
static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
参数file对应打开的文件。
参数cmd 对应用户态ioctl参数2。UI_SET_EVBIT
参数arg对应用户态ioctl参数3。EV_KEY
动作:
将driver参数传递过来。
udev = file->private_data;
udev->dev 是个input_dev 类型数据。 此时,它未初始化。
如果udev->dev为空,则使用 uinput_allocate_device(udev);申请input_dev结构
具体到CMD=UI_SET_EVBIT
uinput_set_bit(arg, evbit, EV_MAX);
首先判断newdev->state为UIST_CREATED,则返回错误码。
这就说明:设置bit,需要在create input device 之前。
具体动作为:udev->dev->evbit 设为EV_KEY.
注意:此处input device的evbit:
一个是evbit表示设备所支持的动作.:
#define EV_KEY 0x01 // 按键
#define EV_REL 0x02 // 释放
其它设置如下:
ret = ioctl(fd, UI_SET_RELBIT, REL_X); //鼠标
ret = ioctl(fd, UI_SET_RELBIT, REL_Y);
ret = ioctl(fd, UI_SET_EVBIT, EV_ABS);
ret = ioctl(fd, UI_SET_ABSBIT, ABS_X);
ret = ioctl(fd, UI_SET_ABSBIT, ABS_Y);
ret = ioctl(fd, UI_SET_ABSBIT, ABS_PRESSURE);
以上设置了Input Device关心或者说会产生的消息。
APP:
struct uinput_user_dev uinput; uinput.id.version = 4; uinput.id.bustype = BUS_USB; uinput.absmin[ABS_X] = 0; uinput.absmax[ABS_X] = 65535; //sam 把屏幕设为0-65535 uinput.absmin[ABS_Y] = 0; uinput.absmax[ABS_Y] = 65535; uinput.absmin[ABS_PRESSURE] = 0; uinput.absmax[ABS_PRESSURE] = 0xfff; ret = write(fd, &uinput, sizeof(uinput));
Device status为UIST_NEW_DEVICE
并将udev->dev 这个input device 具体化。初始化该input_dev,之后,改变状态:
udev->state = UIST_SETUP_COMPLETE;
APP:
注意,此处是创建了Input Device。而不是UInput Device。
ioctl(fd, UI_DEV_CREATE);
Kernel:
input_register_device(udev->dev); //向子系统注册该设备,之后中断时input_event()向子系统报告事件
udev->state = UIST_CREATED;
APP:
struct input_event event = {0}; gettimeofday(&event.time, NULL); event.type = EV_KEY; event.code = key; event.value = press ? 1:0; write(fd, &event, sizeof(event));
使用UInput的步骤为:
1. 打开设备。
2. 使用ioctl() 配置设备。
3. 使用write() 将input device信息设置好。
4. 使用ioctl(UI_DEV_CREATE)创建Input Device。(即使用write设置的)
5. 再使用write() 写入event.
/* Globals */ static int uinp_fd = -1; struct uinput_user_dev uinp; // uInput device structure struct input_event event; // Input device structure /* Setup the uinput device */ int setup_uinput_device() { // Temporary variable int i=0; // Open the input device uinp_fd = open("/dev/uinput", O_WRONLY | O_NDELAY); if (uinp_fd == NULL) { Dashboard January 2007 Issue printf("Unable to open /dev/uinput/n"); return -1; } memset(&uinp,0,sizeof(uinp)); // Intialize the uInput device to NULL strncpy(uinp.name, "PolyVision Touch Screen", UINPUT_MAX_NAME_SIZE); uinp.id.version = 4; uinp.id.bustype = BUS_USB; // Setup the uinput device ioctl(uinp_fd, UI_SET_EVBIT, EV_KEY); ioctl(uinp_fd, UI_SET_EVBIT, EV_REL); ioctl(uinp_fd, UI_SET_RELBIT, REL_X); ioctl(uinp_fd, UI_SET_RELBIT, REL_Y); for (i=0; i < 256; i++) { ioctl(uinp_fd, UI_SET_KEYBIT, i); } ioctl(uinp_fd, UI_SET_KEYBIT, BTN_MOUSE); ioctl(uinp_fd, UI_SET_KEYBIT, BTN_TOUCH); ioctl(uinp_fd, UI_SET_KEYBIT, BTN_MOUSE); ioctl(uinp_fd, UI_SET_KEYBIT, BTN_LEFT); ioctl(uinp_fd, UI_SET_KEYBIT, BTN_MIDDLE); ioctl(uinp_fd, UI_SET_KEYBIT, BTN_RIGHT); ioctl(uinp_fd, UI_SET_KEYBIT, BTN_FORWARD); ioctl(uinp_fd, UI_SET_KEYBIT, BTN_BACK); /* Create input device into input sub-system */ write(uinp_fd, &uinp, sizeof(uinp)); if (ioctl(uinp_fd, UI_DEV_CREATE)) { printf("Unable to create UINPUT device."); return -1; } return 1; } void send_click_events( ) { // Move pointer to (100,100) location memset(&event, 0, sizeof(event)); gettimeofday(&event.time, NULL); event.type = EV_REL; event.code = REL_X; event.value = 100; write(uinp_fd, &event, sizeof(event)); event.type = EV_REL; event.code = REL_Y; event.value = 100; write(uinp_fd, &event, sizeof(event)); event.type = EV_SYN; event.code = SYN_REPORT; event.value = 0; write(uinp_fd, &event, sizeof(event)); // Report BUTTON CLICK - PRESS event memset(&event, 0, sizeof(event)); gettimeofday(&event.time, NULL); event.type = EV_KEY; event.code = BTN_LEFT; event.value = 1; write(uinp_fd, &event, sizeof(event)); event.type = EV_SYN; event.code = SYN_REPORT; event.value = 0; write(uinp_fd, &event, sizeof(event)); // Report BUTTON CLICK - RELEASE event memset(&event, 0, sizeof(event)); gettimeofday(&event.time, NULL); event.type = EV_KEY; event.code = BTN_LEFT; event.value = 0; write(uinp_fd, &event, sizeof(event)); event.type = EV_SYN; event.code = SYN_REPORT; event.value = 0; write(uinp_fd, &event, sizeof(event)); } void send_a_button() { // Report BUTTON CLICK - PRESS event memset(&event, 0, sizeof(event)); gettimeofday(&event.time, NULL); event.type = EV_KEY; event.code = KEY_A; event.value = 1; write(uinp_fd, &event, sizeof(event)); event.type = EV_SYN; event.code = SYN_REPORT; event.value = 0; write(uinp_fd, &event, sizeof(event)); // Report BUTTON CLICK - RELEASE event memset(&event, 0, sizeof(event)); gettimeofday(&event.time, NULL); event.type = EV_KEY; event.code = KEY_A; event.value = 0; write(uinp_fd, &event, sizeof(event)); event.type = EV_SYN; event.code = SYN_REPORT; event.value = 0; write(uinp_fd, &event, sizeof(event)); } /* This function will open the uInput device. Please make sure that you have inserted the uinput.ko into kernel. */ int main() { // Return an error if device not found. if (setup_uinput_device() < 0) { printf("Unable to find uinput device/n"); return -1; } send_a_button(); // Send a "A" key send_click_events(); // Send mouse event /* Destroy the input device */ ioctl(uinp_fd, UI_DEV_DESTROY); /* Close the UINPUT device */ close(uinp_fd); }