Android 支持各种触摸屏和触摸板,包括基于触控笔的数字化板。
触摸屏是与显示屏相关联的触摸设备,使用户能够在屏幕上直接操纵内容。
触摸板是不与显示屏相关联的触摸设备(如数字化板)。触摸板通常用于指控或绝对间接定位或基于手势的界面控制。
触摸设备可能具有功能与鼠标按钮类似的按钮。
有时可以使用各种不同的工具(如手指或触控笔)操作触摸设备,具体取决于底层的触摸传感器技术。
触摸设备有时用于实现虚拟按键。例如,在某些 Android 设备上,触摸屏传感器区域延伸超出显示屏的边缘,作为触摸式键盘的一部分发挥双重作用。
由于触摸设备种类繁多,因此 Android 依赖于大量配置属性来描述每种设备的特征和预期行为。
触摸设备分类
如果同时满足以下两个条件,那么输入设备属于多点触控设备:
- 输入设备报告存在
ABS_MT_POSITION_X
和ABS_MT_POSITION_Y
绝对轴。 - 输入设备没有任何游戏手柄按钮。某些游戏手柄会使用与 MT 轴的代码重叠的代码来报告轴,而这一条件则消除了这种歧义。
如果同时满足以下两个条件,那么输入设备属于单点触控设备:
- 输入设备不属于多点触控设备。输入设备要么属于单点触控设备,要么属于多点触控设备,而不会同时属于这两种类别。
- 输入设备报告存在
ABS_X
和ABS_Y
绝对轴以及BTN_TOUCH
按键代码。
如果输入设备属于触摸设备,系统会通过尝试加载设备的虚拟按键映射文件来确定是否存在虚拟按键。如果存在虚拟按键映射,则还会加载设备的按键布局文件。如需了解这些文件的位置和格式,请参阅 [虚拟按键映射文件](#virtual-key-map-files)。
接下来,系统会加载触摸设备的输入设备配置文件。
所有内置触摸设备都应具有输入设备配置文件。如果没有输入设备配置文件,系统会选择适用于通用触摸外围设备(如外部 USB 或蓝牙 HID 触摸屏或触摸板)的默认配置。这些默认配置不适用于内置触摸屏,可能会导致错误行为。
加载输入设备配置后,系统会将输入设备分类为触摸屏、触摸板或指控设备。
- 触摸屏设备用于直接操纵屏幕上的对象。用户直接触摸屏幕,因此系统不需要使用任何额外的方式来指明所操控的对象。
- 触摸板设备用于向应用提供关于在给定传感器区域上进行触摸时的绝对定位信息。它可能对数字化板有用。
- 指控设备用于使用光标间接操纵屏幕上的对象。手指被解释为多点触控指控手势。其他工具(如触控笔)则通过绝对位置来解释。有关详情,请参阅间接多点触控指控手势。
以下规则用于将输入设备归类为触摸屏、触摸板或指控设备。
- 如果设置了
touch.deviceType
属性,将按照指示设置设备类型。 - 如果输入设备报告存在
INPUT_PROP_DIRECT
输入属性(通过EVIOCGPROP
ioctl),设备类型将设置为触摸屏。该条件假设直接输入触摸设备已连接到同样处于连接状态的显示屏。 - 如果输入设备报告存在
INPUT_PROP_POINTER
输入属性(通过EVIOCGPROP
ioctl),设备类型将设置为指控设备。 - 如果输入设备报告存在
REL_X
或REL_Y
相对轴,设备类型将设置为触摸板。该条件消除了由鼠标和触摸板组成的输入设备存在的歧义。在这种情况下,触摸板不会用于控制指针,因为指针已由鼠标控制。 - 否则,设备类型将设置为指控设备。该默认设置确保没有指定任何其他特殊用途的触摸板将用于控制指控设备。
按钮
按钮是应用可用来执行其他功能的可选控件。触摸设备上的按钮与鼠标按钮类似,主要与指控式触摸设备或者触控笔配合使用。
支持以下按钮:
BTN_LEFT
:映射到MotionEvent.BUTTON_PRIMARY
。BTN_RIGHT
:映射到MotionEvent.BUTTON_SECONDARY
。BTN_MIDDLE
:映射到MotionEvent.BUTTON_MIDDLE
。BTN_BACK
和BTN_SIDE
:映射到MotionEvent.BUTTON_BACK
。按此按钮还可以合成按键(使用按键代码KeyEvent.KEYCODE_BACK
)。BTN_FORWARD
和BTN_EXTRA
:映射到MotionEvent.BUTTON_FORWARD
。按此按钮还可以合成按键(使用按键代码KeyEvent.KEYCODE_FORWARD
)。BTN_STYLUS
:映射到MotionEvent.BUTTON_SECONDARY
。BTN_STYLUS2
:映射到MotionEvent.BUTTON_TERTIARY
。
工具和工具类型
“工具”是指用于和触摸设备进行交互的手指、触控笔或其他装置。有些触摸设备可以区分不同类型的工具。
在 Android 的其他位置(和在 MotionEvent
API 中一样),工具通常称为“指针”。
支持以下工具类型:
BTN_TOOL_FINGER
和MT_TOOL_FINGER
:映射到MotionEvent.TOOL_TYPE_FINGER
。BTN_TOOL_PEN
和MT_TOOL_PEN
:映射到MotionEvent.TOOL_TYPE_STYLUS
。BTN_TOOL_RUBBER
:映射到MotionEvent.TOOL_TYPE_ERASER
。BTN_TOOL_BRUSH
:映射到MotionEvent.TOOL_TYPE_STYLUS
。BTN_TOOL_PENCIL
:映射到MotionEvent.TOOL_TYPE_STYLUS
。BTN_TOOL_AIRBRUSH
:映射到MotionEvent.TOOL_TYPE_STYLUS
。BTN_TOOL_MOUSE
:映射到MotionEvent.TOOL_TYPE_MOUSE
。BTN_TOOL_LENS
:映射到MotionEvent.TOOL_TYPE_MOUSE
。BTN_TOOL_DOUBLETAP
、BTN_TOOL_TRIPLETAP
和BTN_TOOL_QUADTAP
:映射到MotionEvent.TOOL_TYPE_FINGER
。
悬停与触摸工具
工具可以与触摸设备接触,也可以在触摸设备的感应范围内悬停在设备的上方。并非所有触摸设备都能够感应到悬停在其上方的工具。那些可实现感应的触摸设备(如基于射频的触控笔数字化仪)通常能在工具进入数字化仪有限的感应范围后检测到该工具。
InputReader
组件会区分触摸工具和悬停工具。同样,触摸工具和悬停工具也会以不同的方式报告给应用。
系统将使用 MotionEvent.ACTION_DOWN
、MotionEvent.ACTION_MOVE
、MotionEvent.ACTION_DOWN
、MotionEvent.ACTION_POINTER_DOWN
和 MotionEvent.ACTION_POINTER_UP
将触摸工具作为触摸事件报告给应用,
并使用 MotionEvent.ACTION_HOVER_ENTER
、MotionEvent.ACTION_HOVER_MOVE
和 MotionEvent.ACTION_HOVER_EXIT
将悬停工具作为通用动作事件报告给应用。
触摸设备驱动程序要求
- 触摸设备驱动程序应仅注册其支持的轴/按钮的轴/按键代码。如果注册不受支持的轴或按键代码,可能会令设备分类算法感到困惑,或导致系统在检测设备功能时出错。例如,如果设备报告
BTN_TOUCH
按键代码,系统会假设BTN_TOUCH
将始终用于指示工具是否触摸到屏幕。因此,不应使用BTN_TOUCH
来指示工具只是在感应范围内悬停。 - 单点触控设备使用以下 Linux 输入事件:
ABS_X
:(必需)报告工具的 X 坐标。ABS_Y
:(必需)报告工具的 Y 坐标。ABS_PRESSURE
:(可选)报告应用于工具尖端的物理压力或触摸接触面的信号强度。ABS_TOOL_WIDTH
:(可选)报告触摸接触面或工具本身的横截面积或宽度。ABS_DISTANCE
:(可选)报告工具与触摸设备表面之间的距离。ABS_TILT_X
:(可选)报告工具沿触摸设备表面 X 轴方向的倾斜度。ABS_TILT_Y
:(可选)报告工具沿触摸设备表面 Y 轴方向的倾斜度。BTN_TOUCH
:(必需)指示工具是否触摸到设备。BTN_LEFT
、BTN_RIGHT
、BTN_MIDDLE
、BTN_BACK
、BTN_SIDE
、BTN_FORWARD
、BTN_EXTRA
、BTN_STYLUS
、BTN_STYLUS2
:(可选)报告按钮状态。BTN_TOOL_FINGER
、BTN_TOOL_PEN
、BTN_TOOL_RUBBER
、BTN_TOOL_BRUSH
、BTN_TOOL_PENCIL
、BTN_TOOL_AIRBRUSH
、BTN_TOOL_MOUSE
、BTN_TOOL_LENS
、BTN_TOOL_DOUBLETAP
、BTN_TOOL_TRIPLETAP
、BTN_TOOL_QUADTAP
:(可选)报告工具类型。
- 多点触控设备使用以下 Linux 输入事件:
ABS_MT_POSITION_X
:(必需)报告工具的 X 坐标。ABS_MT_POSITION_Y
:(必需)报告工具的 Y 坐标。ABS_MT_PRESSURE
:(可选)报告应用于工具尖端的物理压力或触摸接触面的信号强度。ABS_MT_TOUCH_MAJOR
:(可选)报告触摸接触面的横截面积或触摸接触面较长尺寸的长度。ABS_MT_TOUCH_MINOR
:(可选)报告触摸区域较短尺寸的长度。如果ABS_MT_TOUCH_MAJOR
报告区域测量,不应使用此轴。ABS_MT_WIDTH_MAJOR
:(可选)报告工具本身的横截面积或工具本身较长方向的长度。除非您了解工具本身的尺寸,否则请勿使用此轴。ABS_MT_WIDTH_MINOR
:(可选)报告工具本身较短尺寸的长度。如果ABS_MT_WIDTH_MAJOR
报告区域测量尺寸,或者如果工具本身的尺寸未知,则不应使用此轴。ABS_MT_ORIENTATION
:(可选)报告工具的方向。ABS_MT_DISTANCE
:(可选)报告工具与触摸设备表面之间的距离。ABS_MT_TOOL_TYPE
:(可选)将工具类型报告为MT_TOOL_FINGER
或MT_TOOL_PEN
。ABS_MT_TRACKING_ID
:(可选)报告工具的跟踪 ID。跟踪 ID 是一个任意的非负整数。当多个工具同时处于活动状态时,可以使用该 ID 独立识别和跟踪各个工具。例如,当多个手指同时触摸设备时,应为每个手指分配一个不同的跟踪 ID,用于在手指触摸设备期间识别手指。跟踪 ID 可在其关联的工具移出感应范围后重复使用。ABS_MT_SLOT
:(可选)在使用 Linux 多点触控协议“B”时,报告工具的槽位 ID。有关详情,请参阅 Linux 多点触控协议文档。BTN_TOUCH
:(必需)指示工具是否触摸到设备。BTN_LEFT
、BTN_RIGHT
、BTN_MIDDLE
、BTN_BACK
、BTN_SIDE
、BTN_FORWARD
、BTN_EXTRA
、BTN_STYLUS
、BTN_STYLUS2
:(可选)报告按钮状态。BTN_TOOL_FINGER
、BTN_TOOL_PEN
、BTN_TOOL_RUBBER
、BTN_TOOL_BRUSH
、BTN_TOOL_PENCIL
、BTN_TOOL_AIRBRUSH
、BTN_TOOL_MOUSE
、BTN_TOOL_LENS
、BTN_TOOL_DOUBLETAP
、BTN_TOOL_TRIPLETAP
、BTN_TOOL_QUADTAP
:(可选)报告工具类型。
- 如果同时针对单点触控协议和多点触控协议定义了轴,则仅会使用多点触控轴,并忽略单点触控轴。
ABS_X
、ABS_Y
、ABS_MT_POSITION_X
和ABS_MT_POSITION_Y
轴的最小值和最大值用于指定设备有效区域的范围,采用适用于具体设备的 surface 单位。如果是触摸屏,有效区域是指触摸设备实际覆盖显示屏的部分。对于触摸屏,系统会自动插入报告的触摸位置(采用 surface 单位),以通过以下公式计算得出以显示像素表示的触摸位置:
displayX = (x - minX) * displayWidth / (maxX - minX + 1) displayY = (y - minY) * displayHeight / (maxY - minY + 1)
触摸屏可能会报告在报告的有效区域之外发起的触摸。
在有效区域之外发起的触摸不会传递给应用,但可用于虚拟按键。
在有效区域内发起的触摸或进入和退出显示区域的触摸会传递给应用。因此,如果触摸是在应用的范围内开始,然后移动到有效区域之外,那么应用可能会收到显示坐标为负或超出显示范围的触摸事件。这属于正常现象。
触摸设备不得限制有效区域的触摸坐标边界。如果触摸离开有效区域,则应将其报告为超出有效区域,或者根本不应报告。
例如,如果用户的手指在触摸屏左上角附近触摸,可能会报告 (minX, minY) 坐标。如果手指继续移动到有效区域之外,触摸屏应该开始报告分量小于 minX 和 minY 的坐标(如 (minX - 2, minY - 3)),或者完全停止报告触摸。换而言之,当用户的手指确实触摸到有效区域之外时,触摸屏不应该报告 (minX, minY)。
如果将触摸坐标限制为不超过显示屏边缘,会导致屏幕边缘周围形成人为硬边界,从而使系统无法顺畅地跟踪进入或离开显示区域边界的动作。
ABS_PRESSURE
或ABS_MT_PRESSURE
报告的值(如果有报告)在工具触摸设备时必须为非零值;否则就为零,表示该工具处于悬停状态。可以选择性报告压力信息,但强烈建议报告。 应用可以使用压力信息实现压敏绘图等效果。
ABS_TOOL_WIDTH
、ABS_MT_TOUCH_MAJOR
、ABS_MT_TOUCH_MINOR
、ABS_MT_WIDTH_MAJOR
或ABS_MT_WIDTH_MINOR
报告的值在工具触摸设备时应为非零值;否则就为零,但这不是必需的。例如,触摸设备可能能够测量手指触摸接触面的尺寸,但不能测量触控笔触摸接触面的尺寸。可以选择性报告大小信息,但强烈建议报告。 应用可以使用压力信息来实现尺寸敏感绘图等效果。
在工具触摸设备时,
ABS_DISTANCE
或ABS_MT_DISTANCE
报告的值应接近零。即使当工具处于直接接触时,距离仍可能为非零。报告的确切值取决于硬件测量距离的方式。可以自行选择是否报告距离信息,但对于触控笔设备,建议报告该信息。
当工具垂直于设备时,
ABS_TILT_X
和ABS_TILT_Y
报告的值应为零。倾斜度非零表示工具保持在倾斜处。假定沿 X 轴和 Y 轴的倾斜角度以与垂直方向的夹角计。中心点(完全垂直)由
(max + min) / 2
针对每个轴指定。小于中心点的值表示向上或向左倾斜,大于中心点的值表示向下或向右倾斜。InputReader
将 X 和 Y 倾斜分量转换成从 0 到PI / 2
弧度的垂直倾斜角以及从-PI
到PI
弧度的平面定向角。该表示法将产生与描述手指触摸所用方向相符的方向描述。可以自行选择是否报告倾斜信息,但对于触控笔设备,建议报告该信息。
如果工具类型是由
ABS_MT_TOOL_TYPE
报告的,它会取代BTN_TOOL_*
报告的任何工具类型信息。如果没有任何工具类型信息,工具类型将默认为MotionEvent.TOOL_TYPE_FINGER
。根据以下条件确定工具的活动状态:
当使用单点触控协议时,如果
BTN_TOUCH
或BTN_TOOL_*
为 1,表示工具处于活动状态。这个条件意味着
InputReader
至少需要获得一些关于工具性质的信息:工具是否正在触摸屏幕,或者至少获取工具的类型。如果没有可用的信息,它会假定工具处于非活动状态(超出范围)。- 当使用多点触控协议“A”时,只要工具出现在最近的同步报告中,则表示其处于活动状态。当工具不再出现在同步报告中时,则表示工具已不再处于活动状态。
- 当使用多点触控协议“B”时,只要工具具有活动槽位,则表示其处于活动状态。当插槽被清除时,则表示工具不再存在。
- 根据以下条件确定工具悬停:
- 如果工具为
BTN_TOOL_MOUSE
或BTN_TOOL_LENS
,则工具不会悬停,即使以下任一条件为 true 也不例外。 - 如果工具处于活动状态,并且驱动程序报告的压力为零,则表示工具处于悬停状态。
- 如果工具处于活动状态,驱动程序支持
BTN_TOUCH
按键代码,并且BTN_TOUCH
的值为零,则表示工具处于悬停状态。
- 如果工具为
InputReader
支持多点触控协议“A”和“B”。新驱动程序应该使用“B”协议,但是使用任一协议均可正常运作。从 Android 4.0 开始,为遵循 Linux 输入协议规范,可能需要更改触摸屏驱动程序。
可能需要进行以下更改:
当一个工具变为非活动状态(手指“抬起”)时,它应该停止显示在后续的多点触控同步报告中。当所有工具变为非活动状态(“抬起”所有手指)时,驱动程序应发送一个空的同步报告数据包,如
SYN_MT_REPORT
后跟SYN_REPORT
。以前版本的 Android 通过发送压力值 0 来报告“抬起”事件。这种旧行为不符合 Linux 输入协议规范,因此不再受支持。
物理压力或信号强度信息应使用
ABS_MT_PRESSURE
进行报告。以前版本的 Android 从
ABS_MT_TOUCH_MAJOR
检索压力信息。这种旧行为不符合 Linux 输入协议规范,因此不再受支持。- 触摸尺寸信息应使用
ABS_MT_TOUCH_MAJOR
进行报告。以前版本的 Android 从
ABS_MT_TOOL_MAJOR
检索尺寸信息。这种旧行为不符合 Linux 输入协议规范,因此不再受支持。
触摸设备操作
下面简要汇总了 Android 上的触摸设备操作。
EventHub
从evdev
驱动程序读取原始事件。InputReader
会使用原始事件,并更新关于每个工具的位置和其他特征的内部状态。它还会跟踪按钮状态。- 如果按下或释放后退或前进,
InputReader
会向InputDispatcher
发出按键事件通知。 InputReader
确定是否发生了虚拟按键的按压操作。如果是,它会向InputDispatcher
发出按键事件通知。InputReader
确定触摸行为是否是在显示范围内发起的。如果是,它会向InputDispatcher
发出触摸事件通知。- 如果没有触摸工具,但至少有一个悬停工具,那么
InputReader
会向InputDispatcher
发出悬停事件通知。 - 如果触摸设备类型是指控设备,
InputReader
会执行指控手势检测,相应地移动指针和相关点,并向InputDispatcher
发出指针事件通知。 InputDispatcher
会根据WindowManagerPolicy
确定是否应分派这些事件,以及它们是否应唤醒设备。然后,InputDispatcher
会将事件传递给相应的应用。
触摸设备配置
触摸设备行为由设备的坐标轴、按钮、输入属性、输入设备配置、虚拟按键映射和按键布局确定。
如需详细了解参与键盘配置的文件,请参阅以下部分:
属性
系统依赖于许多输入设备配置属性来配置和校准触摸设备行为。
原因之一是触摸设备的设备驱动程序通常使用特定于设备的单元来报告触摸特性。
例如,许多触摸设备使用内部特定于设备的比例(例如由触摸触发的传感器节点的总数)来测量触摸接触面积。此原始尺寸值对应用来说没有意义,因为它们需要了解触摸设备传感器节点的物理尺寸和其他特性。
系统会使用在输入设备配置文件中编码的校准参数将触摸设备报告的值解码、转换,并标准化为应用可以理解的更简单的标准表示形式。
文档规范
对本文档而言,我们将使用以下规范来描述系统在校准过程中使用的值。
原始轴值
以下表达式表示触摸设备驱动程序作为 EV_ABS
事件报告的原始值。
raw.x
ABS_X
或ABS_MT_POSITION_X
轴的值。raw.y
ABS_Y
或ABS_MT_POSITION_Y
轴的值。raw.pressure
ABS_PRESSURE
或ABS_MT_PRESSURE
轴的值,如果未提供,则为 0。raw.touchMajor
ABS_MT_TOUCH_MAJOR
轴的值,如果未提供,则为 0。raw.touchMinor
ABS_MT_TOUCH_MINOR
轴的值,如果未提供,则为raw.touchMajor
。raw.toolMajor
ABS_TOOL_WIDTH
或ABS_MT_WIDTH_MAJOR
轴的值,如果未提供,则为 0。raw.toolMinor
ABS_MT_WIDTH_MINOR
轴的值,如果未提供,则为raw.toolMajor
。raw.orientation
ABS_MT_ORIENTATION
轴的值,如果未提供,则为 0。raw.distance
ABS_DISTANCE
或ABS_MT_DISTANCE
轴的值,如果未提供,则为 0。raw.tiltX
ABS_TILT_X
轴的值,如果未提供,则为 0。raw.tiltY
ABS_TILT_Y
轴的值,如果未提供,则为 0。
原始轴范围
以下表达式表示原始值的范围。通过为每个轴调用 EVIOCGABS
ioctl 获取它们。
raw.*.min
- 原始轴的最小值(含)。
raw.*.max
- 原始轴的最大值(含)。
raw.*.range
- 相当于
raw.*.max - raw.*.min
。 raw.*.fuzz
- 原始轴的精度。例如,fuzz = 1 表示值精确到 +/- 1 个单位。
raw.width
- 触摸区域的宽度(含),相当于
raw.x.range + 1
。 raw.height
- 触摸区域的高度(含),相当于
raw.y.range + 1
。
输出范围
以下表达式表示输出坐标系的特性。系统使用线性插值将触摸设备使用的 Surface 单元的触摸位置信息转换成将报告给应用的输出单元(如显示像素)。
output.width
- 输出宽度。对于触摸屏(与显示屏相关联),输出宽度是显示屏宽度(以像素为单位)。对于触摸板(不与显示屏相关联),输出宽度等于
raw.width
,表示不会执行任何插值。 output.height
- 输出高度。对于触摸屏(与显示屏相关联),输出高度是显示屏高度(以像素为单位)。对于触摸板(不与显示屏相关联),输出高度等于
raw.height
,表示不会执行任何插值。 output.diag
- 输出坐标系的对角线长度,相当于
sqrt(output.width ^2 + output.height ^2)
。
基本配置
触摸输入映射器在输入设备配置文件中使用许多配置属性来指定校准值。下表介绍了一些通用配置属性。下面的部分中介绍了所有其他属性以及使用这些属性进行校准时所用的字段。
touch.deviceType
定义:touch.deviceType
= touchScreen
|
touchPad
| pointer
| default
指定触摸设备类型。
-
如果值为
touchScreen
,那么触摸设备是与显示屏相关联的触摸屏。 -
如果值为
touchPad
,那么触摸设备是不与显示屏相关联的触摸板。 -
如果值为
pointer
,那么触摸设备是不与显示屏相关联的触摸板,并且其动作用于间接多点触控指控手势。 -
如果值为
default
,系统将根据分类算法自动检测设备类型。
有关设备类型如何影响触摸设备的行为的详细信息,请参阅分类部分。
在 Android 3 及更低版本中,所有触摸设备都被视为触摸屏。
touch.orientationAware
定义:touch.orientationAware
= 0
| 1
指定触摸设备是否应对显示屏的方向更改做出响应。
-
如果值为
1
,只要显示屏的方向更改了,触摸设备报告的触摸位置就会旋转。 -
如果值为
0
,触摸设备报告的触摸位置将不受显示屏方向更改的影响。
如果设备是触摸屏,默认值为 1
,否则为 0
。
系统会区分内部和外部触摸屏与显示部分。方向感知型内部触摸屏基于内部显示部分的方向进行旋转。方向感知型外部触摸屏基于外部显示部分的方向进行旋转。
方向感知功能用于支持 Nexus One 等设备上的触摸屏旋转。例如,当设备从其自然方向顺时针旋转 90 度时,触摸的绝对位置将被重新映射,使得在触摸屏绝对坐标系左上角的触摸行为被报告为在显示屏旋转后坐标系左上角的触摸行为。这样做是为了使用应用绘制其可见元素时所用的同一坐标系报告触摸行为。
在 Honeycomb 之前,所有触摸设备都被视为具有方向感知功能。
touch.gestureMode
定义:touch.gestureMode
= pointer
| spots
|
default
指定指控手势的表示模式。仅在触摸设备为指控类型时,该配置属性才具有相关性。
-
如果值为
pointer
,触摸板手势将通过与鼠标指针类似的光标来表示。 -
如果值为
spots
,触摸板手势将通过代表手势形心的锚点和代表各个手指位置的一组圆形斑点来表示。
如果设置了 INPUT_PROP_SEMI_MT
输入属性,默认值为 pointer
,否则为 spots
。
X 和 Y 字段
X 和 Y 字段给出了接触区域中心的位置信息。
计算
计算非常简单:以线性方式将触摸驱动程序的位置信息插入输出坐标系。
xScale = output.width / raw.width yScale = output.height / raw.height If not orientation aware or screen rotation is 0 degrees: output.x = (raw.x - raw.x.min) * xScale output.y = (raw.y - raw.y.min) * yScale Else If rotation is 90 degrees: output.x = (raw.y - raw.y.min) * yScale output.y = (raw.x.max - raw.x) * xScale Else If rotation is 180 degrees: output.x = (raw.x.max - raw.x) * xScale output.y = (raw.y.max - raw.y) * yScale Else If rotation is 270 degrees: output.x = (raw.y.max - raw.y) * yScale output.y = (raw.x - raw.x.min) * xScale End If
touchMajor、touchMinor、toolMajor、toolMinor、size 字段
touchMajor
和 touchMinor
字段用于描述接触面的大致尺寸,采用输出单位(像素)。
toolMajor
和 toolMinor
字段用于描述工具本身的大致尺寸,采用输出单位(像素)。
size
字段描述了相对于触摸设备可以感知的最大可能触摸区域的标准化触摸区域尺寸。可能的最小标准化尺寸为 0.0(无接触或不可测量),可能的最大标准化尺寸为 1.0(传感器区域已经完全覆盖)。
如果可以同时测量近似长度和宽度,touchMajor
字段会指定接触区域的较长尺寸,touchMinor
字段会指定接触区域的较短尺寸。如果只能测量接触区域的大致直径,touchMajor
和 touchMinor
字段相等。
同样,toolMajor
字段用于指定工具横截面较长方向的尺寸,toolMinor
字段用于指定工具横截面较短方向的尺寸。
如果触摸尺寸不可测量,但工具尺寸可测量,那么工具尺寸将设为等于触摸尺寸。相反,如果工具尺寸不可测量,但触摸尺寸可测量,那么触摸尺寸将设为等于工具尺寸。
触摸设备以多种方式测量或报告触摸尺寸和工具尺寸。目前的实现支持三种不同的测量尺寸:直径、面积以及采用 surface 单位表示的几何边界框。
定义:touch.size.calibration
= none
|
geometric
| diameter
| area
| default
指定触摸驱动程序报告触摸尺寸和工具尺寸时所用的测量类型。
-
如果值为
none
,那么尺寸设为零。 -
如果值为
geometric
,那么假定以与位置相同的 Surface 单元指定尺寸,从而以相同的方式对尺寸进行缩放。 -
如果值为
diameter
,那么假定尺寸与触摸或工具直径(宽度)成比例。 -
如果值为
area
,那么假定尺寸与触摸或工具面积成比例。 -
如果值为
default
,那么在raw.touchMajor
或raw.toolMajor
轴可用的情况下,系统将使用geometric
校准,否则使用none
校准。
touch.size.scale
定义:touch.size.scale
= <非负浮点数>
指定进行校准时使用的恒定缩放比例。
默认值为 1.0
。
touch.size.bias
定义:touch.size.bias
= <非负浮点数>
指定校准中使用的恒定偏差值。
默认值为 0.0
。
touch.size.isSummed
定义:touch.size.isSummed
= 0
| 1
指定尺寸是报告为所有有效接触区域的尺寸总和,还是针对每个接触区域单独报告尺寸。
-
如果值为
1
,报告的尺寸需除以接触区域数量,然后才能使用。 -
如果值为
0
,则报告的尺寸将按原样使用。
默认值为 0
。
一些触摸设备(尤其是“Semi-MT”设备)无法区分多个接触面的单独尺寸,因此它们会报告表示总面积或总宽度的尺寸测量结果。对于此类设备,此属性只能设为 1
。如果不确定,请将此值设为 0
。
计算
touchMajor
、touchMinor
、toolMajor
、toolMinor
和 size
字段的计算方法取决于指定的校准参数。
If raw.touchMajor and raw.toolMajor are available: touchMajor = raw.touchMajor touchMinor = raw.touchMinor toolMajor = raw.toolMajor toolMinor = raw.toolMinor Else If raw.touchMajor is available: toolMajor = touchMajor = raw.touchMajor toolMinor = touchMinor = raw.touchMinor Else If raw.toolMajor is available: touchMajor = toolMajor = raw.toolMajor touchMinor = toolMinor = raw.toolMinor Else touchMajor = toolMajor = 0 touchMinor = toolMinor = 0 size = 0 End If size = avg(touchMajor, touchMinor) If touch.size.isSummed == 1: touchMajor = touchMajor / numberOfActiveContacts touchMinor = touchMinor / numberOfActiveContacts toolMajor = toolMajor / numberOfActiveContacts toolMinor = toolMinor / numberOfActiveContacts size = size / numberOfActiveContacts End If If touch.size.calibration == "none": touchMajor = toolMajor = 0 touchMinor = toolMinor = 0 size = 0 Else If touch.size.calibration == "geometric": outputScale = average(output.width / raw.width, output.height / raw.height) touchMajor = touchMajor * outputScale touchMinor = touchMinor * outputScale toolMajor = toolMajor * outputScale toolMinor = toolMinor * outputScale Else If touch.size.calibration == "area": touchMajor = sqrt(touchMajor) touchMinor = touchMajor toolMajor = sqrt(toolMajor) toolMinor = toolMajor Else If touch.size.calibration == "diameter": touchMinor = touchMajor toolMinor = toolMajor End If If touchMajor != 0: output.touchMajor = touchMajor * touch.size.scale + touch.size.bias Else output.touchMajor = 0 End If If touchMinor != 0: output.touchMinor = touchMinor * touch.size.scale + touch.size.bias Else output.touchMinor = 0 End If If toolMajor != 0: output.toolMajor = toolMajor * touch.size.scale + touch.size.bias Else output.toolMajor = 0 End If If toolMinor != 0: output.toolMinor = toolMinor * touch.size.scale + touch.size.bias Else output.toolMinor = 0 End If output.size = size
pressure 字段
pressure
字段用于描述施加到触摸设备的大概物理压力,以介于 0.0(无接触)和 1.0(正常压力)之间的标准化值形式表示。
零压力表示工具处于悬停状态。
touch.pressure.calibration
定义:touch.pressure.calibration
= none
|
physical
| amplitude
| default
指定触摸驱动程序报告压力所用的测量类型。
-
如果值为
none
,压力未知,那么在触摸时设置为 1.0,悬停时设置为 0.0。 -
如果值为
physical
,那么认为压力轴测量的是施加到触摸板的压力的实际物理强度。 -
如果值为
amplitude
,那么认为压力轴测量的是信号幅度(与接触面的大小和施加的压力有关)。 -
如果值为
default
,在压力轴可用的情况下,系统将使用physical
校准,否则使用none
。
touch.pressure.scale
定义:touch.pressure.scale
= <非负浮点数>
指定进行校准时使用的恒定缩放比例。
默认值为 1.0 / raw.pressure.max
。
计算
pressure
字段的计算方法取决于指定的校准参数。
If touch.pressure.calibration == "physical" or "amplitude": output.pressure = raw.pressure * touch.pressure.scale Else If hovering: output.pressure = 0 Else output.pressure = 1 End If End If
orientation 和 tilt 字段
orientation
字段以角度测量的形式描述触摸和工具的方向。值为 0
表示长轴为垂直方向,-PI/2
表示长轴朝向左方,PI/2
表示长轴朝向右方。当存在触控笔工具时,方向范围可以是从 -PI
到 PI
的整个圆环范围。
tilt
字段通过测量角度描述工具的倾斜度。倾斜度为 0
表示工具垂直于表面。倾斜度为 PI/2
表示工具与表面平行。
touch.orientation.calibration
定义:touch.orientation.calibration
= none
|
interpolated
| vector
| default
指定触摸驱动程序报告方向时所用的测量类型。
- 如果值为
none
,方向未知,则设为 0。 - 如果值为
interpolated
,方向会被线性插入,使得raw.orientation.min
的原始值映射到-PI/2
,raw.orientation.max
的原始值映射到PI/2
。(raw.orientation.min + raw.orientation.max) / 2
的中心值映射到0
。 - 如果值为
vector
,则方向表示为包含两个带符号的 4 位字段的压缩向量。该表示法用于 Atmel 基于对象的协议部分。当解码时,向量生成定向角和置信度。置信度用于缩放尺寸信息,除非它是几何图形。 - 如果值为
default
,那么在方向轴可用的情况下,系统将使用interpolated
校准,否则使用none
。
计算
orientation
和 tilt
字段的计算方法取决于指定的校准参数和可用输入。
If touch.tiltX and touch.tiltY are available: tiltXCenter = average(raw.tiltX.min, raw.tiltX.max) tiltYCenter = average(raw.tiltY.min, raw.tiltY.max) tiltXAngle = (raw.tiltX - tiltXCenter) * PI / 180 tiltYAngle = (raw.tiltY - tiltYCenter) * PI / 180 output.orientation = atan2(-sin(tiltXAngle), sinf(tiltYAngle)) output.tilt = acos(cos(tiltXAngle) * cos(tiltYAngle)) Else If touch.orientation.calibration == "interpolated": center = average(raw.orientation.min, raw.orientation.max) output.orientation = PI / (raw.orientation.max - raw.orientation.min) output.tilt = 0 Else If touch.orientation.calibration == "vector": c1 = (raw.orientation & 0xF0) >> 4 c2 = raw.orientation & 0x0F If c1 != 0 or c2 != 0: If c1 >= 8 Then c1 = c1 - 16 If c2 >= 8 Then c2 = c2 - 16 angle = atan2(c1, c2) / 2 confidence = sqrt(c1*c1 + c2*c2) output.orientation = angle If touch.size.calibration == "diameter" or "area": scale = 1.0 + confidence / 16 output.touchMajor *= scale output.touchMinor /= scale output.toolMajor *= scale output.toolMinor /= scale End If Else output.orientation = 0 End If output.tilt = 0 Else output.orientation = 0 output.tilt = 0 End If If orientation aware: If screen rotation is 90 degrees: output.orientation = output.orientation - PI / 2 Else If screen rotation is 270 degrees: output.orientation = output.orientation + PI / 2 End If End If
distance 字段
distance
字段描述了工具和触摸设备表面之间的距离。值为 0.0 表示直接接触,值越大,表示与表面之间的距离越远。
touch.distance.calibration
定义:touch.distance.calibration
= none
|
scaled
| default
指定触摸驱动程序报告距离时所用的测量类型。
-
如果值为
none
,距离未知,则设为 0。 -
如果值为
scaled
,报告的距离将乘以恒定缩放比例。 -
如果值为
default
,在距离轴可用的情况下,系统将使用scaled
校准,否则使用none
。
touch.distance.scale
定义:touch.distance.scale
= <非负浮点数>
指定进行校准时使用的恒定缩放比例。
默认值为 1.0
。
计算
distance
字段的计算方法取决于指定的校准参数。
If touch.distance.calibration == "scaled": output.distance = raw.distance * touch.distance.scale Else output.distance = 0 End If
示例
# Input device configuration file for a touch screen that supports pressure, # size and orientation. The pressure and size scale factors were obtained # by measuring the characteristics of the device itself and deriving # useful approximations based on the resolution of the touch sensor and the # display. # # Note that these parameters are specific to a particular device model. # Different parameters need to be used for other devices. # Basic Parameters touch.deviceType = touchScreen touch.orientationAware = 1 # Size # Based on empirical measurements, we estimate the size of the contact # using size = sqrt(area) * 28 + 0. touch.size.calibration = area touch.size.scale = 28 touch.size.bias = 0 touch.size.isSummed = 0 # Pressure # Driver reports signal strength as pressure. # # A normal index finger touch typically registers about 80 signal strength # units although we don't expect these values to be accurate. touch.pressure.calibration = amplitude touch.pressure.scale = 0.0125 # Orientation touch.orientation.calibration = vector
兼容性说明
触摸设备的配置属性在 Android Ice Cream Sandwich 4.0 中发生了重大变化。必须更新触摸设备的所有输入设备配置文件,才能使用新的配置属性。
更旧的触摸设备驱动程序可能也需要更新。
虚拟按键映射文件
触摸设备可用于实现虚拟按键。
有几种方法可以做到这一点,具体取决于触摸控制器的功能。一些触摸控制器可以直接配置为通过设置固件寄存器来实现软键。其他时候,最好在软件中执行从触摸坐标到按键代码的映射。
在软件中实现虚拟按键时,内核必须将名为 virtualkeys.<devicename>
的虚拟按键映射文件作为本机已加载属性导出。例如,如果触摸屏设备驱动程序将其名称报告为“touchyfeely”,虚拟按键映射文件的路径必须为 /sys/board_properties/virtualkeys.touchyfeely
。
虚拟按键映射文件描述了触摸屏上虚拟按键的坐标和 Linux 按键代码。
除了虚拟按键映射文件外,还必须有一个对应的按键布局文件和按键字符映射文件,以将 Linux 按键代码映射到 Android 按键代码,并指定键盘设备的类型(通常为 SPECIAL_FUNCTION
)。
语法
虚拟按键映射文件是一个纯文本文件,由一系列用换行符或冒号分隔的虚拟按键布局描述组成。
注释行以“#”开头,并持续到这一行的结束位置。
每个虚拟按键用由 6 个冒号分隔的组件进行描述:
0x01
:版本代码。必须始终为0x01
。- <Linux key code>:虚拟按键的 Linux 按键代码。
- <centerX>:虚拟按键中心的 X 轴坐标(以像素为单位)。
- <centerY>:虚拟按键中心的 Y 轴坐标(以像素为单位)。
- <width>:虚拟按键的宽度(以像素为单位)。
- <height>:虚拟按键的高度(以像素为单位)。
所有的坐标和尺寸都是根据显示坐标系指定的。
下面是一个虚拟按键映射文件,全部写在一行上。
# All on one line 0x01:158:55:835:90:55:0x01:139:172:835:125:55:0x01:102:298:835:115:55:0x01:217:412:835:95:55
相同的虚拟按键映射文件也可以写在多行上。
# One key per line 0x01:158:55:835:90:55 0x01:139:172:835:125:55 0x01:102:298:835:115:55 0x01:217:412:835:95:55
在上述示例中,触摸屏具有 480×800 的分辨率。因此,所有虚拟按键的 <centerY> 坐标均为 835,位于略低于触摸屏可见区域的位置。
第一个按键的 Linux 扫描代码为 158
(KEY_BACK
),centerX 为 55
,centerY 为 835
,width 为 90
,height 为 55
。
示例
虚拟按键映射文件:/sys/board_properties/virtualkeys.touchyfeely
。
0x01:158:55:835:90:55 0x01:139:172:835:125:55 0x01:102:298:835:115:55 0x01:217:412:835:95:55
按键布局文件:/system/usr/keylayout/touchyfeely.kl
。
key 158 BACK key 139 MENU key 172 HOME key 217 SEARCH
按键字符映射文件:/system/usr/keychars/touchyfeely.kcm
。
type SPECIAL_FUNCTION
间接多点触控指控手势
在指控模式下,系统会解释以下手势:
- 单指点按:点击。
- 单指移动:移动指针。
- 单指移动加按下按钮:拖动指针。
- 两个手指移动(两个手指沿相同的方向移动):沿着该方向拖动指针下方的区域。指针本身不动。
- 两个手指移动(两个手指朝着彼此移动或者移向不同方向):平移/缩放/旋转指针周围的区域。指针本身不动。
- 多个手指移动:自由手势。
防止手掌误触
从 Android 13 开始,系统可以在内置框架启用时自动拒绝来自手掌的输入。内部构建的自定义解决方案仍受支持,但可能需要进行修改,以便在检测到手掌时返回 TOOL_TYPE_PALM
标志。内置框架还可与自定义解决方案搭配使用。
实际模型会查看当前指针和周围指针处前 90 毫秒的手势数据,然后考虑触摸与屏幕边缘之间的距离。然后,它会基于每个指控设备确定哪些指控设备是手掌。它还会考虑每个接触面的大小(如 touchMajor
和 touchMinor
所报告)。然后,Android 框架会从触摸流中移除标记为手掌的指针。
如果指针已经发送到应用,系统会执行以下操作之一:
- (如果有其他处于活动状态的指针)使用
ACTION_POINTER_UP
和FLAG_CANCELED
组合取消该指针。 - (如果这是唯一的指针)使用
ACTION_CANCEL
取消该指针。
公共 API MotionEvent.FLAG_CANCELED
表示当前事件不应触发用户操作。此标志针对 ACTION_CANCEL
和 ACTION_POINTER_UP
设置。
如果手掌指针没有发送到应用,系统会直接丢弃该指针。
启用防手掌误触功能
- 在触摸驱动程序中,使用
input_abs_set_res
宏设置下列字段的分辨率(单位为每毫米像素数):ABS_MT_POSITION_X
ABS_MT_POSITION_Y
ABS_MT_TOUCH_MAJOR
ABS_MT_TOUCH_MINOR
对
ABS_MT_TOUCH_MINOR
的支持是可选的。不过,如果您的设备支持它,请确保分辨率设置正确。 - 如需确认这些字段是否已正确设置,请运行以下命令:
$ adb shell getevent -li
- 如需在运行时启用此功能,请运行以下命令:
$ adb shell device_config put input_native_boot palm_rejection_enabled 1
- 重启
system_server
进程。$ adb shell stop && adb shell start
- 确认
adb shell dumpsys input
会显示UnwantedInteractionBlocker
中有防手掌误触工具。如果没有,请检查与输入相关的日志,以查找有关哪些方面配置可能有误的线索。请参考以下示例:
UnwantedInteractionBlocker: mEnablePalmRejection: true isPalmRejectionEnabled (flag value): true mPalmRejectors: deviceId = 3: mDeviceInfo: max_x =
max_y = x_res = 11.00 y_res = 11.00 major_radius_res = 1.00 minor_radius_res = 1.00 minor_radius_supported = true touch_major_res = 1 touch_minor_res = 1 mSlotState: mSlotsByPointerId: mPointerIdsBySlot: mSuppressedPointerIds: {} - 如需永久启用此功能,请在
init**rc
文件中添加相应的 sysprop 命令:setprop persist.device_config.input_native_boot.palm_rejection_enabled 1