文档路径:Documentation\input\multi-touch-protocol.txt
。
一、介绍
为了充分利用新的多点触摸和多用户设备的功能,需要一种从多个触摸点(即与设备表面直接接触的对象)报告详细数据的方法。本文档描述了多触摸(MT
)协议,该协议允许内核驱动程序报告任意数量的触摸点的详细信息。
根据硬件的功能,协议分为两种类型。对于处理不可跟踪触摸点(类型 A
)的设备,协议描述了如何将所有触摸点的原始数据发送给接收方。对于能够跟踪可识别触摸点(类型 B
)的设备,协议描述了如何通过事件槽发送单个触摸点的更新。
注意:MT
协议类型A已过时,所有内核驱动程序都已转换为使用类型 B
。
二、协议使用
触摸点详细信息作为独立的 ABS_MT
事件包按顺序发送。只有 ABS_MT
事件被识别为事件包的一部分。由于这些事件被当前的单点触摸(ST
)应用程序忽略,MT
协议可以在现有驱动程序中的 ST
协议之上实现。
A
类设备的驱动程序通过在每个包的末尾调用 input_mt_sync()
来分离事件包。这将生成一个 SYN_MT_REPORT
事件,该事件指示接收者接受当前触摸点的数据并准备接收另一个触摸点的数据。
B
类设备的驱动程序通过调用 input_mt_slot()
在每个包的开头以 slot
作为参数来分离事件包。这将生成一个 ABS_MT_SLOT
事件,该事件指示接收器为给定事件槽的更新做好准备。
所有驱动程序都通过调用常用的 input_sync()
函数来标记多点触摸传输的结束。这指示接收端处理自上一次 EV_SYN/SYN_REPORT
以来累积的事件,并准备接收一组新的事件包。
无状态类型 A
协议和有状态类型 B
事件槽协议之间的主要区别在于使用可识别触摸点来减少发送到用户空间的数据量。事件槽协议需要使用 ABS_MT_TRACKING_ID
,它可以由硬件提供,也可以从原始数据 [#f5]_
中计算。
对于 A
类设备,内核驱动程序应该生成当前在表面上的全部不可跟踪触摸点的任意枚举。数据包在事件流中出现的顺序并不重要。事件过滤和手指跟踪留给用户空间 [#f3]_
。
对于 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
。
三、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
如果驱动报告 BTN_TOUCH
或 ABS_PRESSURE
除 ABS_MT
事件外,最后一个 SYN_MT_REPORT
事件可能会被省略。否则,最后一个 SYN_REPORT
将被输入核心丢弃,导致没有零接触事件到达用户域。
四、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
五、使用事件
定义了一组具有所需属性的 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
。现在想象一下这个人把手指更用力地压在玻璃上。触摸区域会增加,一般情况下,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
事件可以用于跟踪已识别的触摸点。
在 B
型协议中,ABS_MT_TOOL_TYPE
和 ABS_MT_TRACKING_ID
由输入核心隐式处理;驱动程序应该调用 input_mt_report_slot_state()
。
六、事件语义
1、ABS_MT_TOUCH_MAJOR
触点主轴的长度。长度应以表面单位表示。如果曲面的分辨率是 X
乘以Y
,那么 ABS_MT_TOUCH_MAJOR
的最大可能值是 (X^2 + Y^2)
,对角线 [#f4]_
。
2、ABS_MT_TOUCH_MINOR
接触轴的长度,以表面单位表示。如果接触是圆形的,这个事件可以省略 [#f4]_
。
3、ABS_MT_WIDTH_MAJOR
接触工具主轴的长度,以表面单位表示。这应该被理解为工具本身的大小。触点的方向和接触的工具假设是相同的 [#f4]_
。
4、ABS_MT_WIDTH_MINOR
接触工具小轴的长度,以表面单位表示。省略 if
循环 [#f4]_
。
以上四个值可用于获得关于触摸点的其他信息。比率 ABS_MT_TOUCH_MAJOR / ABS_MT_WIDTH_MAJOR
近似于压力的概念。手和手掌的手指都有不同的特征宽度。
5、ABS_MT_PRESSURE
接触面积上的压力,以任意单位表示。对于基于压力的设备或具有空间信号强度分布的任何设备,可用于代替 TOUCH
和 WIDTH
。
6、ABS_MT_DISTANCE
接触面与表面之间的距离,以表面单位表示。零距离表示触点接触表面。正数表示接触者在水面上方盘旋。
7、ABS_MT_ORIENTATION
接触椭圆的方向。该值应该描述围绕触控中心顺时针旋转的四分之一圈。带符号的值范围是任意的,但是对于与曲面的 Y
轴(北)对齐的椭圆应该返回零,当椭圆向左旋转时返回负值,当椭圆向右旋转时返回正值。当与 X
轴正方向对齐时,应返回范围 max
;当与 X
轴负方向对齐时,应返回 -max
范围。
默认情况下,触摸点是对称的。对于能够真正 360
度方向的设备,报告的方向必须超过最大范围,以表明超过 1/4
转。对于倒置的手指,应该返回范围 max*2
。
如果触摸区域是圆形的,或者如果该信息在内核驱动程序中不可用,则可以省略定向。部分方向支持是可能的,如果设备可以区分两个轴,但不能(唯一地)区分中间的任何值。在这种情况下, ABS_MT_ORIENTATION
的范围应该是 [0,1]
[#f4]_
。
8、ABS_MT_POSITION_X
接触椭圆中心的曲面 X
坐标。
9、ABS_MT_POSITION_Y
接触椭圆中心的面 Y
坐标。
10、ABS_MT_TOOL_X
接触工具中心的曲面 X
坐标。如果设备不能区分预期的触点和工具本身,则省略。
11、ABS_MT_TOOL_Y
接触工具中心的平面 Y
坐标。如果设备不能区分预期的触点和工具本身,则省略。
四个位置值可用于将触摸的位置与工具的位置分开。如果两个位置都存在,主工具轴指向接触点 [#f1]_
。否则,工具轴将与触摸轴对齐。
12、ABS_MT_TOOL_TYPE
接触工具的类型。许多内核驱动程序不能区分不同的工具类型,例如手指或钢笔。在这种情况下,应该省略该事件。协议目前主要支持 MT_TOOL_FINGER
、MT_TOOL_PEN
和 MT_TOOL_PALM
[#f2]_
。对于 B
类设备,此事件由输入核心处理;驱动程序应该使用 input_mt_report_slot_state()
。接触点的 ABS_MT_TOOL_TYPE
可能随着时间的推移而改变,但仍然接触设备,因为固件可能无法确定哪个工具在第一次出现时正在使用。
13、ABS_MT_BLOB_ID
BLOB_ID
将几个数据包组合成一个任意形状的接触点。点的序列形成一个多边形,它定义了触点的形状。这是 a
类设备的低级匿名分组,不应该与高级 trackingID
[#f5]_
混淆。大多数 A
型设备没有 blob
功能,因此驱动程序可以安全地忽略此事件。
14、ABS_MT_TRACKING_ID
TRACKING_ID
在其生命周期中标识一个发起的接触点 [#f5]_
。TRACKING_ID
的取值范围应该足够大,以确保在较长一段时间内保持的接触点的唯一标识。对于 B
类设备,此事件由输入核心处理;驱动程序应该使用 input_mt_report_slot_state()
。
七、事件计算
不同的硬件群不可避免地会导致一些设备比其他设备更适合 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
)增加。最后,假设触摸直径等于工具厚度,我们得到上面的公式。
八、手指跟踪
手指跟踪的过程,即为表面上的每个初始接触分配一个唯一的 trackingID
,是一个欧氏二部匹配问题。在每次事件同步时,实际触摸点集将与前一次同步中的触摸点集匹配。完整的实现可以在 [#f3]_
中找到。
九、手势
在创建手势事件的特定应用中,TOUCH
和 WIDTH
参数可用于近似手指压力或区分食指和拇指。通过添加 MINOR
参数,还可以区分扫指和指向的手指,通过 ORIENTATION
,可以检测手指的扭曲。
十、注意事项
为了与现有的应用程序保持兼容,手指包中报告的数据不能被识别为单点触摸事件。
对于 A
类设备,所有手指数据都绕过输入过滤,因为相同类型的后续事件引用不同的手指。
… [#f1] 此外,差异(TOOL_X
- POSITION_X
)可以用来建模倾斜。
… [#f2] 当然,这个清单还可以扩展。
… [#f3] mtdev
项目:http://bitmath.org/code/mtdev/。
… [#f4] 请参阅有关事件计算的部分。
… [#f5] 参见手指追踪部分。