输入设备应用编程
基于正点原子I.mx6u ALPHA V2.1开发板,记录自己的学习过程
1、如何找到输入设备对应的文件
在Linux中所有的输入设备都会在==/dev/input/==中,使用od
命令后,再操作相应的输入设备,会在终端打印信息若,成功打印信息,这就是输入设备对应的文件
#方法一:
sudo od -x /dev/input/xxx
#方法二:在这个文件里可以看到所有注册的input
cat /proc/bus/input/devices
2、读取设备的流程
- 应用程序打开/dev/input/event0 设备文件;
- 应用程序发起读操作(譬如调用 read),如果没有数据可读则会进入休眠(阻塞 I/O 情况下);
- 当有数据可读时,应用程序会被唤醒,读操作获取到数据返回;
- 应用程序对读取到的数据进行解析。
##3、 解析数据
每一次 read 操作获取的都是一个 struct input_event
结构体类型数据
#include <linux/input.h>
struct input_event {
struct timeval time;
__u16 type; //type 用于描述发生了哪一种类型的事件(对事件的分类)
__u16 code; //表示该类事件中的哪一个具体事件
__s32 value; //内核每次上报事件都会向应用层发送一个数据 value
};
#include "input-event-codes.h"
/*
* Event types
*/
#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)
数据同步:上面我们提到了同步事件类型 EV_SYN, 同步事件用于实现同步操作、告知接收者本轮上报的数据已
经完整。应用程序读取输入设备上报的数据时,一次 read 操作只能读取一个 struct input_event
类型数据,譬如对于触摸屏来说,一个触摸点的信息包含了 X 坐标、 Y 坐标以及其它信息, 对于这样情况,应用程序需
要执行多次 read 操作才能把一个触摸点的信息全部读取出来, 这样才能得到触摸点的完整信息。
那么应用程序如何得知本轮已经读取到完整的数据了呢?其实这就是通过同步事件来实现的, 内核将
本轮需要上报、发送给接收者的数据全部上报完毕后,接着会上报一个同步事件,以告知应用程序本轮数据
已经完整、 可以进行同步了。
4、触摸屏应用编程
触摸屏属于绝对位移设备(type=ev_ABS),分为单点触摸和多点触摸两种。单点触摸的code以ABS_XXX命名;多点触摸的code以ABS_MT_XXX命名
触摸屏设备除了上报绝对位移事件之外,还可以上报按键类事件和同步类事件。 当手指点击触摸屏或手指从触
摸屏离开时,此时就会上报按键类事件, 用于描述按下触摸屏和松开触摸屏; 具体的按键事件为BTN_TOUCH(code=0x14a,也就是 330) ,当然,手指在触摸屏上滑动不会上报 BTN_TOUCH 事件。
单点触摸设备事件上报顺序
# 点击触摸屏时
BTN_TOUCH
ABS_X
ABS_Y
SYN_REPORT
# 滑动
ABS_X
ABS_Y
SYN_REPORT
# 松开
BTN_TOUCH
SYN_REPORT
多点触摸
多点触摸设备使用多点触摸(MT)协议上报各个触摸点的数据, MT 协议分为两种类型: Type A 和 Type B, 主要使用Type B,每个触摸点会与ABS_MT_SLOT(47) 事件关联,ABS_MT_TRACTKING_ID 事件则用于触摸点的创建、替换和销毁工作
获取触摸屏信息
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);
在 input.h 头文件有一些宏定义
#define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo)
通过这个宏可以获取到触摸屏 slot(slot<0>表示触摸点 0、 slot<1>表示触摸点 1、 slot<2>表示触摸点 2,以此类推!)的取值范围, 可以看到使用该宏需要传入一个 abs 参数,该参数表示为一个 ABS_XXX 绝对位移事件,譬如 EVIOCGABS(ABS_MT_SLOT)表示获取触摸屏的 slot 信息,此时 ioctl()函数的第三个参数是
一个 struct input_absinfo *的指针,指向一个 struct input_absinfo 对象,调用 ioctl()会将获取到的信息写入到
struct input_absinfo 对象中。
struct input_absinfo {
__s32 value; //最新的报告值
__s32 minimum; //最小值
__s32 maximum; //最大值
__s32 fuzz;
__s32 flat;
__s32 resolution;
};
//获取触摸屏支持的最大触摸点数
max_slots = info.maximum + 1 - info.minimum;
__s32 fuzz;
__s32 flat;
__s32 resolution;
};
//获取触摸屏支持的最大触摸点数
max_slots = info.maximum + 1 - info.minimum;