输入

Android 输入 HAL 图标

Android 输入子系统名义上由遍历系统多个层的事件管道组成。

输入管道

在最低层,物理输入设备会生成描述状态更改(例如按键按压和轻触接触点)的信号。设备固件以某种方式编码和传输这些信号,例如向系统发送 USB HID 报告或在 I2C 总线上产生中断。

然后,信号由 Linux 内核中的设备驱动程序解码。Linux 内核为许多标准的外围设备提供驱动程序,特别是那些符合 HID 协议的外围设备。然而,原始设备制造商 (OEM) 通常必须为在低级别紧密集成到系统中的嵌入式设备(如触摸屏)提供自定义驱动程序。

输入设备驱动程序负责通过 Linux 输入协议将设备特定信号转换为标准输入事件格式。Linux 输入协议在 linux/input.h 内核头文件中定义了一组标准事件类型和代码。这样一来,内核之外的组件就不需要关注物理扫描代码、HID 用途、I2C 消息、GPIO 引脚等方面的详细信息。

接下来,Android EventHub 组件通过打开与每个输入设备关联的 evdev 驱动程序从内核读取输入事件。然后,Android InputReader 组件根据设备类别解码输入事件,并生成 Android 输入事件流。在此过程中,Linux 输入协议事件代码将根据输入设备配置、键盘布局文件和各种映射表,转化为 Android 事件代码。

最后,InputReader 将输入事件发送到 InputDispatcher,由其将这些事件转发到相应的窗口。

控制点

在输入管道中有几个阶段会影响对输入设备行为的控制。

驱动程序和固件配置

输入设备驱动程序经常通过在寄存器中设置参数甚或上传固件本身来配置输入设备的行为。对于诸如触摸屏等嵌入式设备尤其如此,其中一大部分校准过程涉及到调整这些参数或修复固件,以提供所需的精度和响应能力并抑制噪声。

驱动程序配置选项通常在内核板级支持包 (BSP) 中指定为模块参数,以便同一驱动程序可以支持多种不同的硬件实现。

本文档旨在介绍驱动程序或固件配置,但在总体上提供了有关设备校准的指导。

板配置属性

内核板级支持包 (BSP) 可以通过由 Android InputReader 组件使用的 SysFS 导出板配置属性,如虚拟键在触摸屏上的位置。

有关不同设备如何使用板配置属性的详细信息,请参阅设备类别部分。

资源叠加层

有几个输入行为是通过 config.xml 中的资源叠加层配置的,例如机盖开关的操作。

以下是几个例子:

  • config_lidKeyboardAccessibility:指定机盖开关对硬件键盘可访问还是隐藏的影响。

  • config_lidNavigationAccessibility:指定机盖开关对触控板可访问还是隐藏的影响。

  • config_longPressOnPowerBehavior:指定当用户按住电源按钮时应当发生的情况。

  • config_lidOpenRotation:指定机盖开关对屏幕方向的影响。

如需详细了解每个配置选项,请参阅 frameworks/base/core/res/res/values/config.xml 中的文档。

按键映射

Android EventHubInputReader 组件使用按键映射来配置按键、操纵杆按钮和操纵杆轴从 Linux 事件代码到 Android 事件代码的映射。映射可能会因设备或语言的不同而不同。

要详细了解不同设备如何使用按键映射,请参阅设备类别部分。

输入设备配置文件

Android EventHubInputReader 组件使用输入设备配置文件来配置特殊设备特征,例如,如何报告触摸尺寸信息。

如需详细了解不同设备如何使用输入设备配置映射,请参阅设备类别部分。

了解 HID 用途和事件代码

通常使用几个不同的标识符来指代键盘上的任何指定按键、游戏控制器上的按钮、操纵杆轴或其他控件。这些标识符之间的关系并非总是一样的:它们取决于一组映射表,其中一些映射是固定的,还有一些映射随设备特征、设备驱动程序、当前语言区域、系统配置、用户偏好设置和其他因素而变化。

物理扫描代码

物理扫描代码是与每个按键、按钮或其他控件相关联的设备特定标识符。由于物理扫描代码通常因设备而异,因此固件或设备驱动程序负责将其映射到标准标识符,例如 HID 用途或 Linux 按键代码。

扫描代码主要用于键盘。其他设备通常使用 GPIO 引脚、I2C 消息或其他方式在低级别进行通信。因此,软件堆栈的上层依赖于设备驱动程序来确定发生的操作。

HID 用途

HID 用途是一种标准标识符,用于报告控件(如键盘按键、操纵杆轴、鼠标按钮或触摸接触点)的状态。大多数 USB 和蓝牙输入设备都符合 HID 规范,使得系统能够以统一的方式与它们进行连接。

Android 框架依赖于 Linux 内核 HID 驱动程序将 HID 用途代码转换为 Linux 按键代码和其他标识符。因此,主要是外设制造商关注 HID 用途。

Linux 按键代码

Linux 按键代码是用于按键或按钮的标准标识符。Linux 按键代码在 linux/input.h 头文件中使用以前缀 KEY_BTN_ 开头的常量进行定义。Linux 内核输入驱动程序负责将物理扫描代码、HID 用途和其他设备特定信号转换为 Linux 按键代码,并作为 EV_KEY 事件的一部分提供有关它们的信息。

Android API 有时将与按键相关联的 Linux 按键代码称为其“扫描代码”。这在技术上是错误的,但是有助于在 API 中区分 Linux 按键代码和 Android 按键代码。

Linux 相对或绝对轴代码

Linux 相对或绝对轴代码是一种标准标识符,用于报告沿着某个轴的相对位移或绝对位置,例如鼠标沿其 X 轴的相对位移或者操纵杆沿其 X 轴的绝对位置。Linux 轴代码在 linux/input.h 头文件中使用以前缀 REL_ABS_ 开头的常量进行定义。Linux 内核输入驱动程序负责将 HID 用途和其他设备特定信号转换为 Linux 轴代码,并作为 EV_RELEV_ABS 事件的一部分提供有关它们的信息。

Linux 开关代码

Linux 开关代码是用于报告设备上的开关(例如机盖开关)状态的标准标识符。Linux 开关代码在 linux/input.h 头文件中使用以前缀 SW_ 开头的常量进行定义。Linux 内核输入驱动程序以 EV_SW 事件形式报告开关状态更改。

Android 应用通常不会接收来自开关的事件,但系统可能会在内部使用它们来控制各种特定于设备的功能。

Android 按键代码

Android 按键代码是在 Android API 中定义的标准标识符,用于指示特定按键(如“主屏幕”)。Android 按键代码由 android.view.KeyEvent 类定义为以前缀 KEYCODE_ 开头的常量。

按键布局指定了 Linux 按键代码如何映射到 Android 按键代码。可以使用不同的按键布局,具体取决于键盘型号、语言、国家/地区、布局或特殊功能。

使用特定于设备和语言区域的按键字符映射将 Android 按键代码组合转换为字符代码。例如,当同时按下标识为 KEYCODE_SHIFTKEYCODE_A 的按键时,系统将在按键字符映射中查找该组合并找到大写字母“A”,然后将其插入当前聚焦的文本微件中。

Android 轴代码

Android 轴代码是在 Android API 中定义的标准标识符,用于指示特定设备轴。Android 轴代码由 android.view.MotionEvent 类定义为以前缀 AXIS_ 开头的常量。

按键布局指定了 Linux 轴代码如何映射到 Android 轴代码。可能会使用不同的按键布局,具体取决于设备型号、语言、国家/地区、布局或特殊功能。

Android 元状态

Android 元状态是在 Android API 中定义的标准标识符,用于指示按哪些辅助键。Android 元状态由 android.view.KeyEvent 类定义为以前缀 META_ 开头的常量。

当前元状态由 Android InputReader 组件确定,该组件用于监控何时按下/释放辅助键(如 KEYCODE_SHIFT_LEFT)并设置/重置相应的元状态标志。

辅助键和元状态之间的关系采用硬编码,但是按键布局可以改变辅助键本身的映射方式,这反过来又会影响元状态。

Android 按钮状态

Android 按钮状态是在 Android API 中定义的标准标识符,用于指示按下(鼠标或触控笔上的)哪些按钮。Android 按钮状态由 android.view.MotionEvent 类定义为以前缀 BUTTON_ 开头的常量。

当前的按钮状态由 Android InputReader 组件确定,该组件用于监控何时按下/释放(鼠标或触控笔上的)按钮并设置/重置相应的按钮状态标志。

按钮和按钮状态之间的关系采用硬编码。

深入阅读

  1. Linux 输入事件代码
  2. Linux 多点触控协议
  3. Linux 输入驱动程序
  4. Linux 强制反馈
  5. HID 信息,包括 HID 用途表