简介
为了使用功能强大的多点触控设备,就需要一种方案去上报用户层所需的详细的手指触摸数据。这个文档所描述的多点触控协议可以让内核驱动程序向用户层上报任意多指的数据信息。
使用说明
单点触摸信息是以ABS承载并按一定顺序发送,如BTN_TOUCH、ABS_X、ABS_Y、SYNC。而多点触摸信息则是以ABS_MT承载并按一定顺序发送,如ABS_MT_POSITION_X、ABS_MT_POSITION_Y,然后通过调用input_mt_sync()产生一个 SYN_MT_REPORT event来标记一个点的结束,告诉接收方接收当前手指的信息并准备接收其它手指的触控信息。最后调用 input_sync()函数上报触摸信息开始动作并告诉接收方开始接收下一系列多点触摸信息。
协议定义了一系列ABS_MT事件,这些事件被分为几大类,充许只应用其中的一部份,多点触摸最小的事件集中应包括ABS_MT_TOUCH_MAJOR、ABS_MT_POSITION_X和 ABS_MT_POSITION_Y,以此来实现多点触摸。如果设备支持ABS_MT_WIDTH_MAJOR这个事件,那么此事件可以提供手指触摸接触面积大小。触摸方向等信息可以由ABS_MT_TOUCH_MINOR, ABS_MT_WIDTH_MINOR and ABS_MT_ORIENTATION提供。ABS_MT_TOOL_TYPE提供触摸设备的类别,如手或是笔或是其它。最后有些设备可能会支持ABS_MT_TRACKING_ID,用来支持硬件跟踪多点信息,即该点属于哪一条线等。
下面是两点触摸支持的最小事件集序列:
ABS_MT_TOUCH_MAJOR
ABS_MT_POSITION_X
ABS_MT_POSITION_Y
SYN_MT_REPORT //上报第一个点
ABS_MT_TOUCH_MAJOR
ABS_MT_POSITION_X
ABS_MT_POSITION_Y
SYN_MT_REPORT //上报第二个点
SYN_REPORT //开始动作
Event 原语
“接触”一词用来描述一个物体直接碰到另一个物体的表面。
ABS_MT_TOUCH_MAJOR描述了主接触面的长轴,它和X,Y同一个单位,如果一个面的分辨率为X*Y,则ABS_MT_TOUCH_MAJOR的最大值为sqrt(X^2+Y^2)
ABS_MT_TOUCH_MINOR描述了接触面的短轴,如果接触面是圆形,它可以不用。
ABS_MT_WIDTH_MAJOR描述了接触工具的长轴
ABS_MT_WIDTH_MINOR描述了接触工具的短轴
ABS_MT_TOUCH_MAJOR := max(X, Y)
ABS_MT_TOUCH_MINOR := min(X, Y)
ABS_MT_ORIENTATION := bool(X > Y)
以上四个参数可以用来生成额外的触摸信息,如ABS_MT_TOUCH_MAJOR/ABS_MT_WIDTH_MAJOR的比率可以用来描述压力。
ABS_MT_ORIENTATION
ABS_MT_POSITION_X接触面的中心点X坐标
ABS_MT_POSITION_Y接触面的中心点Y坐标
ABS_MT_TOOL_TYPE描述接触工具类型,很多内核驱动无法区分此参数如手指及笔,如果是这样,该参数可以不用,协议目前支持MT_TOOL_FINGER和MT_TOOL_PEN两种类型。
ABS_MT_BLOB_ID形状集ID,集合几个点以描述一个形状,很多驱动没有形状属性,此参数可以不用。
ABS_MT_TRACKING_ID描述了从接触开始到释放的整个过程的集合,如果设备不支持,此参数可是不用。
触摸轨迹
仅有少数设备可以明触的标识真实的 trackingID,多数情况下 trackingID只能来标识一次触摸动作的过程。
手势
多点触摸指定的应用是创建手势动作, TOUCH和 WIDTH参数经常用来区别手指的压力和手指间的距离,另外 MINOR类的参数可以用来区别设备的接触面的大小(点接触还是面接触),ORIENTATION可以产生旋转事件。
===============================================================================================================
在Linux内核支持的基础上,Android在其2.0源码中加入多点触摸功能。由此触摸屏在Android的frameworks被完全分为2种实现途径:单点触摸屏的单点方式,多点触摸屏的单点和多点方式。
在Linux的input.h中,多点触摸功能依赖于以下几个主要的软件位:
……………………….. #define SYN_REPORT0 #define SYN_CONFIG1 #define SYN_MT_REPORT2 ………………………... #define ABS_MT_TOUCH_MAJOR0x30/* Major axis of touching ellipse */ #define ABS_MT_TOUCH_MINOR0x31/* Minor axis (omit if circular) */ #define ABS_MT_WIDTH_MAJOR0x32/* Major axis of approaching ellipse */ #define ABS_MT_WIDTH_MINOR0x33/* Minor axis (omit if circular) */ #define ABS_MT_ORIENTATION0x34/* Ellipse orientation */ #define ABS_MT_POSITION_X0x35/* Center X ellipse position */ #define ABS_MT_POSITION_Y0x36/* Center Y ellipse position */ #define ABS_MT_TOOL_TYPE0x37/* Type of touching device */ #define ABS_MT_BLOB_ID0x38/* Group a set of packets as a blob */ ………………………… |
在Android中对应的软件位定义在RawInputEvent.java中:
………………….. public class RawInputEvent { ………………. public static final int CLASS_TOUCHSCREEN_MT = 0x00000010; ……………….. public static final int ABS_MT_TOUCH_MAJOR = 0x30; public static final int ABS_MT_TOUCH_MINOR = 0x31; public static final int ABS_MT_WIDTH_MAJOR = 0x32; public static final int ABS_MT_WIDTH_MINOR = 0x33; public static final int ABS_MT_ORIENTATION = 0x34; public static final int ABS_MT_POSITION_X = 0x35; public static final int ABS_MT_POSITION_Y = 0x36; public static final int ABS_MT_TOOL_TYPE = 0x37; public static final int ABS_MT_BLOB_ID = 0x38; …………………. public static final int SYN_REPORT = 0; public static final int SYN_CONFIG = 1; public static final int SYN_MT_REPORT = 2; ……………….. |
在Android中,多点触摸的实现方法在具体的代码实现中和单点是完全区分开的。在Android代码的EventHub.cpp中,单点屏和多点屏由如下代码段来判定:
int EventHub::open_device(const char *deviceName) { ……………………… if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask) && test_bit(ABS_MT_POSITION_X, abs_bitmask) && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) { device->classes |= CLASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT; //LOGI("It is a multi-touch screen!"); } //single-touch? else if (test_bit(BTN_TOUCH, key_bitmask) && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) { device->classes |= CLASS_TOUCHSCREEN; //LOGI("It is a single-touch screen!"); } ……………….. } |
我们知道,在触摸屏驱动中,通常在probe函数中会调用input_set_abs_params给设备的input_dev结构体初始化,这些input_dev的参数会在Android的EventHub.cpp中被读取。如上可知,如果我们的触摸屏想被当成多点屏被处理,只需要在驱动中给input_dev额外增加以下几个参数即可:
input_set_abs_params(mcs_data.input, ABS_MT_POSITION_X, pdata->abs_x_min, pdata->abs_x_max, 0, 0); input_set_abs_params(mcs_data.input, ABS_MT_POSITION_Y, pdata->abs_y_min, pdata->abs_y_max, 0, 0); input_set_abs_params(mcs_data.input, ABS_MT_TOUCH_MAJOR, 0, 15, 0, 0); //相当于单点屏的ABX_PRESSURE input_set_abs_params(mcs_data.input, ABS_MT_WIDTH_MAJOR, 0, 15, 0, 0); //相当于单点屏的ABS_TOOL_WIDTH |
由于多点触摸技术需要采集到多个点,然后再一起处理这些点,所以在软件实现中需要保证每一波点的准确性和完整性。因此,Linux内核提供了input_mt_sync(struct input_dev * input)函数。在每波的每个点上报后需要紧跟一句input_mt_sync(), 当这波所有点上报后再使用input_sync()进行同步。例如一波要上报3个点:
/* 上报点1*/ …………….. input_mt_sync(input); /* 上报点2*/ …………….. input_mt_sync(input); /* 上报点3*/ …………….. input_mt_sync(input); input_sync(input); |
注:即使是仅上报一个点的单点事件,也需要一次input_my_sync。
3.2驱动程序软件设计
依托Linux输入子系统架构,驱动程序的设计需要完成以下工作。
(1)分配、注册、注销input设备
各个接口函数如下:
◆分配函数为structinput_dev*input_allocate_device(void);
◆注册函数为intinput_register_device(structinput_dev*devr);
◆注销函数为voidinput_unregister_device(structinput_dev*dev)。
(2)设置input设备支持的事件类型
通过set_bit()告诉所支持的事件类型,触摸屏的事件类型代码为EV_ABS(0x03)。
(3)电容触摸屏参数设置
由input_set_abs_params()函数完成,代码如下:
input_set_abs_params(input,ABS_X,0,960,0,0);
//屏幕分辨率为960×640
Input_set_abs_params(input,ABS_Y,0.640,0,0);
//X坐标范围0~960
Input_set_abs_params(input,ABS_MAJOR,0,255,0,0);
//Y坐标范围0~640
(4)上报输入事件
触摸屏被触摸感应时,通过input_report_abs()函数上报发生的事件及坐标值。
3.3驱动设计的主要函数
(1)voidspi_init()函数
在该函数中通过spi_register_driver(strcutspi_driver*drv)来注册触摸屏SPI接口。
(2)Touch_probe()函数
在这个函数中,会对SPI总线的相关参数进行配置,并注册open()和close()函数。调用input_dev*input_allocate_device(void)进行输入设备分配;调用set_bit(EV_ABS,input_evbit)来设置触摸屏事件;调用input_set_params()设置坐标范围及接触点主轴长度范围;最后调用input_register_device(structinput_dev*dev)把触摸屏注册为输入子系统设备。
(3)触摸屏中断注册及中断处理函数
request_irq(TOUCHIRQ,Touchinterrupt,0,“touch”,NULL)为中断函数注册,其中Touch_interrupt是中断处理函数。当触摸屏有感应时将拉低INT引脚,此时便触发中断处理函数Touch_interrupt.该中断函数调用intput_report_abs()将采集到的坐标数据上报给输入子系统,当为单点触摸时,上报该触点;当为多点触摸时,依次将每个点的坐标上报。这里为了消除抖动带来的误操作,在中断处理程序中启用了一个定时器init_timer(),进入中断后将延时5ms,然后才对数据读取。
3.4数据的处理
电容式触摸屏支持多点识别,所以必须要处理好多点数据的采集,为此将采集到的数据放到事先分配好的缓存read_data[]中。该缓存存有触点的个数以及各个触点的坐标值,为了保证每一点的准确性和完整性,需要用内核函数input_mt_sync()进行同步。具体的读取代码如下:
文章链接:中国仪表网 http://www.ybzhan.cn/Tech_news/Detail/71150.html