Linux input子系统
Linux input子系统(一)input设备应用编程
Linux input子系统(二)input子系统驱动
在Linux下查看ls /dev/input
,可以看到现在有的输入设备
比如我的结果是
# ls /dev/input/
event0 event1 event2 mice mouse0 mouse1
这些都是通过input子系统实现的输入设备驱动,遵循input子系统规范
其中event2为我的触摸屏设备节点,通过下面命令读取(hexdump读取的数是以16进制打印)
# hexdump /dev/input/event2
当我点击触摸屏然后松开,发现控制台打印了许多消息
0247 0000 00d3 000e 0003 0000 02c4 0000
0247 0000 00db 000e 0003 0001 0181 0000
0247 0000 00de 000e 0001 014a 0001 0000
0247 0000 00e0 000e 0003 0018 0001 0000
0247 0000 00e2 000e 0000 0000 0000 0000
0248 0000 c838 0002 0001 014a 0000 0000
0248 0000 c876 0002 0003 0018 0000 0000
0248 0000 c89f 0002 0000 0000 0000 0000
其中每一行都表示一个input事件,如果单纯这样子看是分析不出所以然的,我们需要先介绍input事件,然后再来分析
input事件结构体的定义如下,在Linux内核的include\linux\input.h
文件中
struct timeval {
__kernel_time_t tv_sec; /* seconds,32bit */
__kernel_suseconds_t tv_usec; /* microseconds,32bit */
};
struct input_event {
struct timeval time; //时间
__u16 type; //事件类型
__u16 code; //事件键值
__s32 value; //值
};
可以看到,每一个input事件都有一个时间,包含32位的秒,32位的微妙
此外还有16位的type(事件类型),16位的code(事件键值),32位的value(值)
好,现在又有疑惑,type、code、value具体是什么?
type
type是指事件类型,在include\linux\input.h
文件中定义了一系列的事件类型
#define EV_SYN 0x00 //同步事件,用于分隔事件
#define EV_KEY 0x01 //按键事件,例如按键、鼠标按键、触摸屏按键
#define EV_REL 0x02 //相对位置事件,常见于鼠标坐标
#define EV_ABS 0x03 //绝对位置事件,常见于触摸屏坐标
...
一个设备可以有多种类型的事件,例如鼠标点击按键时会上报按键事件,移动时会上报相对位置事件
code
code指事件的键值,在事件类型中的子事件,每一个事件类型都有其对应的一系列键值
例如按键事件,那么你这个按键表示按键1还是按键2还是鼠标左键
例如绝对位置事件,那么你上报的这个事件是指X轴还是Y轴
在include\linux\input.h
文件中定义了一系列的事件键值
按键事件的键值
#define KEY_1 2
#define KEY_2 3
#define KEY_3 4
...
#define KEY_A 30
#define KEY_S 31
#define KEY_D 32
...
相对位置事件的键值
#define REL_X 0x00 //x轴
#define REL_Y 0x01 //y轴
#define REL_Z 0x02 //z轴
#define REL_RX 0x03
#define REL_RY 0x04
#define REL_RZ 0x05
#define REL_HWHEEL 0x06
#define REL_DIAL 0x07
#define REL_WHEEL 0x08
#define REL_MISC 0x09
绝对位置事件
#define ABS_X 0x00
#define ABS_Y 0x01
#define ABS_Z 0x02
...
#define ABS_PRESSURE 0x18
...
还有其他的事件类型这里就不详述了
value
value是code(键值)对应的值,其解释随code类型的变化而变化
例如在按键事件中,如果code表示按键1,那么value等于1表示按键1按下,等于0等于按键1未按下
在绝对位置事件中,如果code表示X轴坐标,那么value就表示触摸点在X轴坐标的位置
到这里应该就对input事件的理解很清除了,有了这些理解,下面我们来解析一下上面使用hexdump读取到的数据
由于前64位表示的是事件,所以这里就不解析了
s |us |type|code|value
1: 0247 0000 00d3 000e 0003 0000 02c4 0000 //EV_ABS、ABS_X、708
2: 0247 0000 00db 000e 0003 0001 0181 0000 //EV_ABS、ABS_Y、385
3: 0247 0000 00de 000e 0001 014a 0001 0000 //EV_KEY、BTN_TOUCH、1
4: 0247 0000 00e0 000e 0003 0018 0001 0000 //EV_ABS、ABS_PRESSURE、1
5: 0247 0000 00e2 000e 0000 0000 0000 0000 //EV_SYN
6: 0248 0000 c838 0002 0001 014a 0000 0000 //EV_KEY、BTN_TOUCH、0
7: 0248 0000 c876 0002 0003 0018 0000 0000 //EV_ABS、ABS_PRESSURE、0
8: 0248 0000 c89f 0002 0000 0000 0000 0000 //EV_SYN
1:绝对位置事件,X轴708处
2:绝对位置事件,Y轴385处
3:按键事件,触摸屏按键,1表示按下
4:绝对位置事件,绝对位置按压,压力为1(有些触摸屏是有压力检测的,这款触摸屏没有所以直接上报了1)
5:同步事件,用于分隔
6:按键事件,触摸屏按键,0表示松开
7:绝对位置事件,绝对位置按压,压力为0,表松开
8:同步事件
搞清除input事件后,编写一个应用其实非常简单,以触摸屏为例子,我们可以直接读取struct input_event
对象,然后根据type
、code
、key
来解析
#include
#include
#include
#include
#include
#include
int main(int argc, char* argv[])
{
if(argc != 2)
{
printf("Usage: %s \n", argv[0]);
return -1;
}
int fd = open(argv[1], O_RDONLY);
if(fd < 0)
{
printf("failed to open %s\n", argv[1]);
return -1;
}
struct input_event event;
int x = 0, y = 0;
while(1)
{
memset(&event, 0, sizeof(event));
read(fd, &event, sizeof(event));
if(event.type == EV_SYN)
continue;
if(event.type == EV_ABS)
{
if(event.code == ABS_X)
x = event.value;
else if(event.code == ABS_Y)
y = event.value;
}
else if(event.type == EV_KEY)
{
if(event.value == 1)
{
printf("touch press (%d,%d)\n", x, y);
}
else if(event.value == 0)
{
printf("touch release (%d,%d)\n", x, y);
x = 0;
y = 0;
}
}
else
continue;
}
close(fd);
return 0;
}