常用输入设备:鼠标,键盘,触摸屏,遥控器等。
input子系统:用于屏蔽硬件的差异,向应用层提供同一的接口。基于input子系统注册成功的设备都会在/dev/input目录下生成对应的设备节点,通常为/dev/input/event0等,通常通过这些设备节点可以获取这些设备节点上报的数据。
读取数据的流程:1.应用程序打开/dev/input/event0设备文件
2.应用程序发起读操作(调用read等),如果没有数据可读则会进去休眠。
3.当有数据可读是,应用程序会被唤醒,读操作获取到数据返回。
4.应用程序对读取到的数据进行解析。
如何解析数据:每一次的读取操作都是会哦去一个struct input_event结构体数据类型,结构体定义在<linux/input.h>,
struct input_event{
struct timeval time;
_u16 type;
_u16 code;
_s32 value;
}
结构体中的time是一个timeval类型结构体,用于记录每个上报事件上报的时间。
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)
点击鼠标按键(左键、右键,或鼠标上的其它按键)时会上报按键 类事件,移动鼠标时则会上报相对位移类事件。
code:表示该事件中的那一个具体事件。譬如:A,B字母按键等,告知具体是那一个按键发生了输入事件。
绝对位移事件:触摸屏设备是一种绝对位移设备,它能够产生绝对位移事件;譬如对于触摸屏来说,一个触摸点所包含 的信息可能有多种,譬如触摸点的 X 轴坐标、Y 轴坐标、Z 轴坐标、按压力大小以及接触面积等,所以 code 变量告知应用程序当前上报的是触摸点的哪一种信息(X 坐标还是 Y 坐标、亦或者其它);
value:内核每次上报事件都会向应用层发送一个数据value,value值的解释随着code的变化而变化。
数据同步:上面我们提到了同步事件类型 EV_SYN,同步事件用于实现同步操作、告知接收者本轮上报的数据已 经完整。应用程序读取输入设备上报的数据时,一次 read 操作只能读取一个 struct input_event 类型数据,譬 如对于触摸屏来说,一个触摸点的信息包含了 X 坐标、Y 坐标以及其它信息,对于这样情况,应用程序需 要执行多次 read 操作才能把一个触摸点的信息全部读取出来,这样才能得到触摸点的完整信息。
同步类事件中也包含了多种不同的事件,如下所示:
所以的输入设备都需要上报同步事件,上报的同步事件通常是 SYN_REPORT,而 value 值通常为 0。
读取struct input_event数据:判断具体需要读取哪一个设备节点,也可以通过查看/proc/bus/input/devices 文件得知,查看该文件可以获取到系统中注册 的所有输入设备相关的信息,如下所示:
读取键盘上面的按键:将usb键盘连接到开发板的USB_HOST接口上,插入后终端会打印驱动加载信息。驱动加载成功后,查看键盘按键相关的对应设备节点,使用命令cat /proc/bus/input/devices可以查看设备信息。
触摸屏数据读取:触摸屏设备时一个绝对位移设备,可以上报绝对位移事件。
单点触摸和多点触摸:一轮数据上报只包含一个触摸点信息;;单点触摸设备以 ABS_XXX 事件承载、上报触摸点的信息, 譬如 ABS_X(value 值对应的是 X 轴坐标值)、ABS_Y(value 值对应的是 Y 轴坐标值)等绝对位移事件, 而有些设备可能还支持 Z 轴坐标(通过 ABS_Z 事件上报、value 值对应的便是 Z 轴坐标值)、按压力大小 (通过 ABS_PRESSURE 事件上报、value 值对应的便是按压力大小)以及接触面积等属性。多点设备一轮可以包含多个数据。。多点触摸设备则是以 ABS_MT_XXX (MT 是 Multi-touch,意思为:多点触摸)事件承载、上报触摸点的信息,如 ABS_MT_POSITION_X(X 轴 坐标)、ABS_MT_POSITION_Y(Y 轴坐标)等绝对位移事件。
单点上报顺序:当手指点击触摸屏时,首先上报 BTN_TOUCH 事件,此时 value=1,表示按下;接着上报 ABS_X、ABS_Y 事件将 X、Y 轴坐标数据发送给应用层;数据上报完成接着上报一个同步事件 SYN_REPORT,表示此次触 摸点信息已经完整。当松开时,首先上报了 BTN_TOUCH 事件,此时 value=0,表示手指已经松开了触摸屏,接着上报一个 同步事件 SYN_REPORT。
多点上报顺序:一般使用type B协议。
Type B 协议适用于能够追踪并区分触摸点的设备,开发板配套使用的触摸屏都属于这类设备。Type B 协议的重点是通过 ABS_MT_SLOT 事件上报各个触摸点信息的更新!
能够追踪并区分触摸点的设备通常在硬件上能够区分不同的触摸点,譬如对于一个 5 点触摸设备来说, 硬件能够为每一个识别到的触摸点与一个 slot 进行关联,这个 slot 就是一个编号,触摸点 0、触摸点 1、触 摸点 2 等。底层驱动向应用层上报 ABS_MT_SLOT 事件,此事件会告诉接收者当前正在更新的是哪个触摸 点的数据,ABS_MT_SLOT 事件中对应的 value 数据存放的便是一个 slot、以告知应用层当前正在更新 slot 关联的触摸点对应的信息。
每个识别出来的触摸点分配一个 slot,与该 slot 关联起来,利用这个 slot 来传递对应触点的变化。除了 ABS_MT_SLOT 事 件 之 外 , Type B 协 议 还 会 使 用 到 ABS_MT_TRACTKING_ID 事 件 , ABS_MT_TRACTKING_ID 事件则用于触摸点的创建、替换和销毁工作,ABS_MT_TRACTKING_ID 事件 携带的数据 value 表示一个 ID,一个非负数的 ID(ID>=0)表示一个有效的触摸点,如果 ID 等于-1 表示该 触摸点已经不存在、被移除了;一个以前不存在的 ID 表示这是一个新的触摸点。 Type B 协议可以减少发送到用户空间的数据,只有发生了变更的数据才会上报,譬如某个触摸点发生 了移动,但仅仅只改变了 X 轴坐标、而未改变 Y 轴坐标,那么内核只会将改变后的 X 坐标值通过 ABS_MT_POSITION_X 事件发送给应用层。
获取触摸屏的信息:
可以通过ioctl()来处理,该函数一般用于操作特殊文件或首个被。函数原型如下:
#include<sys/ioctl.h>
int ioctl(intt fd,unsigned long request,....)
第一个参数是文件描述符,第二个参数与具体的操作对象有关,没有统一值,表示文件描述符请求相应操作,此函数hi一个可变参函数。
在input.h有宏定义用于使用:每一个宏定义后面都有相应的注释,对于 input 输入设备,对其执行 ioctl()操作需要使用这些宏,不同 的宏表示不同请求指令;譬如使用 EVIOCGNAME 宏获取设备名称,使用方式如下:
char name[100];
ioctl(fd, EVIOCGNAME(sizeof(name)), name);
EVIOCGNAME(len)就表示用于接收字符串数据的缓冲区大小,而此时 ioctl()函数的第三个参数需要传 入一个缓冲区的地址,该缓冲区用于存放设备名称对应的字符串数据。
EVIOCG(get)开头的表示获取信息,EVIOCS(set)开头表示设置;这里暂且不管其它宏,重点来看 看 EVIOCGABS(abs)宏,这个宏也是通常使用最多的,如下所示:
#define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo)
可以看到使用该宏需要传入一个 abs 参数,该参数表示为一个 ABS_XXX 绝对位 移事件,譬如 EVIOCGABS(ABS_MT_SLOT)表示获取触摸屏的 slot 信息,此时 ioctl()函数的第三个参数是 一个 struct input_absinfo *的指针,指向一个 struct input_absinfo 对象,调用 ioctl()会将获取到的信息写入到 struct input_absinfo 对象中。struct input_absinfo 结构体如下所示: