天天看點

Linux與Android 多點觸摸協定

Linux與Android 多點觸摸協定

  參考于:http://blog.csdn.net/joqian/article/details/8269205

            為了使用功能強大的多點觸控裝置,就需要一種方案去上報使用者層所需的詳細的手指觸摸資料。這個文檔所描述的多點觸控協定可以讓核心驅動程式向使用者層上報任意多指的資料資訊。

1、使用說明

            單點觸摸資訊是以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,用來支援硬體跟蹤多點資訊,即該點屬于哪一條線等。

[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.     ABS_MT_ORIENTATION := 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.     ABS_MT_ORIENTATION := 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的比率可以用來描述壓力。

                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描述了從接觸開始到釋放的整個過程的集合,如果裝置不支援,此參數可是不用。

3、觸摸軌迹

            僅有少數裝置可以明觸的辨別真實的 trackingID,多數情況下 trackingID隻能來辨別一次觸摸動作的過程。

4、手勢

            多點觸摸指定的應用是建立手勢動作, TOUCH和 WIDTH參數經常用來差別手指的壓力和手指間的距離,另外 MINOR類的參數可以用來差別裝置的接觸面的大小(點接觸還是面接觸),ORIENTATION可以産生旋轉事件。

5、在Linux核心支援的基礎上,Android在其2.0源碼中加入多點觸摸功能(android4.0中間層有所不同)

            由此觸摸屏在Android的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 RawInputEvent {  
  3.  ……  
  4.  public static final int CLASS_TOUCHSCREEN_MT = 0x00000010;  
  5.  ……  
  6.  public static final int ABS_MT_TOUCH_MAJOR = 0x30;  
  7.  public static final int ABS_MT_TOUCH_MINOR = 0x31;  
  8.  public static final int ABS_MT_WIDTH_MAJOR = 0x32;  
  9.  public static final int ABS_MT_WIDTH_MINOR = 0x33;  
  10.  public static final int ABS_MT_ORIENTATION = 0x34;  
  11.  public static final int ABS_MT_POSITION_X = 0x35;  
  12.  public static final int ABS_MT_POSITION_Y = 0x36;  
  13.  public static final int ABS_MT_TOOL_TYPE = 0x37;  
  14.  public static final int ABS_MT_BLOB_ID = 0x38;  
  15.  ……  
  16.  public static final int SYN_REPORT = 0;  
  17.  public static final int SYN_CONFIG = 1;  
  18.  public static final int SYN_MT_REPORT = 2;  
  19.  ……  

[cpp] view plain copy print ?

  1. ……  
  2.  public class RawInputEvent {  
  3.  ……  
  4.  public static final int CLASS_TOUCHSCREEN_MT = 0x00000010;  
  5.  ……  
  6.  public static final int ABS_MT_TOUCH_MAJOR = 0x30;  
  7.  public static final int ABS_MT_TOUCH_MINOR = 0x31;  
  8.  public static final int ABS_MT_WIDTH_MAJOR = 0x32;  
  9.  public static final int ABS_MT_WIDTH_MINOR = 0x33;  
  10.  public static final int ABS_MT_ORIENTATION = 0x34;  
  11.  public static final int ABS_MT_POSITION_X = 0x35;  
  12.  public static final int ABS_MT_POSITION_Y = 0x36;  
  13.  public static final int ABS_MT_TOOL_TYPE = 0x37;  
  14.  public static final int ABS_MT_BLOB_ID = 0x38;  
  15.  ……  
  16.  public static final int SYN_REPORT = 0;  
  17.  public static final int SYN_CONFIG = 1;  
  18.  public static final int SYN_MT_REPORT = 2;  
  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 *deviceName)  
  2. {  
  3. ……  
  4. if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)  
  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. //single-touch?  
  11. else if (test_bit(BTN_TOUCH, key_bitmask)  
  12. && test_bit(ABS_X, abs_bitmask)  
  13. && test_bit(ABS_Y, abs_bitmask)) {  
  14. device->classes |= CLASS_TOUCHSCREEN;  
  15. //LOGI("It is a single-touch screen!");  
  16. }  
  17. ……  
  18. }  

[cpp] view plain copy print ?

  1. int EventHub::open_device(const char *deviceName)  
  2. {  
  3. ……  
  4. if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)  
  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. //single-touch?  
  11. else if (test_bit(BTN_TOUCH, key_bitmask)  
  12. && test_bit(ABS_X, abs_bitmask)  
  13. && test_bit(ABS_Y, abs_bitmask)) {  
  14. device->classes |= CLASS_TOUCHSCREEN;  
  15. //LOGI("It is a single-touch screen!");  
  16. }  
  17. ……  
  18. }  
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額外增加以下幾個參數即可:

[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.  input_set_abs_params(mcs_data.input, ABS_MT_TOUCH_MAJOR, 0, 15, 0, 0);//相當于單點屏的ABX_PRESSURE  
  4.  input_set_abs_params(mcs_data.input, ABS_MT_WIDTH_MAJOR, 0, 15, 0, 0);//相當于單點屏的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.  input_set_abs_params(mcs_data.input, ABS_MT_TOUCH_MAJOR, 0, 15, 0, 0);//相當于單點屏的ABX_PRESSURE  
  4.  input_set_abs_params(mcs_data.input, ABS_MT_WIDTH_MAJOR, 0, 15, 0, 0);//相當于單點屏的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
           

               由于多點觸摸技術需要采集到多個點,然後再一起處理這些點,是以在軟體實作中需要保證每一波點的準确性和完整性。是以,Linux核心提供了input_mt_sync(struct input_dev * input)函數。在每波的每個點上報後需要緊跟一句input_mt_sync(),當這波所有點上報後再使用input_sync()進行同步。

[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。  

繼續閱讀