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
用于同步和分离触摸事件。有关更多信息,请参阅多点触控 (MT) 协议文档。
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;当工具离开可检测范围时,应设置为 0。BTN_TOOL_<name> 指示硬件当前检测到的工具类型,并且独立于 ABS_DISTANCE 和/或 BTN_TOUCH。
ABS_PROFILE
用于描述多值配置文件开关的状态。仅当所选配置文件更改时才发出事件,指示新选择的配置文件值。
ABS_MT_<name>
用于描述多点触控输入事件。有关详细信息,请参阅多点触控 (MT) 协议。
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.3. INPUT_PROP_SEMI_MT¶
一些触控板(在 2008 年至 2011 年间最常见)可以检测到多个触点的存在,但无法解析各个位置;只知道触点数量和矩形形状。对于此类触控板,应设置 SEMI_MT 属性。
根据设备的不同,该矩形可能包围所有触摸(如边界框),或者只包围其中一部分,例如最近的两次触摸。这种多样性使得矩形的使用受限,但通常可以从中提取一些手势。
如果未设置 INPUT_PROP_SEMI_MT,则假定该设备是真正的 MT 设备。
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。