Android 支持各种触摸屏和触摸板,包括基于手写笔的数字化仪平板电脑。
触摸屏是与显示屏关联的触摸设备,用户可以通过触摸屏直接操纵屏幕上的项目。
触摸板是不与显示屏关联的触摸设备,例如数字化仪平板电脑。触摸板通常用于指针操作,或用于绝对间接定位或基于手势的用户界面控制。
触摸设备可以有按钮,其功能类似于鼠标按钮。
有时,可以根据底层触摸传感器技术,使用各种不同的工具(例如手指或手写笔)来操作触摸设备。
触摸设备有时用于实现虚拟按键。例如,在某些 Android 设备上,触摸屏传感器区域会延伸到显示屏边缘之外,并兼作触摸感应键盘的一部分。
由于触摸设备种类繁多,Android 依赖于大量的配置属性来描述每个设备的特性和期望行为。
触摸设备分类
如果同时满足以下两个条件,则输入设备被归类为多点触控设备
- 输入设备报告存在
ABS_MT_POSITION_X
和ABS_MT_POSITION_Y
绝对轴。 - 输入设备没有任何游戏手柄按钮。此条件解决了某些游戏手柄的歧义,这些游戏手柄报告的轴代码与 MT 轴的代码重叠。
如果同时满足以下两个条件,则输入设备被归类为单点触控设备
- 输入设备未被归类为多点触控设备。输入设备要么被归类为单点触控设备,要么被归类为多点触控设备,绝不会两者都是。
- 输入设备报告存在
ABS_X
和ABS_Y
绝对轴,以及存在BTN_TOUCH
键代码。
当输入设备被归类为触摸设备时,虚拟按键的存在与否取决于是否尝试加载设备的虚拟按键映射文件。如果虚拟按键映射可用,则还会加载设备的按键布局文件。有关这些文件的位置和格式的信息,请参阅[虚拟按键映射文件](#virtual-key-map-files)。
接下来,系统会加载触摸设备的输入设备配置文件。
所有内置触摸设备都应具有输入设备配置文件。 如果没有输入设备配置文件,系统会选择适合通用触摸外围设备(例如外部 USB 或蓝牙 HID 触摸屏或触摸板)的默认配置。这些默认设置并非为内置触摸屏而设计,可能会导致行为不正确。
加载输入设备配置后,系统会将输入设备分类为触摸屏、触摸板或指针设备。
- 触摸屏设备用于直接操纵屏幕上的对象。用户直接触摸屏幕,因此系统不需要任何额外的提示来指示正在操纵的对象。
- 触摸板设备用于向应用提供有关给定传感器区域上触摸的绝对位置信息。它对于数字化仪平板电脑非常有用。
- 指针设备用于使用光标间接操纵屏幕上的对象。手指被解释为多点触控指针手势。其他工具(例如手写笔)则使用绝对位置进行解释。有关详情,请参阅[间接多点触控指针手势](#indirect-multi-touch-pointer-gestures)。
以下规则用于将输入设备分类为触摸屏、触摸板或指针设备。
- 如果设置了
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
。
悬停工具与触摸工具
工具可以与触摸设备接触,也可以在范围内悬停在其上方。并非所有触摸设备都能感应到悬停在触摸设备上方的工具的存在。那些可以感应到的设备(例如基于 RF 的手写笔数字化仪)通常可以检测到工具何时在数字化仪的有限范围内。
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
:(可选)报告[按钮](#buttons)状态。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
:(可选)报告[工具类型](#tools-and-tool-types)。
- 多点触控设备使用以下 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
形式报告[工具类型](#tools-and-tool-types)。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
:(可选)报告[按钮](#buttons)状态。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
:(可选)报告[工具类型](#tools-and-tool-types)。
- 如果同时定义了单点触控和多点触控协议的轴,则仅使用多点触控轴,而忽略单点触控轴。
ABS_X
、ABS_Y
、ABS_MT_POSITION_X
和ABS_MT_POSITION_Y
轴的最小值和最大值定义了设备特定表面单位的设备活动区域的边界。对于触摸屏,活动区域描述了实际覆盖显示屏的触摸设备部分。对于触摸屏,系统会自动插补表面单位中报告的触摸位置,以根据以下计算获得显示屏像素中的触摸位置
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
,则即使以下任一条件为真,该工具也不会悬停。 - 如果工具处于活动状态,并且驱动程序报告了压力信息,并且报告的压力为零,则工具正在悬停。
- 如果工具处于活动状态,并且驱动程序支持
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
。
输出范围
以下表达式表示输出坐标系的特性。系统使用线性插值将触摸位置信息从触摸设备使用的表面单位转换为报告给应用(例如显示屏像素)的输出单位。
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
,则触摸设备是不与显示屏关联的触摸板,并且其动作用于[间接多点触控指针手势](#indirect-multi-touch-pointer-gestures)。 -
如果值为
default
,则系统会根据分类算法自动检测设备类型。
有关设备类型如何影响触摸设备行为的更多详细信息,请参阅[分类](#touch-device-classification)部分。
在 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
字段描述了输出单位(像素)中[工具](#tools-and-tool-types)本身的大致尺寸。
size
字段描述了触摸相对于触摸设备可感应的最大可能触摸的归一化大小。最小可能的归一化大小为 0.0(无接触或不可测量),最大可能的归一化大小为 1.0(传感器区域饱和)。
当长度和宽度都可以大致测量时,touchMajor
字段指定接触区域的较长尺寸,touchMinor
字段指定接触区域的较短尺寸。当只能测量接触区域的大致直径时,touchMajor
和 touchMinor
字段相等。
同样,toolMajor
字段指定工具横截面积的较长尺寸,toolMinor
字段指定工具横截面积的较短尺寸。
如果触摸大小不可用但工具大小可用,则工具大小设置为等于触摸大小。相反,如果工具大小不可用但触摸大小可用,则触摸大小设置为等于工具大小。
触摸设备以各种方式测量或报告触摸大小和工具大小。当前的实现支持三种不同的测量类型:直径、面积和表面单位的几何边界框。
定义: touch.size.calibration
= none
| geometric
| diameter
| area
| default
指定触摸驱动程序用于报告触摸大小和工具大小的测量类型。
-
如果值为
none
,则大小设置为零。 -
如果值为
geometric
,则假定大小以与位置相同的表面单位指定,因此以相同的方式缩放。 -
如果值为
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 键码>:虚拟按键的 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
在上面的示例中,触摸屏的分辨率为 480x800。因此,所有虚拟按键的 <centerY> 坐标均为 835,这比触摸屏的可见区域略低。
第一个按键的 Linux 扫描代码为 158
(KEY_BACK
),centerX 为 55
,centerY 为 835
,宽度为 90
,高度为 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_POINTER_UP
取消指针。 - (如果这是唯一的指针)使用
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