输入系统框架图:
数据流程:
① APP 发起read操作,若无数据则休眠;
② 用户操作设备,硬件上产生中断;
③ 输入系统驱动层对应的驱动程序处理中断: 读取到数据,转换为标准的输入事件,向核心层汇报;
④ 核心层可以决定把输入事件转发给上面哪个 handler 来处理;
(evdev_handler、kbd_handler、joydev_handler 等)
evdev_handler(最常用):把 input_event 结构体保存在内核 buffer ,支持多个 APP 同时访问。
⑤ APP 对输入事件的处理;
APP 获 得 数 据 的 方 法 有 2 种 : 直 接 访 问 设 备 节 点 或者通过 tslib、libinput 这类库来间接 访问设备节点。
驱动程序:把数据从硬件设备传到APP(可以将同一硬件数据分发给多个APP)
APP得到的数据时一系列的输入事件
单个输入事件以“struct input_event”结构体表示
struct input_event{ struct timeval time; #时间 __u16 type; #哪类(如EV_KEY代表按键) __u16 code; #哪个(如KEY_A) __s32 value; #取值大小(如0-按下,1-松开) } struct timeval{ __kernel_time_t tv_sec; #时间以秒表示 __kernel_suseconds_t tv_usec; #时间以微秒表示 }
一份触摸屏数据:
同步事件“0000 0000 0000 0000”(type=code=value=0)会分隔开独立的完整事件。
输入设备:以“struct input_dev”结构体表示
struct input_dev { const char *name; const char *phys; const char *uniq; struct input_id id; unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; #支持哪类事件? key/rel/abs? unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; #支持按键的话,支持哪个/些按键 unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; #支持相对位移的话,支持哪此 unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; #支持绝对位移的话,支持哪些 unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; }
查看输入设备的设备节点:ls /dev/input/* -l
查看设备节点对应的硬件信息:cat /proc/bus/input/devices
应用编程:使用ioctl( )查看输入设备的的硬件信息
#include <linux/input.h> #include <sys/types.h> //open()头文件 #include <sys/stat.h> //open()头文件 #include <fcntl.h> //open()头文件 #include <sys/ioctl.h> //ioctl()头文件 #include <stdio.h> //print()头文件 /* input:./01_get_input_info /dev/input/event0 */ int main(int argc, char **argv) { int fd; int err; int len; int i; unsigned char byte; int bit; struct input_id id; unsigned int evbit[2]; char *ev_names[] = { //事件类型-事件名称对应表 "EV_SYN ", "EV_KEY ", "EV_REL ", "EV_ABS ", "EV_MSC ", "EV_SW ", "NULL ", "NULL ", "NULL ", "NULL ", "NULL ", "NULL ", "NULL ", "NULL ", "NULL ", "NULL ", "NULL ", "EV_LED ", "EV_SND ", "NULL ", "EV_REP ", "EV_FF ", "EV_PWR ", }; if (argc != 2) { printf("Usage: %s <dev>\n", argv[0]); return -1; } fd = open(argv[1], O_RDWR); //O_RDWR可读可写 if (fd < 0) //无法打开 { printf("open %s err\n", argv[1]); return -1; } err = ioctl(fd, EVIOCGID, &id); //get id,需传入id地址才能对其操作 if (err == 0) { printf("bustype = 0x%x\n", id.bustype ); printf("vendor = 0x%x\n", id.vendor ); printf("product = 0x%x\n", id.product ); printf("version = 0x%x\n", id.version ); } len = ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), &evbit); //get evbit设备支持的事件类型 if (len > 0 && len <= sizeof(evbit)) //长度符合要求代表读取到数据,打印数据对应类型 { printf("support ev type: "); for (i = 0; i < len; i++) { byte = ((unsigned char *)evbit)[i]; for (bit = 0; bit < 8; bit++) { if (byte & (1<<bit)) { //byte里的低bit位为1 printf("%s ", ev_names[i*8 + bit]); } } } printf("\n"); } return 0; }
事件类型-事件名称对应表 不连续的值用NULL表示