Linux与Android 多点触摸协议

  参考于:

            为了使用功能强大的多点触控设备,就需要一种方案去上报用户层所需的详细的手指触摸数据。这个文档所描述的多点触控协议可以让内核驱动程序向用户层上报任意多指的数据信息。

1、使用说明

承载并按一定顺序发送,如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_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,用来支持硬件跟踪多点信息,即该点属于哪一条线等。



[cpp] view plain copy print ?


1. 下面是两点触摸支持的最小事件集序列:  
2. ABS_MT_TOUCH_MAJOR  
3. ABS_MT_POSITION_X  
4. ABS_MT_POSITION_Y  
5. SYN_MT_REPORT //上报第一个点
6. ABS_MT_TOUCH_MAJOR  
7. ABS_MT_POSITION_X  
8. ABS_MT_POSITION_Y  
9. SYN_MT_REPORT //上报第二个点
10. //完成多点上报
11. SYN_REPORT //开始动作

[cpp] view plain copy print ?


1. 下面是两点触摸支持的最小事件集序列:  
2. ABS_MT_TOUCH_MAJOR  
3. ABS_MT_POSITION_X  
4. ABS_MT_POSITION_Y  
5. SYN_MT_REPORT //上报第一个点
6. ABS_MT_TOUCH_MAJOR  
7. ABS_MT_POSITION_X  
8. ABS_MT_POSITION_Y  
9. SYN_MT_REPORT //上报第二个点
10. //完成多点上报
11. SYN_REPORT //开始动作

下面是两点触摸支持的最小事件集序列:
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 //开始动作

2、Event原语

一词用来描述一个物体直接碰到另一个物体的表面。

                ABS_MT_TOUCH_MAJOR描述了主接触面的长轴,它和X,Y同一个单位,如果一个面的分辨率为X*Y,则ABS_MT_TOUCH_MAJOR的最大值为sqrt(X^2+Y^2)


[cpp] view plain copy print ?



    1. <SPAN style="WHITE-SPACE: pre"> </SPAN>ABS_MT_TOUCH_MINOR描述了接触面的短轴,如果接触面是圆形,它可以不用。  
    2.     ABS_MT_WIDTH_MAJOR描述了接触工具的长轴  
    3.     ABS_MT_WIDTH_MINOR描述了接触工具的短轴  
    4.     ABS_MT_TOUCH_MAJOR := max(X, Y)  
    5.     ABS_MT_TOUCH_MINOR := min(X, Y)  
    6. bool(X > Y)


    [cpp] view plain copy print ?



    1. <SPAN style="WHITE-SPACE: pre"> </SPAN>ABS_MT_TOUCH_MINOR描述了接触面的短轴,如果接触面是圆形,它可以不用。  
    2.     ABS_MT_WIDTH_MAJOR描述了接触工具的长轴  
    3.     ABS_MT_WIDTH_MINOR描述了接触工具的短轴  
    4.     ABS_MT_TOUCH_MAJOR := max(X, Y)  
    5.     ABS_MT_TOUCH_MINOR := min(X, Y)  
    6. bool(X > Y)


    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的比率可以用来描述压力。


    接触面的中心点X坐标

    接触面的中心点Y坐标

    描述接触工具类型,很多内核驱动无法区分此参数如手指及笔,如果是这样,该参数可以不用,协议目前支持MT_TOOL_FINGER和MT_TOOL_PEN两种类型。

    形状集ID,集合几个点以描述一个形状,很多驱动没有形状属性,此参数可以不用。ABS_MT_TRACKING_ID描述了从接触开始到释放的整个过程的集合,如果设备不支持,此参数可是不用。

    3、触摸轨迹

    ,多数情况下 trackingID只能来标识一次触摸动作的过程。

    4、手势

    和 WIDTH参数经常用来区别手指的压力和手指间的距离,另外 MINOR类的参数可以用来区别设备的接触面的大小(点接触还是面接触),ORIENTATION可以产生旋转事件。

    5、在Linux内核支持的基础上,Android在其2.0源码中加入多点触摸功能(android4.0中间层有所不同)

    的frameworks被完全分为2种实现途径:单点触摸屏的单点方式,多点触摸屏的单点和多点方式。

                 在Linux的input.h中,多点触摸功能依赖于以下几个主要的软件位:


    [cpp] view plain copy print ?

    1. ……  
    2. #define SYN_REPORT0
    3. #define SYN_CONFIG1
    4. #define SYN_MT_REPORT2
    5. ……  
    6. #define ABS_MT_TOUCH_MAJOR0x30
    7. #define ABS_MT_TOUCH_MINOR0x31
    8. #define ABS_MT_WIDTH_MAJOR0x32
    9. #define ABS_MT_WIDTH_MINOR0x33
    10. #define ABS_MT_ORIENTATION0x34
    11. #define ABS_MT_POSITION_X0x35
    12. #define ABS_MT_POSITION_Y0x36
    13. #define ABS_MT_TOOL_TYPE0x37
    14. #define ABS_MT_BLOB_ID0x38
    15. ……

      


    [cpp] view plain copy print ?



      1. ……  
      2. #define SYN_REPORT0
      3. #define SYN_CONFIG1
      4. #define SYN_MT_REPORT2
      5. ……  
      6. #define ABS_MT_TOUCH_MAJOR0x30
      7. #define ABS_MT_TOUCH_MINOR0x31
      8. #define ABS_MT_WIDTH_MAJOR0x32
      9. #define ABS_MT_WIDTH_MINOR0x33
      10. #define ABS_MT_ORIENTATION0x34
      11. #define ABS_MT_POSITION_X0x35
      12. #define ABS_MT_POSITION_Y0x36
      13. #define ABS_MT_TOOL_TYPE0x37
      14. #define ABS_MT_BLOB_ID0x38
      15. ……


      ……
        #define SYN_REPORT0
        #define SYN_CONFIG1
        #define SYN_MT_REPORT2
        ……
        #define ABS_MT_TOUCH_MAJOR0x30
        #define ABS_MT_TOUCH_MINOR0x31
        #define ABS_MT_WIDTH_MAJOR0x32
        #define ABS_MT_WIDTH_MINOR0x33
        #define ABS_MT_ORIENTATION0x34
        #define ABS_MT_POSITION_X0x35
        #define ABS_MT_POSITION_Y0x36
        #define ABS_MT_TOOL_TYPE0x37
        #define ABS_MT_BLOB_ID0x38
        ……




      在Android中对应的软件位定义在RawInputEvent.java中:



      [cpp] view plain copy print ?


      1. ……  
      2. public class
      3.  ……  
      4. public static final int
      5.  ……  
      6. public static final int
      7. public static final int
      8. public static final int
      9. public static final int
      10. public static final int
      11. public static final int
      12. public static final int
      13. public static final int
      14. public static final int
      15.  ……  
      16. public static final int
      17. public static final int
      18. public static final int
      19.  ……

      [cpp] view plain copy print ?

      1. ……  
      2. public class
      3.  ……  
      4. public static final int
      5.  ……  
      6. public static final int
      7. public static final int
      8. public static final int
      9. public static final int
      10. public static final int
      11. public static final int
      12. public static final int
      13. public static final int
      14. public static final int
      15.  ……  
      16. public static final int
      17. public static final int
      18. public static final int
      19.  ……

      ……
        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中,单点屏和多点屏由如下代码段来判定:


      [cpp] view plain copy print ?


      1. int EventHub::open_device(const char
      2. {  
      3. ……  
      4. if
      5. && test_bit(ABS_MT_POSITION_X, abs_bitmask)  
      6. && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {  
      7. device->classes |= CLASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT;  
      8. //LOGI("It is a multi-touch screen!");
      9. }  
      10.   
      11. //single-touch?
      12. else if
      13. && test_bit(ABS_X, abs_bitmask)  
      14. && test_bit(ABS_Y, abs_bitmask)) {  
      15. device->classes |= CLASS_TOUCHSCREEN;  
      16. //LOGI("It is a single-touch screen!");
      17. }  
      18. ……  
      19. }


      [cpp] view plain copy print ?


      1. int EventHub::open_device(const char
      2. {  
      3. ……  
      4. if
      5. && test_bit(ABS_MT_POSITION_X, abs_bitmask)  
      6. && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {  
      7. device->classes |= CLASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT;  
      8. //LOGI("It is a multi-touch screen!");
      9. }  
      10.   
      11. //single-touch?
      12. else if
      13. && test_bit(ABS_X, abs_bitmask)  
      14. && test_bit(ABS_Y, abs_bitmask)) {  
      15. device->classes |= CLASS_TOUCHSCREEN;  
      16. //LOGI("It is a single-touch screen!");
      17. }  
      18. ……  
      19. }


      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!");
        }
        ……
        }



      [cpp] view plain copy print ?

      1.  input_set_abs_params(mcs_data.input, ABS_MT_POSITION_X, pdata->abs_x_min, pdata->abs_x_max, 0, 0);  
      2.  input_set_abs_params(mcs_data.input, ABS_MT_POSITION_Y, pdata->abs_y_min, pdata->abs_y_max, 0, 0);  
      3. //相当于单点屏的ABX_PRESSURE
      4. //相当于单点屏的ABS_TOOL_WIDTH

      [cpp] view plain copy print ?


      1.  input_set_abs_params(mcs_data.input, ABS_MT_POSITION_X, pdata->abs_x_min, pdata->abs_x_max, 0, 0);  
      2.  input_set_abs_params(mcs_data.input, ABS_MT_POSITION_Y, pdata->abs_y_min, pdata->abs_y_max, 0, 0);  
      3. //相当于单点屏的ABX_PRESSURE
      4. //相当于单点屏的ABS_TOOL_WIDTH

      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


      [cpp] view plain copy print ?


      1. 例如一波要上报3个点:  
      2.    ……  
      3.   input_mt_sync(input);  
      4.   ……  
      5.   input_mt_sync(input);  
      6.   ……  
      7.   input_mt_sync(input);  
      8.   input_sync(input);  
      9.  注:即使是仅上报一个点的单点事件,也需要一次input_mt_sync。