触摸设备

Android 支持各种触摸屏和触摸板,包括基于手写笔的数字化仪平板电脑。

触摸屏是与显示屏关联的触摸设备,用户可以通过触摸屏直接操纵屏幕上的项目。

触摸板是不与显示屏关联的触摸设备,例如数字化仪平板电脑。触摸板通常用于指针操作,或用于绝对间接定位或基于手势的用户界面控制。

触摸设备可以有按钮,其功能类似于鼠标按钮。

有时,可以根据底层触摸传感器技术,使用各种不同的工具(例如手指或手写笔)来操作触摸设备。

触摸设备有时用于实现虚拟按键。例如,在某些 Android 设备上,触摸屏传感器区域会延伸到显示屏边缘之外,并兼作触摸感应键盘的一部分。

由于触摸设备种类繁多,Android 依赖于大量的配置属性来描述每个设备的特性和期望行为。

触摸设备分类

如果同时满足以下两个条件,则输入设备被归类为多点触控设备

  • 输入设备报告存在 ABS_MT_POSITION_XABS_MT_POSITION_Y 绝对轴。
  • 输入设备没有任何游戏手柄按钮。此条件解决了某些游戏手柄的歧义,这些游戏手柄报告的轴代码与 MT 轴的代码重叠。

如果同时满足以下两个条件,则输入设备被归类为单点触控设备

  • 输入设备未被归类为多点触控设备。输入设备要么被归类为单点触控设备,要么被归类为多点触控设备,绝不会两者都是。
  • 输入设备报告存在 ABS_XABS_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_XREL_Y 相对轴,则设备类型设置为触摸板。此条件解决了由鼠标和触摸板组成的输入设备的歧义。在这种情况下,触摸板不用于控制指针,因为鼠标已控制指针。
  • 否则,设备类型设置为指针。此默认设置可确保尚未指定任何其他特殊用途的触摸板控制指针。

按钮

按钮是可选控件,应用可以使用这些控件来执行其他功能。触摸设备上的按钮的行为与鼠标按钮类似,主要用于指针类型触摸设备或手写笔。

支持以下按钮

  • BTN_LEFT:映射到 MotionEvent.BUTTON_PRIMARY
  • BTN_RIGHT:映射到 MotionEvent.BUTTON_SECONDARY
  • BTN_MIDDLE:映射到 MotionEvent.BUTTON_MIDDLE
  • BTN_BACKBTN_SIDE:映射到 MotionEvent.BUTTON_BACK。按下此按钮还会合成一个键代码为 KeyEvent.KEYCODE_BACK 的按键。
  • BTN_FORWARDBTN_EXTRA:映射到 MotionEvent.BUTTON_FORWARD。按下此按钮还会合成一个键代码为 KeyEvent.KEYCODE_FORWARD 的按键。
  • BTN_STYLUS:映射到 MotionEvent.BUTTON_SECONDARY
  • BTN_STYLUS2:映射到 MotionEvent.BUTTON_TERTIARY

工具和工具类型

工具是指用于与触摸设备交互的手指、手写笔或其他设备。某些触摸设备可以区分不同类型的工具。

在 Android 的其他地方(例如 MotionEvent API 中),工具通常被称为指针

支持以下工具类型

  • BTN_TOOL_FINGERMT_TOOL_FINGER:映射到 MotionEvent.TOOL_TYPE_FINGER
  • BTN_TOOL_PENMT_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_DOUBLETAPBTN_TOOL_TRIPLETAPBTN_TOOL_QUADTAP:映射到 MotionEvent.TOOL_TYPE_FINGER

悬停工具与触摸工具

工具可以与触摸设备接触,也可以在范围内悬停在其上方。并非所有触摸设备都能感应到悬停在触摸设备上方的工具的存在。那些可以感应到的设备(例如基于 RF 的手写笔数字化仪)通常可以检测到工具何时在数字化仪的有限范围内。

InputReader 组件区分触摸工具和悬停工具。同样,触摸工具和悬停工具会以不同的方式报告给应用。

触摸工具作为触摸事件报告给应用,使用 MotionEvent.ACTION_DOWNMotionEvent.ACTION_MOVEMotionEvent.ACTION_DOWNMotionEvent.ACTION_POINTER_DOWNMotionEvent.ACTION_POINTER_UP

悬停工具作为通用动作事件报告给应用,使用 MotionEvent.ACTION_HOVER_ENTERMotionEvent.ACTION_HOVER_MOVEMotionEvent.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_LEFTBTN_RIGHTBTN_MIDDLEBTN_BACKBTN_SIDEBTN_FORWARDBTN_EXTRABTN_STYLUSBTN_STYLUS2(可选)报告[按钮](#buttons)状态。
    • BTN_TOOL_FINGERBTN_TOOL_PENBTN_TOOL_RUBBERBTN_TOOL_BRUSHBTN_TOOL_PENCILBTN_TOOL_AIRBRUSHBTN_TOOL_MOUSEBTN_TOOL_LENSBTN_TOOL_DOUBLETAPBTN_TOOL_TRIPLETAPBTN_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_FINGERMT_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_LEFTBTN_RIGHTBTN_MIDDLEBTN_BACKBTN_SIDEBTN_FORWARDBTN_EXTRABTN_STYLUSBTN_STYLUS2(可选)报告[按钮](#buttons)状态。
    • BTN_TOOL_FINGERBTN_TOOL_PENBTN_TOOL_RUBBERBTN_TOOL_BRUSHBTN_TOOL_PENCILBTN_TOOL_AIRBRUSHBTN_TOOL_MOUSEBTN_TOOL_LENSBTN_TOOL_DOUBLETAPBTN_TOOL_TRIPLETAPBTN_TOOL_QUADTAP(可选)报告[工具类型](#tools-and-tool-types)。
  • 如果同时定义了单点触控和多点触控协议的轴,则仅使用多点触控轴,而忽略单点触控轴。
  • ABS_XABS_YABS_MT_POSITION_XABS_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_PRESSUREABS_MT_PRESSURE 报告的值,则当工具触摸设备时,这些值必须为非零值,否则为零,以指示工具正在悬停。

    报告压力信息是可选的,但强烈建议这样做。应用可以使用压力信息来实现压感绘图和其他效果。

  • 当工具触摸设备时,ABS_TOOL_WIDTHABS_MT_TOUCH_MAJORABS_MT_TOUCH_MINORABS_MT_WIDTH_MAJORABS_MT_WIDTH_MINOR 报告的值应为非零值,否则为零,但这并非必需。例如,触摸设备可能能够测量手指触摸接触的大小,但不能测量手写笔触摸接触的大小。

    报告尺寸信息是可选的,但强烈建议这样做。应用可以使用压力信息来实现尺寸敏感绘图和其他效果。

  • 当工具触摸设备时,ABS_DISTANCEABS_MT_DISTANCE 报告的值应接近于零。即使工具直接接触,距离也可能保持非零值。报告的确切值取决于硬件测量距离的方式。

    对于手写笔设备,建议可选报告距离信息。

  • 当工具垂直于设备时,ABS_TILT_XABS_TILT_Y 报告的值应为零。非零倾斜度表示工具以一定倾角保持。

    沿 X 轴和 Y 轴的倾斜角假定以度为单位指定,从垂直方向算起。中心点(完全垂直)由每个轴的 (max + min) / 2 给出。小于中心点的值表示向上或向左倾斜,大于中心点的值表示向下或向右倾斜。

    InputReader 将 X 和 Y 倾斜分量转换为垂直倾斜角(范围为 0 到 PI / 2 弧度)和平面的方向角(范围为 -PIPI 弧度)。此表示形式生成的方向描述与用于描述手指触摸的方向描述兼容。

    对于手写笔设备,建议可选报告倾斜信息。

  • 如果工具类型由 ABS_MT_TOOL_TYPE 报告,则它将取代由 BTN_TOOL_* 报告的任何工具类型信息。如果根本没有工具类型信息可用,则工具类型默认为 MotionEvent.TOOL_TYPE_FINGER

  • 根据以下条件确定工具是否处于活动状态

    • 当使用单点触控协议时,如果 BTN_TOUCHBTN_TOOL_* 为 1,则工具处于活动状态。

      此条件意味着 InputReader 需要至少了解一些有关工具性质的信息,无论是工具是否正在触摸,还是至少其工具类型。如果没有信息可用,则假定工具处于非活动状态(超出范围)。

    • 当使用多点触控协议“A”时,只要工具出现在最新的同步报告中,该工具就处于活动状态。当工具停止出现在同步报告中时,它便会停止存在。
    • 当使用多点触控协议“B”时,只要工具具有活动插槽,该工具就处于活动状态。当插槽被清除时,该工具便会停止存在。
  • 根据以下条件确定工具是否正在悬停
    • 如果工具是 BTN_TOOL_MOUSEBTN_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 的自定义。通过依赖标准 Linux 输入协议,Android 可以使用未修改的驱动程序来支持更广泛的触摸外围设备,例如外部 HID 多点触控触摸屏。

触摸设备操作

以下是 Android 上触摸设备操作的简要概述。

  1. EventHubevdev 驱动程序读取原始事件。
  2. InputReader 使用原始事件并更新有关每个工具的位置和其他特性的内部状态。它还会跟踪按钮状态。
  3. 如果按下或释放了返回前进,则 InputReader 会将按键事件通知 InputDispatcher
  4. InputReader 确定是否发生了虚拟按键按下操作。如果发生,它会将按键事件通知 InputDispatcher
  5. InputReader 确定触摸是否在显示屏的边界内发起。如果是,它会将触摸事件通知 InputDispatcher
  6. 如果没有触摸工具,但至少有一个悬停工具,则 InputReader 会将悬停事件通知 InputDispatcher
  7. 如果触摸设备类型为指针,则 InputReader 执行指针手势检测,相应地移动指针和斑点,并将指针事件通知 InputDispatcher
  8. InputDispatcher 使用 WindowManagerPolicy 来确定是否应调度事件以及它们是否应唤醒设备。然后,InputDispatcher 将事件传递给相应的应用。

触摸设备配置

触摸设备行为由设备的轴、按钮、输入属性、输入设备配置、虚拟按键映射和按键布局决定。

有关参与键盘配置的文件的更多详细信息,请参阅以下部分

属性

系统依赖许多输入设备配置属性来配置和校准触摸设备行为。

其中一个原因是触摸设备的设备驱动程序通常使用设备特定的单位报告触摸的特性。

例如,许多触摸设备使用内部设备特定的比例来测量触摸接触面积,例如由触摸触发的传感器节点的总数。原始尺寸值对应用没有意义,因为它们需要了解触摸设备传感器节点的物理尺寸和其他特性。

系统使用在输入设备配置文件中编码的校准参数来解码、转换和标准化触摸设备报告的值,从而获得应用可以理解的更简单的标准表示形式。

文档约定

出于文档目的,我们使用以下约定来描述系统在校准过程中使用的值。

原始轴值

以下表达式表示触摸设备驱动程序报告为 EV_ABS 事件的原始值。

raw.x
ABS_XABS_MT_POSITION_X 轴的值。
raw.y
ABS_YABS_MT_POSITION_Y 轴的值。
raw.pressure
ABS_PRESSUREABS_MT_PRESSURE 轴的值;如果不可用,则为 0。
raw.touchMajor
ABS_MT_TOUCH_MAJOR 轴的值;如果不可用,则为 0。
raw.touchMinor
ABS_MT_TOUCH_MINOR 轴的值;如果不可用,则为 raw.touchMajor
raw.toolMajor
ABS_TOOL_WIDTHABS_MT_WIDTH_MAJOR 轴的值;如果不可用,则为 0。
raw.toolMinor
ABS_MT_WIDTH_MINOR 轴的值;如果不可用,则为 raw.toolMajor
raw.orientation
ABS_MT_ORIENTATION 轴的值;如果不可用,则为 0。
raw.distance
ABS_DISTANCEABS_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 字段

touchMajortouchMinor 字段描述了输出单位(像素)中接触区域的大致尺寸。

toolMajortoolMinor 字段描述了输出单位(像素)中[工具](#tools-and-tool-types)本身的大致尺寸。

size 字段描述了触摸相对于触摸设备可感应的最大可能触摸的归一化大小。最小可能的归一化大小为 0.0(无接触或不可测量),最大可能的归一化大小为 1.0(传感器区域饱和)。

当长度和宽度都可以大致测量时,touchMajor 字段指定接触区域的较长尺寸,touchMinor 字段指定接触区域的较短尺寸。当只能测量接触区域的大致直径时,touchMajortouchMinor 字段相等。

同样,toolMajor 字段指定工具横截面积的较长尺寸,toolMinor 字段指定工具横截面积的较短尺寸。

如果触摸大小不可用但工具大小可用,则工具大小设置为等于触摸大小。相反,如果工具大小不可用但触摸大小可用,则触摸大小设置为等于工具大小。

触摸设备以各种方式测量或报告触摸大小和工具大小。当前的实现支持三种不同的测量类型:直径、面积和表面单位的几何边界框。

定义: touch.size.calibration = none | geometric | diameter | area | default

指定触摸驱动程序用于报告触摸大小和工具大小的测量类型。

  • 如果值为 none,则大小设置为零。

  • 如果值为 geometric,则假定大小以与位置相同的表面单位指定,因此以相同的方式缩放。

  • 如果值为 diameter,则假定大小与触摸或工具的直径(宽度)成正比。

  • 如果值为 area,则假定大小与触摸或工具的面积成正比。

  • 如果值为 default,则如果 raw.touchMajorraw.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

计算

touchMajortouchMinortoolMajortoolMinorsize 字段的计算取决于指定的校准参数。

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 表示主轴向右定向。当存在触控笔工具时,方向范围可以在从 -PIPI 的完整圆范围内描述。

tilt 字段以角度测量值描述工具的倾斜度。0 的倾斜度表示工具垂直于表面。PI/2 的倾斜度表示工具平放在表面上。

touch.orientation.calibration

定义: touch.orientation.calibration = none | interpolated | vector | default

指定触摸驱动程序用于报告方向的测量类型。

  • 如果值为 none,则方向未知,因此设置为 0。
  • 如果值为 interpolated,则方向线性插值,使得 raw.orientation.min 的原始值映射到 -PI/2raw.orientation.max 的原始值映射到 PI/2(raw.orientation.min + raw.orientation.max) / 2 的中心值映射到 0
  • 如果值为 vector,则方向被解释为由两个带符号的 4 位字段组成的打包向量。此表示形式用于 Atmel 基于对象的协议部件。解码后,向量产生方向角和置信度大小。置信度大小用于缩放大小信息,除非它是几何的。
  • 如果值为 default,则如果方向轴可用,系统将使用 interpolated 校准,否则使用 none

计算

orientationtilt 字段的计算取决于指定的校准参数和可用的输入。

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 毫秒、当前指针以及周围的指针,然后考虑触摸点距离显示边缘有多远。然后,它逐个指针地确定哪些指针是手掌。它还会考虑每个接触的大小,如 touchMajortouchMinor 报告的那样。然后,Android 框架从触摸流中删除标记为手掌的指针。

如果指针已发送到应用,则系统会执行以下操作之一

  • (如果还有其他活动指针)使用设置了 ACTION_POINTER_UPFLAG_CANCELEDACTION_POINTER_UP 取消指针。
  • (如果这是唯一的指针)使用 ACTION_CANCEL 取消指针。

公共 API MotionEvent.FLAG_CANCELED 指示当前事件不应触发用户操作。此标志为 ACTION_CANCELACTION_POINTER_UP 设置。

如果手掌指针未发送到应用,则系统只需删除该指针。

启用防误触

  1. 在您的触摸驱动程序中,使用 input_abs_set_res为以下字段设置分辨率(单位为 像素/毫米
    • ABS_MT_POSITION_X
    • ABS_MT_POSITION_Y
    • ABS_MT_TOUCH_MAJOR
    • ABS_MT_TOUCH_MINOR

    ABS_MT_TOUCH_MINOR 的支持是可选的。但是,如果您的设备支持它,请确保分辨率设置正确。

  2. 要确认字段设置正确,请运行
        $ adb shell getevent -li
    
  3. 要在运行时启用该功能,请运行
        $ adb shell device_config put input_native_boot palm_rejection_enabled 1
    
  4. 重启 system_server 进程。
         $ adb shell stop && adb shell start
        
  5. 确认 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: {}
    
  6. 要永久启用该功能,请在您的 init**rc 文件中添加相应的 sysprop 命令

    setprop persist.device_config.input_native_boot.palm_rejection_enabled 1
    

延伸阅读