Multi-touch Protocol

kernel/Documentation/input/multi-touch-protocol.rst

:Copyright: |copy| 2009-2010 Henrik Rydberg mailto:rydberg@euromail.se

Introduction

为了充分利用新的多点触控和多用户设备的全部功能,需要一种方式来上报多个触点(即与设备表面直接接触的对象)详细数据的方法。此文档描述了允许内核驱动程序报告任意数量的触点的详细信息的多点触控(MT)协议。

根据硬件的能力,此协议被分为了两种类型。对于处理匿名触点的设备(type A),此协议描述了如何将所有触点的原始数据发送给接收者。对于能够跟踪可识别触点的设备(type B),此协议描述了如何通过event slot来发送单个触点的更新信息。

注意: type A多点触控协议已经过时,所有的内核驱动程序都转用type B协议。

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。

Protocol 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_TOUCHABS_PRESSURE,则可以省略最后一个 SYN_MT_REPORT 事件。否则,最后一个 SYN_REPORT 将input core 忽略,导致没有零接触事件到达用户空间。

Protocol 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_XABS_MT_POSITION_Y 组成,允许跟踪多个触点。如果设备支持,ABS_MT_TOUCH_MAJORABS_MT_WIDTH_MAJOR 可分别用于提供触点面积尺寸和接触工具尺寸。

TOUCHWIDTH参数具有几何解释; 想象通过窗户看着某人轻轻地将手指靠在玻璃上。你会看到两个区域,一个由实际触碰在玻璃上的手指部分组成的内部区域,一个由手指周边形成的外部区域。接触区域的中心(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的比率与触点压力相关,该比率会小于1。对于基于压力的设备,使用ABS_MT_PRESSURE提供触点区域的压力。能够悬停接触的设备可以使用ABS_MT_DISTANCE来指示接触点与表面之间的距离。

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

除了MAJOR参数外,还可以通过添加MINOR参数来描述触摸区域和手指区域的椭圆形状,以使MAJORMINOR是椭圆的长轴和短轴。触摸椭圆的方向可以用ORIENTATION参数描述,而手指椭圆的方向则由矢量(a-b)给出。

对于A型设备,可以通过ABS_MT_BLOB_ID进一步指定触摸形状。

ABS_MT_TOOL_TYPE可以用于区分接触工具是手指、笔或者其他工具。最后,ABS_MT_TRACKING_ID事件可以用于跟踪一段时间内已识别的触点

Event Semantics:

ABS_MT_TOUCH_MAJOR

触点主轴长度。该长度需要以表面单位给出。如果表面的分辨率是X的Y倍,则ABS_MT_TOUCH_MAJOR的最大可能值为sqrt(X ^ 2 + Y ^ 2),即对角线。

ABS_MT_TOUCH_MINOR

触点的短轴长度,单位为表面单位。如果触点是元,该事件可以被忽略。

ABS_MT_WIDTH_MAJOR

接触工具的长轴长度,单位为表面单位。这要被理解为工具自身的尺寸。触点和接触工具的方向假定是一样的。

ABS_MT_WIDTH_MINOR

接触工具的长轴短度,单位为表面单位。如果为圆形忽略。

以上四个值可用于导出触点的其他信息。 比率ABS_MT_TOUCH_MAJOR / BS_MT_WIDTH_MAJOR近似于压力的概念。 手的手指和手掌都有不同的特征宽度。

ABS_MT_PRESSURE

接触区域上的压力(以任意单位表示)。 对于基于压力的设备或任何具有空间信号强度分布的设备,可以代替TOUCHWIDTH使用。

ABS_MT_DISTANCE

接触点和曲面之间的距离(以曲面为单位)。零距离意味着触点正在接触表面。 正数表示触点悬停在表面上方。

ABS_MT_ORIENTATION

接触椭圆的方向。该值应描述围绕触摸中心顺时针旋转的四分之一圈。有符号的值范围是任意的,但对于与曲面的Y轴(北)对齐的椭圆,应返回零;当将椭圆向左旋转时,应返回负值;当将椭圆向右旋转时,则应返回正值。当在正方向上与X轴对齐时,应返回最大范围; 当与X轴在负方向上对齐时,应返回-max范围。

默认情况下,触摸椭圆是对称的。 对于具有真正360度方位角的设备,报告的方位角必须超出最大范围,以表示超过四分之一圈。 对于倒置的手指,应返回最大* 2的范围。

如果接触区域是圆形或者在内核驱动中没有有效信息,方向可以被忽略。如果设备可以区分两个轴,但不能(唯一地)区分两个轴,则可以进行部分定向。在这种情况下,ABS_MT_ORIENTATION的取值范围为[0, 1]

ABS_MT_POSITION_X

接触椭圆中心表面X坐标。

ABS_MT_POSITION_Y

接触椭圆中心表面Y坐标。

ABS_MT_TOOL_X

接触工具的中心表面X坐标。如果设备不能区分想要的触点和工具本身,则可以忽略。

ABS_MT_TOOL_Y

接触工具的中心表面Y坐标。如果设备不能区分想要的触点和工具本身,则可以忽略。

以上四个位置值可用于将触摸位置与工具位置分开。如果两个位置都存在,则主工具轴指向接触点,否则,工具轴与触摸轴对其。

ABS_MT_TOOL_TYPE

接触工具类型。很多内核驱动不能分辨不同的工具类型,例如手指或笔。在这种情况下,该事件应该被忽略。协议当前主要支持MT_TOOL_FINGERMT_TOOL_PENMT_TOOL_PALM.

对于类型B设备,该事件由输入内核处理;驱动程序应该改用input_mt_report_slot_state()。一个触点的ABS_MT_TOOL_TYPE在一直触摸设备时可能发生改变,因为当工具首次出现时固件不能够确定正在使用哪个工具。

ABS_MT_BLOB_ID

BLOB_ID将几个数据包组合在一起,形成一个任意形状的触点。点序列形成定义接触形状的多边形。这是用于类型A设备的低级别匿名分组,不应与高级TrackingID 混淆。大部分的类型A设备没有这个blob功能,所以驱动可以安全地忽略这个事件。

ABS_MT_TRACKING_ID

TRACKING_ID识别一个触点并贯穿它的生命周期。TRACKING_ID的值范围应足够大,以确保在长时间内能唯一标识触点。 对于类型B的设备,此事件由输入内核处理;驱动程序应该改用input_mt_report_slot_state()

Event Computation

不同硬件的多样性不可避免地导致某些设备比其他设备更适合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)。

对于Win8设备具有T和C坐标,位置映射为:

   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)增大。 最后,假设接触直径等于工具厚度,我们得出上面的公式。

Finger Tracking

手指跟踪的过程,即为表面上的每个已启动接触分配唯一的trackingID,是欧几里得两部分匹配问题。在每个事件同步中,实际触点集与来自先前同步的触点集匹配。 完整的实现可以在下面找到。

Gestures

在创建手势事件的特定应用中,TOUCHWIDTH参数可用于例如估计手指压力或区分食指和拇指。通过添加MINOR参数,您还可以区分手指是扫动手指还是手指,并且通过ORIENTATION,可以检测手指的扭曲。

注意

为了与已存在的应用保持兼容,手指数据包中报告的数据不得被识别为单点触摸事件。

对于类型A设备,所有手指数据都绕过输入过滤,因为相同类型的后续事件引用了不同的手指。


戈壁老王
143 声望64 粉丝

做为一个不称职的老年码农,一直疏忽整理笔记,开博记录一下,用来丰富老年生活,


引用和评论

0 条评论