目录
一、输入设备
输入设备为外部输入信息给用户的设备,常见的输入设备有:键盘,鼠标,触摸屏。它们均能产生输入事件,产生输入数据给计算机。
二、input子系统
Linux系统为了统一管理输入设备,实现了一套能够兼容输入设备的驱动框架,这个框架就是input子系统。
tips:基于input子系统注册成功的输入设备,都会在/dev/input目录下生成对应的设备文件(设备节点),设备节点的名字通常为eventX(X:0,1,2....)
三、读取数据
1.打开设备节点文件
2.程序进行读操作(read)
3.读操作获取到数据
4.解析数据
四、解析数据
read 操作获取的都是一个 struct input_event 结构体类型数据,struct input_event结构体如下所示:
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
1.time:记录每个上报事件的发生时间
2.type:描述哪一类事件,linux所支持事件如下所示
#define EV_SYN 0x00 //同步类事件,用于同步事件
#define EV_KEY 0x01 //按键类事件
#define EV_REL 0x02 //相对位移类事件(譬如鼠标)
#define EV_ABS 0x03 //绝对位移类事件(譬如触摸屏)
#define EV_MSC 0x04 //其它杂类事件
#define EV_SW 0x05
#define EV_LED 0x11
#define EV_SND 0x12
#define EV_REP 0x14
#define EV_FF 0x15
#define EV_PWR 0x16
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
#define EV_CNT (EV_MAX+1)
3.code:描述type事件中的具体事件,例如按键事件(键盘)中的A按键按下或是松开,code按键类事件如下所示:
#define KEY_RESERVED 0
#define KEY_ESC 1 //ESC 键
#define KEY_1 2 //数字 1 键
#define KEY_2 3 //数字 2 键
#define KEY_TAB 15 //TAB 键
#define KEY_Q 16 //字母 Q 键
#define KEY_W 17 //字母 W 键
#define KEY_E 18 //字母 E 键
#define KEY_R 19 //字母 R 键
……
相对位移事件:
相对位移事件
#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 REL_MAX 0x0f
#define REL_CNT (REL_MAX+1)
绝对位移事件(触摸屏):
#define ABS_X 0x00 //X 轴
#define ABS_Y 0x01 //Y 轴
#define ABS_Z 0x02 //Z 轴
#define ABS_RX 0x03
#define ABS_RY 0x04
#define ABS_RZ 0x05
#define ABS_THROTTLE 0x06
#define ABS_RUDDER 0x07
#define ABS_WHEEL 0x08
#define ABS_GAS 0x09
#define ABS_BRAKE 0x0a
#define ABS_HAT0X 0x10
#define ABS_HAT0Y 0x11
#define ABS_HAT1X 0x12
#define ABS_HAT1Y 0x13
#define ABS_HAT2X 0x14
#define ABS_HAT2Y 0x15
#define ABS_HAT3X 0x16
#define ABS_HAT3Y 0x17
#define ABS_PRESSURE 0x18
#define ABS_DISTANCE 0x19
#define ABS_TILT_X 0x1a
#define ABS_TILT_Y 0x1b
#define ABS_TOOL_WIDTH 0x1c
......
tips:可以自己浏览<linux/input.h>头文件(这些宏其实是定义在input-event-codes.h 头文中,该头文件被<linux/input.h>所包含了)。
4.value:内核每次上报一个事件都会向应用层发送一个数据value。例如对于按键事件来说,如果 code=2,那么如果 value 等于 1,则表示 KEY_1 键按下;value 等于 0 表示 KEY_1 键松开,如果 value 等于 2则表示 KEY_1 键长按。
五、数据同步
同步类事件EV_SYN,用于实现同步操作。告知接收者本轮上报的数据已经完整。同步事件中也包含了多种不同事件。
#define SYN_REPORT 0
#define SYN_CONFIG 1
#define SYN_MT_REPORT 2
#define SYN_DROPPED 3
#define SYN_MAX 0xf
#define SYN_CNT (SYN_MAX+1)
tips:应用程序读取输入设备上报的数据时,一次read操作只能读取一个strucu input_event类型数据,多次读取(read)得到完整数据信息,通过同步事件,告知应用程序本轮数据已经完整。
六、KEY代码编写
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <linux/input.h>
int main(int argc,char *argv[])
{
struct input_event in_ev = {0};
int ret,fd = -1,value = -1;
//检验传参
if(argc != 2)
{
fprintf(stderr,"usage:%s<input-dev>\n",argv[0]);
exit(-1);
}
//打开文件
fd = open(argv[1],O_RDONLY);
if(fd < 0)
{
fprintf(stderr,"open error");
exit(-1);
}
while(1)
{
//循环读取数据
ret = sizeof(struct input_event);
if(ret != read(fd,&in_ev,ret))
{
fprintf(stderr,"read error");
close(fd);
exit(-1);
}
if(EV_KEY == in_ev.type)//按键事件
{
switch(in_ev.value)
{
case 0:
{
fprintf(stdout,"code<%d>:松开\n",in_ev.code);
}break;
case 1:
{
fprintf(stdout,"code<%d>:按下\n",in_ev.code);
}break;
case 2:
{
fprintf(stdout,"code<%d>:长按\n",in_ev.code);
}break;
}
}
}
}
tips:设备文件不同于普通文件,读写设备文件之前无需设置读写位置偏移量
七、编译
arm-linux-gnueabihf-gcc key.c -o keyAPP
八、运行
运行结果如下所示:
tips:按下开发板上的KEY0,松开开发板上的KEY0,长按开发板上的KEY0观察实验现象是否一致。
九、作者自述
记录生活。