触摸屏的使用
在Linux中,触摸屏是什么?
是文件,操作触摸屏其实就是操作文件(对于上层应用来说),可以使用操作文件的接口(open/read/close)去操作触摸屏
文件名(gec6818):"/dev/input/event0"(gec210):"/dev/event0"
在linux系统把所有的输入都封装为一个"输入事件"的结构体,都归属于linux输入子系统管理,linux输入子系统管理所有的输入设备,当输入设备发生输入信息的时候,会把输入信息包装为一个"输入事件"的结构体,再把结构体放到对应的文件中去
APP <---------> OS(linux) <----------> 驱动 <------------> Hardware
键盘
鼠标
触摸屏
手柄
.....
都是输入设备,都归结到输入子系统
对于APP,所有的设备都是以文件的方式去操作的
APP可以获取"输入事件"
输入设备发生的输入都会包装成为一个"输入事件(描述事件的数据)(struct input_event)",把输入事件保存到对应的文件(键盘,鼠标,触摸屏)中
任何设备发生的输入,都会包装成对应的事件保存到发生输入的"设备文件"中
用户如果需要获取输入信息,只需要打开对应的设备文件,读取结构体的内容即可:
(触摸屏和显示屏是两个独立的设备) 内屏:显示屏 外屏:触摸屏
操作的大概步骤:
1. 打开文件
2. 读取对应输入事件(结构体)
3. 解析结构体
4. 关闭文件输入事件是如何封装的?
在Linux中,使用了一个结构体来描述输入事件(struct input_event)定义在内核的头文件中(<linux/input.h>)
vim /usr/include/linux/input.h键盘事件
鼠标事件/* * The event structure itself */ struct input_event { struct timeval time; // 时间,记录了事件发生的时间 __u16 type; // unsigned short 事件的类型 __u16 code; // 事件的编码,根据事件的类型解析 __s32 value; // 事件的值,根据type的不同,有不同的含义 }; __u16 type; // unsigned short 事件的类型 // 判断是什么设备发生的这个事件。这些数据应该写入哪一个设备文件 Linux把所有的输入都进行了分类,不同的类型使用不同的“宏”表示 常见的: #define EV_KEY 0x01 // 按键事件(键盘事件) #define EV_REL 0x02 // 相对坐标事件(鼠标移动) #define EV_ABS 0x03 // 绝对坐标事件(触摸屏点的位置) ...... __u16 code; // 事件的编码,根据事件的类型解析 随着type的不同,code有不同的解释 如: if (type == EV_KEY) code表示键盘的键值,国际标准化组织,给每一个按键都分配了一个值 #define KEY_A 30 #define KEY_S 31 #define KEY_D 32 #define KEY_F 33 #define KEY_G 34 #define KEY_H 35 #define KEY_J 36 #define KEY_K 37 #define KEY_L 38 ...... 有时候也会把触摸屏整体当做一个按键 #define BTN_TOUCH 0x14a (判断手指是否离开屏幕) ... value表示具体的操作(按键的状态): value == 0 松开 value == 1 按下 ... 在虚拟机中, /dev/input/event1 表示键盘 当按键发生按键事件的时候,Linux输入子系统会把这个事件包装为结构体 写入到对应的文件中去,我们只需要读取事件结构体就可以了
触摸屏事件if (type == EV_REL) 此时code表示为相对(相对上一次)坐标事件 鼠标移动的时候,新的位置会相对于之前的位置有一个变化(轨迹) 鼠标移动一次,至少产生两个事件,坐标分为x和y 读取鼠标的移动,至少需要两个事件辅助 每一次的事件都和上一次的有关系 如: x轴相对原来的位置偏移了多少 y轴相对原来的位置偏移了多少 code表示相对坐标轴向 #define REL_X 0x00 #define REL_Y 0x01 ... 当ev.type == EV_REL && ev.code == REL_X 此事件结构体中的value表示x轴相对于原来的位置偏移了多少 当ev.type==EV_REL && ev.code==REL_Y 此事件结构体中的value表示y轴相对于原来的位置偏移了多少 value表示具体的偏移量(可正可负)
if (type == EV_ABS) 此时code表示为绝对(绝对的)坐标事件 触摸屏点击屏幕的时候,这次的位置和上次的位置没有关系,只需要说明当前位置的绝对坐标即可 整个屏幕所有的像素点其实是一个二维坐标系,只要能够描述点的位置即可 每一次发生的输入和上次没有关系 code表示绝对坐标轴向 #define ABS_X 0x00 #define ABS_Y 0x01 ... #define ABS_PRESSURE 0x18 // 压力值(判断手指是否离开屏幕) 当ev.type == EV_ABS && ev.code == ABS_X 此事件结构体中的value表示x轴的值是多少 当ev.type == EV_ABS && ev.code == ABS_Y 此事件结构体中的value表示y轴的值是多少 当ev.type == EV_ABS && ev.code == ABS_PRESSURE ---->这个事件去掉了,驱动里面没有了,不可再用 此事件结构体中的value表示压力值 value表示具体的坐标(>=0)
触摸屏的分辨率可能和显示屏的分辨率不一样,没有一一对应
触摸屏:1024*600 x*y
显示屏:800*480 x0*y0
需要做一个等比例的缩放:
x/1024 = x0/800 ===>x0 = 1.0 * x / 1024 * 800 注意:乘以1.0
y/600 = x0/480 ===>y0 = 1.0 * y / 600 * 480 注意:乘以1.0手指没有离开触摸屏,一直都在产生输入事件,多个struct input_event可以确定一个点
获取触摸屏上一个点的坐标
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <linux/input.h> int main(int argc, char *argv[]) { // 打开文件 int fd = open("/dev/input/event0", O_RDONLY); if (-1 == fd) { perror("open failed"); return -1; } struct input_event ev; // 保存读取到的输入事件 int x, y; while (1) { // 读取输入事件 int r = read(fd, &ev, sizeof(ev)); if (r != sizeof(ev)) { continue; } // 解析输入事件 if (ev.type == EV_ABS && ev.code == ABS_X) { x = ev.value * 1.0 / 1024 * 800; } if (ev.type == EV_ABS && ev.code == ABS_Y) { y = ev.value * 1.0 / 600 * 480; } // 手指离开屏幕的时候,退出循环 if (ev.type == EV_KEY && ev.code == BTN_TOUCH && ev.value == 0) { break; } // 手指离开屏幕的时候,退出循环,这个事件去掉了,不可再用 // if (ev.type == EV_ABS && ev.code == ABS_PRESSURE && ev.value == 0) { // break; // } } printf("x = %d,y = %d\n", x, y); // 关闭文件 close(fd); return 0; }
获取手指滑动的方向: