您的位置:首页 > 产品设计 > UI/UE

使用UInput模拟系统键盘鼠标动作

2017-11-18 21:36 309 查看
转自:http://blog.sina.com.cn/s/blog_602f87700100llew.html

在最近的项目中,Sam需要将设备数据解析后以系统键盘鼠标的消息发送出去。选用UInput(关于UInputDriver以及编译,( http://blog.sina.com.cn/s/blog_602f87700100liyk.html)。
 

当uinput driver已经insmod, 且node 已经建立后。即可使用它们传递系统输入设备消息。

 

1. 打开UInputDevice:

应用程序:

dev 为 UInput Node名:通常为/dev/uinput。

open(dev, O_WRONLY | O_NDELAY);

 

此时,在Kernel 层,对应的动作为:

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;

 

 

2. 设置UInputDevice:

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

动作:

2.1 将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.表示设备所支持的动作.

#defineEV_KEY   0x01 // 按键

#defineEV_REL   0x02 // 释放

 

3.继续设置 Device:

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);

同上。设置了Keybit等。

这里就是设置了Input Device关心或者说会产生的消息。

 

 

4. 写入设备:

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));

此时,在Kernel 层,对应的动作为:

此时Device status为UIST_NEW_DEVICE

并将udev->dev 这个input device 具体化。初始化该input_dev。

之后,改变状态:

udev->state =UIST_SETUP_COMPLETE;

 

 

5.创建InputDevice:

注意,此处是创建了Input Device。而不是UInput Device。

ioctl(fd, UI_DEV_CREATE);

 此时,在Kernel 层,对应的动作为:

input_register_device(udev->dev);//向子系统注册该设备,之后中断时input_event()向子系统报告事件

udev->state = UIST_CREATED;

 

6. 向InputDevice发送Event:

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));

 此时,在Kernel 层,对应的动作为:

static ssize_t uinput_write(struct file *file, const char __user*buffer, size_t count, loff_t *ppos)

因为此时state为UIST_CREATED

input_event(udev->dev, ev.type, ev.code,ev.value);

发送event.

 

 

总结:

使用UInput的步骤为:

1. 打开设备。

2. 使用ioctl() 配置设备。

3. 使用write() 将input device信息设置好。

4. 使用ioctl(UI_DEV_CREATE)创建Input Device。(即使用write设置的)

5. 再使用write() 写入event.

 

 

 

 

UInput添加的Input Device在/proc的反应:

#cat /proc/bus/input/device

I: Bus=0003 Vendor=0000 Product=0000 Version=0004

N: Name="uinput"

P: Phys=

S: Sysfs=/class/input/input6

H: Handlers=event1 mouse1

B: EV=f

B: KEY=400 0 670000 ffff ffffffff ffffffff ffffffff ffffffffffffffff ffffffff ffffffff

B: REL=3

B: ABS=1000003

解释如下:

Bus=0003 Vendor=0000 Product=0000Version=0004

这是在第一次write时设置的:

uinp.id.version = 4;

uinp.id.bustype = BUS_USB;

struct input_id {

 __u16 bustype;

 __u16 vendor;

 __u16 product;

 __u16 version;

};

 

EV=f

 

后记:

后来的工作中,Sam又看到Hi3716C中,如何使用Driver将红外遥控器模拟成一个Keyboard.
http://blog.sina.com.cn/s/blog_602f877001019wtx.html
其实原理非常类似. 都需要指出支持什么Type的Event.

注3:不同类型的InputEvent:

#define EV_SYN         0x00   表示设备支持所有的事件
#define EV_KEY         0x01   键盘或者按键,表示一个键码 
#define EV_REL         0x02   鼠标设备,表示一个相对的光标位置结果
#define EV_ABS         0x03   手写板产生的值,其是一个绝对整数值 
#define EV_MSC         0x04   其他类型 
#define EV_LED         0x11   LED灯设备
#define EV_SND         0x12   蜂鸣器,输入声音 
#define EV_REP         0x14   允许重复按键类型 
#define EV_PWR         0x16   电源管理事件 

#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
#define EV_CNT (EV_MAX+1)

也要指出每种Type的Event中又分别支持什么具体值.

然后才是创建Device.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: