3. 多點觸控 (MT) 協議

版權:

© 2009-2010 Henrik Rydberg <rydberg@euromail.se>

3.1. 簡介

為了充分利用新的多點觸控和多使用者裝置的功能,需要一種報告來自多個觸點(即與裝置表面直接接觸的物體)的詳細資料的方式。本文件描述了多點觸控 (MT) 協議,該協議允許核心驅動程式報告任意數量觸點的詳細資訊。

該協議分為兩種型別,具體取決於硬體的功能。對於處理匿名觸點(A 型)的裝置,該協議描述瞭如何將所有觸點的原始資料傳送給接收器。對於能夠跟蹤可識別觸點(B 型)的裝置,該協議描述瞭如何透過事件槽傳送單個觸點的更新。

注意

MT 協議 A 型已過時,所有核心驅動程式都已轉換為使用 B 型。

3.2. 協議用法

觸點詳細資訊作為單獨的 ABS_MT 事件包按順序傳送。只有 ABS_MT 事件被識別為觸點包的一部分。由於當前單點觸控 (ST) 應用程式會忽略這些事件,因此 MT 協議可以在現有驅動程式中的 ST 協議之上實現。

A 型裝置的驅動程式透過在每個資料包末尾呼叫 input_mt_sync() 來分隔觸點資料包。 這會生成一個 SYN_MT_REPORT 事件,該事件指示接收器接受當前觸點的資料並準備接收另一個。

B 型裝置的驅動程式透過在每個資料包的開頭呼叫 input_mt_slot(),並以槽作為引數,來分隔觸點資料包。 這會生成一個 ABS_MT_SLOT 事件,該事件指示接收器準備給定槽的更新。

所有驅動程式都透過呼叫常用的 input_sync() 函式來標記多點觸控傳輸的結束。 這指示接收器對自上次 EV_SYN/SYN_REPORT 以來累積的事件執行操作,並準備接收一組新的事件/資料包。

無狀態的 A 型協議和有狀態的 B 型槽協議之間的主要區別在於使用可識別的觸點來減少傳送到使用者空間的資料量。 槽協議需要使用 ABS_MT_TRACKING_ID,可以是硬體提供的,也可以是從原始資料計算出來的 [5]

對於 A 型裝置,核心驅動程式應生成當前表面上完整的一組匿名觸點的任意列舉。 資料包在事件流中出現的順序並不重要。 事件過濾和手指跟蹤留給使用者空間 [3]

對於 B 型裝置,核心驅動程式應將一個槽與每個已識別的觸點相關聯,並使用該槽來傳播該觸點的更改。 觸點的建立、替換和銷燬透過修改關聯槽的 ABS_MT_TRACKING_ID 來實現。 非負跟蹤 ID 被解釋為觸點,值 -1 表示未使用的槽。 以前不存在的跟蹤 ID 被認為是新的,不再存在的跟蹤 ID 被認為是已刪除的。 由於只傳播更改,因此每個已啟動觸點的完整狀態必須駐留在接收端。 接收到 MT 事件後,只需更新當前槽的相應屬性。

某些裝置識別和/或跟蹤的觸點比它們可以報告給驅動程式的觸點更多。 此類裝置的驅動程式應將一個 B 型槽與硬體報告的每個觸點相關聯。 每當與槽關聯的觸點的身份發生更改時,驅動程式應透過更改其 ABS_MT_TRACKING_ID 來使該槽失效。 如果硬體發出訊號表明它正在跟蹤比當前報告的更多的觸點,則驅動程式應使用 BTN_TOOL_*TAP 事件來通知使用者空間此時硬體跟蹤的總觸點數。 驅動程式應透過顯式傳送相應的 BTN_TOOL_*TAP 事件並在呼叫 input_mt_report_pointer_emulation() 時將 use_count 設定為 false 來執行此操作。 驅動程式應僅通告硬體可以報告的槽數。 使用者空間可以透過注意到支援的最大 BTN_TOOL_*TAP 事件大於 ABS_MT_SLOT 軸的 absinfo 中報告的 B 型槽總數來檢測驅動程式可以報告比槽更多的總觸點數。

ABS_MT_SLOT 軸的最小值必須為 0。

3.3. 協議示例 A

以下是 A 型裝置兩次觸碰的最小事件序列示例

ABS_MT_POSITION_X x[0]
ABS_MT_POSITION_Y y[0]
SYN_MT_REPORT
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_MT_REPORT
SYN_REPORT

移動其中一個觸點後的序列看起來完全相同; 每個與 SYN_REPORT 的同步之間都會發送所有當前觸點的原始資料。

以下是抬起第一個觸點後的序列

ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_MT_REPORT
SYN_REPORT

以下是抬起第二個觸點後的序列

SYN_MT_REPORT
SYN_REPORT

如果驅動程式除了 ABS_MT 事件之外還報告 BTN_TOUCH 或 ABS_PRESSURE,則可以省略最後一個 SYN_MT_REPORT 事件。 否則,最後一個 SYN_REPORT 將被輸入核心丟棄,導致沒有零觸點事件到達使用者空間。

3.4. 協議示例 B

以下是 B 型裝置兩次觸碰的最小事件序列示例

ABS_MT_SLOT 0
ABS_MT_TRACKING_ID 45
ABS_MT_POSITION_X x[0]
ABS_MT_POSITION_Y y[0]
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID 46
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_REPORT

以下是在 x 方向上移動觸點 45 後的序列

ABS_MT_SLOT 0
ABS_MT_POSITION_X x[0]
SYN_REPORT

以下是抬起槽 0 中的觸點後的序列

ABS_MT_TRACKING_ID -1
SYN_REPORT

正在修改的槽已經是 0,因此省略了 ABS_MT_SLOT。 該訊息刪除了槽 0 與觸點 45 的關聯,從而銷燬觸點 45 並釋放槽 0 以供另一個觸點重用。

最後,以下是抬起第二個觸點後的序列

ABS_MT_SLOT 1
ABS_MT_TRACKING_ID -1
SYN_REPORT

3.5. 事件用法

定義了一組具有所需屬性的 ABS_MT 事件。 這些事件分為幾類,以允許部分實現。 最小集合由 ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y 組成,這允許跟蹤多個觸點。 如果裝置支援,則可以使用 ABS_MT_TOUCH_MAJOR 和 ABS_MT_WIDTH_MAJOR 來分別提供接觸區域和接近工具的大小。

TOUCH 和 WIDTH 引數具有幾何解釋; 想象一下透過窗戶看著有人輕輕地將手指按在玻璃上。 您將看到兩個區域,一個內部區域由實際接觸玻璃的手指部分組成,另一個外部區域由手指的周長形成。 觸控區域的中心 (a) 是 ABS_MT_POSITION_X/Y,接近手指的中心 (b) 是 ABS_MT_TOOL_X/Y。 觸控直徑為 ABS_MT_TOUCH_MAJOR,手指直徑為 ABS_MT_WIDTH_MAJOR。 現在想象一下這個人更用力地將手指按在玻璃上。 觸控區域將會增大,並且通常,始終小於 1 的比率 ABS_MT_TOUCH_MAJOR / ABS_MT_WIDTH_MAJOR 與接觸壓力有關。 對於基於壓力的裝置,可以使用 ABS_MT_PRESSURE 來提供接觸區域上的壓力。 能夠進行接觸懸停的裝置可以使用 ABS_MT_DISTANCE 來指示觸點與表面之間的距離。

     Linux MT                               Win8
    __________                     _______________________
   /          \                   |                       |
  /            \                  |                       |
 /     ____     \                 |                       |
/     /    \     \                |                       |
\     \  a  \     \               |       a               |
 \     \____/      \              |                       |
  \                 \             |                       |
   \        b        \            |           b           |
    \                 \           |                       |
     \                 \          |                       |
      \                 \         |                       |
       \                /         |                       |
        \              /          |                       |
         \            /           |                       |
          \__________/            |_______________________|

除了 MAJOR 引數之外,觸控區域和手指區域的橢圓形狀可以透過新增 MINOR 引數來描述,這樣 MAJOR 和 MINOR 就是橢圓的長軸和短軸。 觸控橢圓的方向可以用 ORIENTATION 引數描述,手指橢圓的方向由向量 (a - b) 給出。

對於 A 型裝置,可以透過 ABS_MT_BLOB_ID 進一步指定觸控形狀。

ABS_MT_TOOL_TYPE 可用於指定觸控工具是手指還是筆或其他工具。 最後,可以使用 ABS_MT_TRACKING_ID 事件來跟蹤一段時間內識別的觸點 [5]

在 B 型協議中,ABS_MT_TOOL_TYPE 和 ABS_MT_TRACKING_ID 由輸入核心隱式處理; 驅動程式應改為呼叫 input_mt_report_slot_state()

3.6. 事件語義

ABS_MT_TOUCH_MAJOR

觸點的長軸長度。 長度應以表面單位給出。 如果表面具有 X 乘以 Y 的解析度,則 ABS_MT_TOUCH_MAJOR 的最大可能值為 sqrt(X^2 + Y^2),即對角線 [4]

ABS_MT_TOUCH_MINOR

觸點的短軸長度(以表面單位為單位)。 如果觸點是圓形的,則可以省略此事件 [4]

ABS_MT_WIDTH_MAJOR

接近工具的長軸長度(以表面單位為單位)。 這應該理解為工具本身的大小。 假定觸點和接近工具的方向相同 [4]

ABS_MT_WIDTH_MINOR

接近工具的短軸長度(以表面單位為單位)。 如果是圓形的,則省略 [4]

以上四個值可用於推導有關觸點的其他資訊。 比率 ABS_MT_TOUCH_MAJOR / ABS_MT_WIDTH_MAJOR 近似於壓力的概念。 手指和手掌都有不同的特徵寬度。

ABS_MT_PRESSURE

接觸區域上的壓力,以任意單位表示。 對於基於壓力的裝置或任何具有空間訊號強度分佈的裝置,可以代替 TOUCH 和 WIDTH 使用。

如果解析度為零,則壓力資料以任意單位表示。 如果解析度不為零,則壓力資料以單位/克表示。 有關詳細資訊,請參閱 輸入事件程式碼

ABS_MT_DISTANCE

觸點與表面之間的距離(以表面單位為單位)。 零距離表示觸點正在觸控表面。 正數表示觸點懸停在表面上方。

ABS_MT_ORIENTATION

觸控橢圓的方向。 該值應描述圍繞觸控中心順時針方向旋轉的帶符號的四分之一圈。 帶符號的值範圍是任意的,但是對於與表面的 Y 軸(北)對齊的橢圓應返回零,當橢圓向左轉時應返回負值,當橢圓向右轉時應返回正值。 當與正方向的 X 軸對齊時,應返回範圍 max;當與負方向的 X 軸對齊時,應返回範圍 -max。

觸控橢圓預設是對稱的。 對於能夠進行真正 360 度方向的裝置,報告的方向必須超過範圍 max 才能指示超過四分之一圈。 對於倒置的手指,應返回範圍 max * 2。

如果觸控區域是圓形的,或者核心驅動程式中沒有此資訊,則可以省略方向。 如果裝置可以區分兩個軸,但不能(唯一地)區分其間的任何值,則可以提供部分方向支援。 在這種情況下,ABS_MT_ORIENTATION 的範圍應為 [0, 1] [4]

ABS_MT_POSITION_X

觸控橢圓中心的表面 X 座標。

ABS_MT_POSITION_Y

觸控橢圓中心的表面 Y 座標。

ABS_MT_TOOL_X

接近工具中心的表面 X 座標。 如果裝置無法區分預期觸控點和工具本身,則省略。

ABS_MT_TOOL_Y

接近工具中心的表面 Y 座標。 如果裝置無法區分預期觸控點和工具本身,則省略。

四個位置值可用於將觸控的位置與工具的位置分開。 如果兩個位置都存在,則主工具軸指向觸控點 [1]。 否則,工具軸與觸控軸對齊。

ABS_MT_TOOL_TYPE

接近工具的型別。 許多核心驅動程式無法區分不同的工具型別,例如手指或筆。 在這種情況下,應省略該事件。 該協議目前主要支援 MT_TOOL_FINGER、MT_TOOL_PEN 和 MT_TOOL_PALM [2]。 對於 B 型裝置,此事件由輸入核心處理; 驅動程式應改為使用 input_mt_report_slot_state()。 觸點的 ABS_MT_TOOL_TYPE 可能會隨著時間的推移而發生變化,同時仍觸控裝置,因為韌體可能無法確定首次出現時正在使用哪個工具。

ABS_MT_BLOB_ID

BLOB_ID 將多個數據包分組到一個任意形狀的觸點中。 點序列形成一個多邊形,該多邊形定義了觸點的形狀。 這是 A 型裝置的低階匿名分組,不應與高階跟蹤 ID 混淆 [5]。 大多數 A 型裝置沒有 blob 功能,因此驅動程式可以安全地省略此事件。

ABS_MT_TRACKING_ID

TRACKING_ID 標識已啟動觸點的整個生命週期 [5]。 TRACKING_ID 的值範圍應足夠大,以確保在長時間內保持觸點的唯一標識。 對於 B 型裝置,此事件由輸入核心處理; 驅動程式應改為使用 input_mt_report_slot_state()

3.7. 事件計算

不同的硬體的出現不可避免地導致某些裝置比其他裝置更適合 MT 協議。 為了簡化和統一對映,本節給出瞭如何計算某些事件的說明。

對於將觸點報告為矩形的裝置,無法獲得帶符號的方向。 假設 X 和 Y 是觸控矩形的邊長,以下是一個簡單的公式,可以保留儘可能多的資訊

ABS_MT_TOUCH_MAJOR := max(X, Y)
ABS_MT_TOUCH_MINOR := min(X, Y)
ABS_MT_ORIENTATION := bool(X > Y)

ABS_MT_ORIENTATION 的範圍應設定為 [0, 1],以指示裝置可以區分沿 Y 軸的手指 (0) 和沿 X 軸的手指 (1)。

對於具有 T 和 C 座標的 Win8 裝置,位置對映為

ABS_MT_POSITION_X := T_X
ABS_MT_POSITION_Y := T_Y
ABS_MT_TOOL_X := C_X
ABS_MT_TOOL_Y := C_Y

不幸的是,沒有足夠的資訊來指定觸控橢圓和工具橢圓,因此必須求助於近似值。 一種簡單的方案(與早期用法相容)是

ABS_MT_TOUCH_MAJOR := min(X, Y)
ABS_MT_TOUCH_MINOR := <not used>
ABS_MT_ORIENTATION := <not used>
ABS_MT_WIDTH_MAJOR := min(X, Y) + distance(T, C)
ABS_MT_WIDTH_MINOR := min(X, Y)

理由:我們沒有關於觸控橢圓方向的資訊,因此可以用內切圓來近似它。 工具橢圓應與向量 (T - C) 對齊,因此直徑必須隨距離 (T, C) 增加。 最後,假設觸控直徑等於工具厚度,我們得出以上公式。

3.8. 手指跟蹤

手指跟蹤的過程,即為表面上每個啟動的觸點分配唯一的 trackingID,是一個歐幾里得二分匹配問題。 在每次事件同步時,實際觸點集與上次同步的觸點集進行匹配。 完整的實現可以在 [3] 中找到。

3.9. 手勢

在建立手勢事件的具體應用中,TOUCH 和 WIDTH 引數可以用來近似手指壓力或區分食指和拇指。新增 MINOR 引數後,還可以區分掃動的手指和指向的手指,而透過 ORIENTATION,可以檢測手指的扭動。

3.10. 註釋

為了保持與現有應用程式的相容性,在手指資料包中報告的資料不得被識別為單點觸控事件。

對於 A 類裝置,所有手指資料都繞過輸入過濾,因為同一型別的後續事件指的是不同的手指。