2. 输入事件代码

输入协议使用类型和代码的映射来向用户空间表达输入设备的值。本文档描述了这些类型和代码,以及它们的使用方式和时机。

单个硬件事件会生成多个输入事件。每个输入事件包含单个数据项的新值。一个特殊的事件类型 EV_SYN 用于将输入事件分隔为在同一时刻发生的输入数据更改的数据包。在下文中,“事件”一词指的是包含类型、代码和值的单个输入事件。

输入协议是一个有状态的协议。仅当事件代码的值发生更改时才会发出事件。但是,状态是在 Linux 输入子系统内维护的;驱动程序无需维护状态,并且可以尝试发出未更改的值而不会造成损害。用户空间可以使用 linux/input.h 中定义的 EVIOCG* ioctl 获取事件代码值的当前状态。设备支持的事件报告也由 sysfs 在 class/input/event*/device/capabilities/ 中提供,设备的属性在 class/input/event*/device/properties 中提供。

2.1. 事件类型

事件类型是在逻辑输入结构下对代码进行的分组。每种类型都有一组适用的代码,用于生成事件。有关每种类型的有效代码的详细信息,请参阅“代码”部分。

  • EV_SYN

    • 用作分隔事件的标记。事件可以在时间或空间上分隔,例如使用多点触控协议。

  • EV_KEY

    • 用于描述键盘、按钮或其他类似按键的设备的状态变化。

  • EV_REL

    • 用于描述相对轴值的变化,例如鼠标向左移动 5 个单位。

  • EV_ABS

    • 用于描述绝对轴值的变化,例如描述触摸屏上触摸的坐标。

  • EV_MSC

    • 用于描述不适合其他类型的各种输入数据。

  • EV_SW

    • 用于描述二进制状态输入开关。

  • EV_LED

    • 用于打开和关闭设备上的 LED。

  • EV_SND

    • 用于向设备输出声音。

  • EV_REP

    • 用于自动重复设备。

  • EV_FF

    • 用于向输入设备发送力反馈命令。

  • EV_PWR

    • 电源按钮和开关输入的特殊类型。

  • EV_FF_STATUS

    • 用于接收力反馈设备状态。

2.2. 事件代码

事件代码定义了事件的精确类型。

2.2.1. EV_SYN

EV_SYN 事件值是未定义的。它们的使用仅由它们在 evdev 事件流中发送的时间定义。

  • SYN_REPORT

    • 用于同步和分离事件,将其分为在同一时刻发生的输入数据更改的数据包。例如,鼠标的移动可能会为一次移动设置 REL_X 和 REL_Y 值,然后发出 SYN_REPORT。下一次移动将发出更多的 REL_X 和 REL_Y 值并发送另一个 SYN_REPORT。

  • SYN_CONFIG

    • 待定

  • SYN_MT_REPORT

  • SYN_DROPPED

    • 用于指示 evdev 客户端的事件队列中缓冲区溢出。客户端应忽略所有事件,直到并包括下一个 SYN_REPORT 事件,并查询设备(使用 EVIOCG* ioctl)以获取其当前状态。

2.2.2. EV_KEY

EV_KEY 事件采用 KEY_<name> 或 BTN_<name> 的形式。例如,KEY_A 用于表示键盘上的“A”键。当按下某个键时,会发出一个值为 1 的键代码事件。当松开键时,会发出一个值为 0 的事件。一些硬件会在重复按键时发送事件。这些事件的值为 2。通常,KEY_<name> 用于键盘按键,而 BTN_<name> 用于其他类型的瞬时开关事件。

一些 EV_KEY 代码具有特殊的含义

  • BTN_TOOL_<name>

    • 这些代码与输入触控板、平板电脑和触摸屏一起使用。这些设备可以与手指、笔或其他工具一起使用。当发生事件并且使用工具时,应将相应的 BTN_TOOL_<name> 代码设置为值 1。当工具不再与输入设备交互时,应将 BTN_TOOL_<name> 代码重置为 0。所有触控板、平板电脑和触摸屏在生成事件时都应至少使用一个 BTN_TOOL_<name> 代码。同样,所有触控板、平板电脑和触摸屏一次应仅导出一个 BTN_TOOL_<name>。为了不破坏现有的用户空间,建议不要在一个 EV_SYN 帧中切换工具,而是先将旧的 BTN_TOOL_<name> 发射为 0,然后发射一个 SYN_REPORT,然后将新的 BTN_TOOL_<name> 设置为 1。

  • BTN_TOUCH

    BTN_TOUCH 用于触摸接触。当确定输入工具在有意义的物理接触范围内时,此属性的值必须设置为 1。有意义的物理接触可能意味着任何接触,或者它可能意味着由实现定义的属性调节的接触。例如,触摸板可能仅在触摸压力高于某个值时才将该值设置为 1。BTN_TOUCH 可以与 BTN_TOOL_<name> 代码组合使用。例如,笔平板电脑可能会在笔悬停在平板电脑表面上方但未接触时将 BTN_TOOL_PEN 设置为 1,将 BTN_TOUCH 设置为 0。

注意:为了保证传统的 mousedev 仿真驱动程序的正常功能,BTN_TOUCH 必须是同步帧中发出的第一个 evdev 代码。

注意:历史上,带有 BTN_TOOL_FINGER 和 BTN_TOUCH 的触摸设备被用户空间解释为触摸板,而没有 BTN_TOOL_FINGER 的类似设备被解释为触摸屏。为了与当前用户空间向后兼容,建议遵循此区分。将来,这种区分将被弃用,并且将使用 linux/input.h 中定义的设备属性 ioctl EVIOCGPROP 来传递设备类型。

  • BTN_TOOL_FINGER、BTN_TOOL_DOUBLETAP、BTN_TOOL_TRIPLETAP、BTN_TOOL_QUADTAP

    • 这些代码表示触控板或触摸屏上的一根、两根、三根和四根手指的交互。例如,如果用户使用两根手指并在触控板上移动它们以尝试在屏幕上滚动内容,则应在移动过程中将 BTN_TOOL_DOUBLETAP 的值设置为 1。请注意,所有 BTN_TOOL_<name> 代码和 BTN_TOUCH 代码在用途上是正交的。手指触摸生成的触控板事件应为每个组生成一个代码的事件。在任何同步帧期间,最多只能有一个 BTN_TOOL_<name> 代码的值为 1。

注意:历史上,一些驱动程序在同一个同步帧中发出多个值为 1 的手指计数代码。此用法已弃用。

注意:在多点触控驱动程序中,应使用 input_mt_report_finger_count() 函数发出这些代码。有关详细信息,请参阅 多点触控 (MT) 协议

2.2.3. EV_REL

EV_REL 事件描述了属性中的相对变化。例如,鼠标可以向左移动一定数量的单位,但其在空间中的绝对位置是未知的。如果已知绝对位置,则应使用 EV_ABS 代码而不是 EV_REL 代码。

一些 EV_REL 代码具有特殊的含义

  • REL_WHEEL、REL_HWHEEL

    • 这些代码分别用于垂直和水平滚轮。该值是滚轮上移动的棘爪的数量,其物理尺寸因设备而异。对于高分辨率滚轮,这可能是基于高分辨率滚动事件的近似值,请参阅 REL_WHEEL_HI_RES。这些事件代码是旧代码,应在可用时首选 REL_WHEEL_HI_RES 和 REL_HWHEEL_HI_RES。

  • REL_WHEEL_HI_RES、REL_HWHEEL_HI_RES

    • 高分辨率滚轮数据。累积值 120 表示移动了一个棘爪。对于不提供高分辨率滚动的设备,该值始终是 120 的倍数。对于具有高分辨率滚动的设备,该值可能是 120 的一小部分。

      如果垂直滚轮支持高分辨率滚动,则除了 REL_WHEEL 或 REL_HWHEEL 之外,还会发出此代码。REL_WHEEL 和 REL_HWHEEL 可能是基于高分辨率滚动事件的近似值。不能保证高分辨率数据在模拟 REL_WHEEL 或 REL_HWHEEL 事件时是 120 的倍数。

2.2.4. EV_ABS

EV_ABS 事件描述了属性中的绝对变化。例如,触摸板可能会发出触摸位置的坐标。

一些 EV_ABS 代码具有特殊的含义

  • ABS_DISTANCE

    • 用于描述工具与交互表面的距离。仅当工具悬停时才应发出此事件,这意味着在设备附近,并且 BTN_TOUCH 代码的值为 0。如果可以在三个维度上自由使用输入设备,请考虑使用 ABS_Z 代替。

    • 当工具进入可检测的邻近度时,应将 BTN_TOOL_<name> 设置为 1,当工具离开可检测的邻近度时,应将 BTN_TOOL_<name> 设置为 0。BTN_TOOL_<name> 表示硬件当前检测到的工具类型,并且在其他方面独立于 ABS_DISTANCE 和/或 BTN_TOUCH。

  • ABS_PROFILE

    • 用于描述多值配置文件开关的状态。仅当选定的配置文件发生更改时才会发出事件,指示新选择的配置文件值。

  • ABS_MT_<name>

  • ABS_PRESSURE/ABS_MT_PRESSURE

    • 对于触摸设备,许多设备将接触面积转换为压力。手指会随着压力而变平,导致接触面积增大,因此压力和接触面积直接相关。其他设备并非如此,例如具有真正压力传感器(“压力板”)的数字化仪和触摸板。

      设备应设置轴的分辨率,以指示压力是否以可测量的单位表示。如果分辨率为零,则压力数据以任意单位表示。如果分辨率不为零,则压力数据以单位/克表示。例如,分辨率为 1 时,值 10 表示 10 克,分辨率为 1000 时,值 10 表示 10 微克。

2.2.5. EV_SW

EV_SW 事件描述有状态的二进制开关。例如,SW_LID 代码用于表示笔记本电脑的盖子何时关闭。

当绑定到设备或从挂起状态恢复时,驱动程序必须报告当前的开关状态。这确保设备、内核和用户空间状态同步。

恢复后,如果开关状态与挂起前相同,则输入子系统将过滤掉重复的开关状态报告。驱动程序无需随时保持开关的状态。

2.2.6. EV_MSC

EV_MSC 事件用于不属于其他类别的输入和输出事件。

一些 EV_MSC 代码具有特殊含义

  • MSC_TIMESTAMP

    • 用于报告自上次重置以来的微秒数。此事件应编码为 uint32 值,允许其回绕而没有特殊后果。假设两个连续事件之间的时间差在合理的时间尺度(小时)上是可靠的。可能会发生重置为零的情况,在这种情况下,自上次事件以来的时间是未知的。如果设备不提供此信息,则驱动程序不得将其提供给用户空间。

2.2.7. EV_LED

EV_LED 事件用于输入和输出,以设置和查询设备上各种 LED 的状态。

2.2.8. EV_REP

EV_REP 事件用于指定自动重复事件。

2.2.9. EV_SND

EV_SND 事件用于向简单的声音输出设备发送声音命令。

2.2.10. EV_FF

EV_FF 事件用于初始化支持力反馈的设备并使该设备进行力反馈。

2.2.11. EV_PWR

EV_PWR 事件是一种特殊的事件类型,专门用于电源管理。其用法尚未明确定义。将在以后解决。

2.3. 设备属性

通常,用户空间会根据其发出的数据(即事件类型)设置输入设备。在两个设备发出相同事件类型的情况下,可以以设备属性的形式提供其他信息。

2.3.1. INPUT_PROP_DIRECT + INPUT_PROP_POINTER

INPUT_PROP_DIRECT 属性表示设备坐标应直接映射到屏幕坐标(不考虑微小的转换,例如缩放、翻转和旋转)。非直接输入设备需要进行非微小的转换,例如触摸板的绝对到相对转换。典型的直接输入设备:触摸屏、绘图板;非直接设备:触摸板、鼠标。

INPUT_PROP_POINTER 属性表示设备在屏幕上未转置,因此需要使用屏幕上的指针来跟踪用户的移动。典型的指针设备:触摸板、平板电脑、鼠标;非指针设备:触摸屏。

如果未设置 INPUT_PROP_DIRECT 或 INPUT_PROP_POINTER,则该属性被视为未定义,并且应以传统方式使用发出的事件类型来推断设备类型。

2.3.2. INPUT_PROP_BUTTONPAD

对于按钮位于表面下方的触摸板,按下触摸板会导致按钮点击,应设置此属性。在 Clickpad 笔记本电脑和 2009 年及之后的 Macbooks 中常见。

最初,buttonpad 属性在 bcm5974 驱动程序版本字段中以集成按钮的名称编码。为了向后兼容,需要在用户空间中检查这两种方法。

2.3.3. INPUT_PROP_SEMI_MT

一些触摸板(最常见于 2008 年到 2011 年之间)可以检测到多个触点的存在,而无需解析各个位置;仅知道触点的数量和矩形形状。对于此类触摸板,应设置 SEMI_MT 属性。

根据设备的不同,矩形可以包围所有触摸(如边界框),也可以只包围其中一些触摸,例如最近的两个触摸。这种多样性使得矩形的用途有限,但通常可以从中提取一些手势。

如果未设置 INPUT_PROP_SEMI_MT,则假定该设备是真正的 MT 设备。

2.3.4. INPUT_PROP_TOPBUTTONPAD

一些笔记本电脑,最著名的是联想 40 系列,提供了一个指点杆设备,但没有与该指点杆设备关联的物理按钮。相反,触摸板的顶部区域被标记为显示用于指点杆的左、中、右按钮的视觉/触觉区域。

如果设置了 INPUT_PROP_TOPBUTTONPAD,用户空间应相应地模拟按钮。此属性不影响内核行为。内核不为此类设备提供按钮模拟,而是将其视为任何其他 INPUT_PROP_BUTTONPAD 设备。

2.3.5. INPUT_PROP_ACCELEROMETER

此设备上的方向轴(绝对和/或相对 x、y、z)表示加速度计数据。一些设备还会报告陀螺仪数据,这些设备可以通过旋转轴(绝对和/或相对 rx、ry、rz)进行报告。

所有其他轴保留其含义。设备不得在同一事件节点上混合常规方向轴和加速度计轴。

2.4. 指南

以下指南确保正确地进行单点触控和多指功能。有关多点触控功能,请参阅多点触控 (MT) 协议文档以获取更多信息。

2.4.1. 鼠标

当鼠标移动时,必须报告 REL_{X,Y}。BTN_LEFT 必须用于报告主按钮按下。BTN_{MIDDLE,RIGHT,4,5,etc.} 应用于报告该设备的更多按钮。REL_WHEEL 和 REL_HWHEEL 应用于报告可用的滚轮事件。

2.4.2. 触摸屏

必须报告 ABS_{X,Y} 以及触摸的位置。BTN_TOUCH 必须用于报告屏幕上何时有触摸激活。不得将 BTN_{MOUSE,LEFT,MIDDLE,RIGHT} 报告为触摸接触的结果。应尽可能报告 BTN_TOOL_<name> 事件。

对于新硬件,应设置 INPUT_PROP_DIRECT。

2.4.3. 触控板

仅提供相对位置信息的传统触控板必须报告如上所述的鼠标事件。

提供绝对触摸位置的触控板必须报告 ABS_{X,Y} 作为触摸的位置。BTN_TOUCH 必须用于报告触控板上何时有触摸激活。如果提供多指支持,则应使用 BTN_TOOL_<name> 来报告触控板上激活的触摸次数。

对于新硬件,应设置 INPUT_PROP_POINTER。

2.4.4. 平板电脑

当手写笔或其他工具在平板电脑上激活时,必须报告 BTN_TOOL_<name> 事件。必须报告 ABS_{X,Y} 以及工具的位置。BTN_TOUCH 必须用于报告工具何时与平板电脑接触。BTN_{STYLUS,STYLUS2} 应该用于报告工具本身的按钮。除了 BTN_{MOUSE,LEFT} 外,任何按钮都可以用于平板电脑上的按钮。BTN_{0,1,2,etc} 是未标记按钮的良好通用代码。除非该设备上的按钮为此目的进行了标记,否则不要使用有意义的按钮(如 BTN_FORWARD)。

对于新硬件,应同时设置 INPUT_PROP_DIRECT 和 INPUT_PROP_POINTER。