Multi-touch-protocol
Linux内核文档multi-touch-protocol.rst
Introduction
为了充分利用新的多点触控和多用户设备的全部功能,
需要一种报告来自多个触点(即与设备表面直接接触的对象)的详细数据的方法。
此文档描述了允许内核驱动程序报告任意数量的触点的详细信息的多点触控协议。
根据硬件的能力,此协议被分为了两种类型。对于处理匿名触点的设备(type A),
此协议描述了如何将所有触点的原始数据发送给接收者。
对于能够跟踪可识别触点的设备,此协议描述了如何通过event slot来发送单个
触点的更新信息。
note
type A多点触控协议已经过时,所有的内核驱动程序都转用type bark”中断。
protcol usage
触点的详细信息被作为单独的ABS_MT事件数据包顺序发送。
只有 ABS_MT 事件被识别为触点数据包的一部分。
由于当前的单点触控 (ST) 应用程序忽略了这些事件,
因此可以在现有驱动程序中的 ST 协议之上实现 MT 协议。
type A设备的驱动程序通过在每个数据包的结尾调用input_mt_sync()来分隔触点
数据包。这样会产生一个SYN_MT_REPORT事件来指示接收方接收当前触点的数据并
准备好接收下一个触点的数据。
type B设备通过在每个数据包的开头调用input_mt_slot(),并以slot作为参数
来分隔触点数据包。这样会产生一个ABS_MT_SLOT事件来指示接收方准备更新给定的
slot的信息。
所有的驱动程序都通过调用input_sync()函数来标记多点触控数据传输的结束。
这指示接受者对上一次EV_SYN/SYN_REPORT事件以后的事件进行处理,并准备好接收
新的事件或者数据包。
无状态type A以及有状态type B的主要区别在于使用可识别的触点来减少发送到用户
空间的数据。slot协议需要使用ABS_MT_TRACKING_ID,它由硬件提供或者通过原始数
据计算得出。
对于type A类设备,驱动程序应该生成当前触屏上全部匿名触点的任意枚举。数据
包在事件流中出现的顺序并不重要,事件过滤以及手指跟踪被留到了用户空间。
对于type B设备,驱动程序应该将每个可识别的触点和一个slot关联,并用slot来更
新触点的变化。通过修改触点关联的slot的ABS_MT_TRACKING_ID来创建,替换或者销
毁触点。非负的ID被认为是有效的触点,-1表示未被使用的slot。 以前没有出现的ID
被认为是新的,不再出现的ID被认为是已经移出了的。由于只有改变了的东西会被发送
,因此每个触点的完整状态必须驻留在接收端。 收到 MT 事件后,只需更新当前slot
的相关的属性。
一些设备识别和/或跟踪的触点数量超过了它们可以向驱动程序报告的数量。
此类设备的驱动程序应将一个 B 型slot与硬件报告的每个触点相关联。
每当与slot关联的触点发生更改时,驱动程序应通过更改其ABS_MT_TRACKING_ID使该
slot无效。如果硬件信号表明它正在跟踪的触点数量比当前报告的多,则驱动程序应使
用 BTN_TOOL_*TAP 事件来通知用户空间当时硬件正在跟踪的触点的数量。驱动程序应
通过显式的发送相应的BTN_TOOL_*TAP事件并在调用
input_mt_report_pointer_emulation()时将use_count设置为false来执行此操作。
驱动程序应该只公布硬件可以报告的尽可能多的slot。用户空间可以通过注意最大支持
的 BTN_TOOL_*TAP 事件大于在 ABS_MT_SLOT 轴的 absinfo 中报告的 B 类slot的
总数来检测驱动程序可以报告比插槽更多的总触点数。
ABS_MT_SLOT轴的最小值必须为0。
example A:
以下是type 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 将input core 忽略
,导致没有零接触事件到达用户空间。
example B:
以下是type 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
以下是在释放slot0对应的触点之后的序列:
ABS_MT_TRACKING_ID -1
SYN_REPORT
因为被修改的slot已经是0,所以ABS_MT_SLOT会被忽略。这个消息解除了slot0与触点
45的关联,以此来销毁触点45并释放slot0给其他的触点使用。
最后,以下是释放第二个触点之后的序列:
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID -1
SYN_REPORT
event usage:
定义了一组具有所需属性的 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的比值
总是小于unity,与接触压力有关。对于基于压力的设备,ABS_MT_PRESSURE 可用于
提供接触区域的压力。拥有接触悬停功能的设备可以使用 ABS_MT_DISTANCE 来指示
触点和surface之间的距离。
Linux MT Win8
__________ _______________________
/ \ | |
/ \ | |
/ ____ \ | |
/ / \ \ | |
\ \ a \ \ | a |
\ \____/ \ | |
\ \ | |
\ b \ | b |
\ \ | |
\ \ | |
\ \ | |
\ / | |
\ / | |
\ / | |
\__________/ |_______________________|
除了 MAJOR 参数外,触摸和手指区域的椭圆形状可以通过添加 MINOR 参数来描述,
使得 MAJOR 和 MINOR 是椭圆的长轴和短轴。 触摸椭圆的方向可以用 ORIENTATION
参数描述,手指椭圆的方向由向量 (a - b) 给出。
对于type A设备,可以通过 ABS_MT_BLOB_ID 进一步指定触摸形状。
ABS_MT_TOOL_TYPE 可用于指定触摸工具是手指还是笔或其他东西。最后,
ABS_MT_TRACKING_ID 事件可用于随时间跟踪识别的触点[#f5]_。
在type B协议中,ABS_MT_TOOL_TYPE和ABS_MT_TRACKING_ID由input core隐式处理;
驱动程序应改为调用 input_mt_report_slot_state()。
event semantics:
ABS_MT_TOUCH_MAJOR
触点主轴的长度。长度应以表面单位给出。如果触屏具有 X * Y 分辨率,
则 ABS_MT_TOUCH_MAJOR 可能的最大值是 sqrt(X^2 + Y^2),对角线 [#f4]_。
ABS_MT_TOUCH_MINOR
触点短轴的长度,以表面为单位。如果触点是循环的,这个事件可以省略[#f4]_。
ABS_MT_WIDTH_MAJOR
触控工具主轴的长度,以表面为单位。这应该理解为工具本身的大小。
假定接触方向和接近工具的方向相同 [#f4]_。
ABS_MT_WIDTH_MINOR
触控工具的短轴的长度,以表面为单位。如果循环 [#f4]_ 则省略。
上述四个值可用于获取有关触点的附加信息。
ABS_MT_TOUCH_MAJOR / ABS_MT_WIDTH_MAJOR比值近似于压力的概念。
手和手掌的手指都有不同的特征宽度。
ABS_MT_PRESSURE
触点面积上的压力,以任意单位表示。对于基于压力的设备或任何具有空间信号
强度分布的设备,可以使用它来代替 TOUCH 和 WIDTH。
ABS_MT_DISTANCE
接触点和曲面之间的距离(以曲面为单位)。零距离意味着触点正在接触表面。
正数表示触点悬停在表面上方。
ABS_MT_ORIENTATION
触点椭圆的方向。该值应描述围绕触摸中心顺时针旋转的有符号四分之一。
带符号的值范围是任意的,但是对于与曲面的 Y 轴(北)对齐的椭圆,应返回零,
向左旋转时返回负值,向左旋转时返回正值正确的。与X轴正方向对齐时,
应返回范围最大值;当与 X 轴负方向对齐时,应返回范围 -max。
默认情况下,触摸省略号是对称的。对于能够真正 360 度定向的设备,
报告的方向必须超过最大范围以指示超过四分之一转。
对于倒置的手指,应该返回 range max * 2。
如果触摸区域是圆形的,或者内核驱动程序中没有该信息,则可以省略方向。
如果设备可以区分两个轴,但不能(唯一)介于两者之间的任何值,则可以支持
部分方向。在这种情况下,ABS_MT_ORIENTATION 的范围应该是 [0, 1] [#f4]_。
ABS_MT_POSITION_X
触点椭圆中心的表面 X 坐标。
ABS_MT_POSITION_Y
触点椭圆中心的表面 Y 坐标。
ABS_MT_TOOL_X
接近工具中心的表面 X 坐标。如果设备无法区分预期的接触点和工具本身则省略。
ABS_MT_TOOL_Y
接近工具中心的表面 Y 坐标。如果设备无法区分预期的接触点和工具本身则省略。
这四个位置值可用于将触摸位置与工具位置分开。如果两个位置都存在,
则主工具轴指向接触点 [#f1]_。否则,工具轴与触摸轴对齐。
ABS_MT_TOOL_TYPE
触控工具的类型。许多内核驱动程序无法区分不同的工具类型,例如手指或笔。
在这种情况下,应省略该事件。目前协议主要支持MT_TOOL_FINGER、
MT_TOOL_PEN、MT_TOOL_PALM[#f2]_。
对于 B 类设备,此事件由输入内核处理;驱动程序应改为使用
input_mt_report_slot_state()。
触点的 ABS_MT_TOOL_TYPE 可能会随着时间的推移而变化,但仍会触摸设备,
因为固件可能无法在首次出现时确定正在使用的工具。
ABS_MT_BLOB_ID
BLOB_ID 将多个数据包组合成一个任意形状的触点。
点序列形成定义接触形状的多边形。这是 A 类设备的低级匿名分组,
不应与高级 tracking ID [#f5]_ 混淆。大多数 A 类设备没有 blob 功能,
因此驱动程序可以安全地忽略此事件。
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] 参见手指跟踪部分。
|