输入

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 Usages 或 Linux 键码。

扫描码主要对键盘感兴趣。其他设备通常使用 GPIO 引脚、I2C 消息或其他方式进行低级别通信。因此,软件堆栈的上层依赖于设备驱动程序来理解正在发生的事情。

隐藏使用

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

Android Framework 依靠 Linux 内核 HID 驱动程序将 HID 使用代码转换为 Linux 键码和其他标识符。因此,HID 的使用主要是外围设备制造商感兴趣的。

关键代码

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 开关代码使用以前缀SW_开头的常量在linux/input.h头文件中定义。 Linux 内核输入驱动程序将开关状态更改报告为EV_SW事件。

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

安卓键码

Android 键码是 Android API 中定义的标准标识符,用于指示特定键,例如“HOME”。 Android 键码由android.view.KeyEvent类定义为以前缀KEYCODE_开头的常量。

键布局指定 Linux 键码如何映射到 Android 键码。根据键盘型号、语言、国家/地区、布局或特殊功能,可能会使用不同的按键布局。

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

安卓轴码

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

键布局指定 Linux 轴代码如何映射到 Android 轴代码。根据设备型号、语言、国家、布局或特殊功能,可能会使用不同的按键布局。

安卓元状态

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

当前元状态由 Android InputReader 组件确定,该组件监视何时按下/释放KEYCODE_SHIFT_LEFT等修改键,并设置/重置适当的元状态标志。

修改键和元状态之间的关系是硬编码的,但键布局可以改变修改键本身的映射方式,进而影响元状态。

安卓按钮状态

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

当前按钮状态由 Android InputReader 组件确定,该组件监视何时按下/释放按钮(在鼠标或手写笔上)并设置/重置适当的按钮状态标志。

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

进一步阅读

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