概述
输入系统协议用类型 types 和编码 codes 来表示输入设备的值并用此来通知用户空间的应用程序。这篇文档对这些类型和编码进行了说明并且指出什么时候和如何使用这些类型和编码。
一个单一的硬件事件可以产生多个输入事件,每个输入事件包含一个单一数据项的新的数据值。EV_SYN 是一个特别的事件类型,它用来把同一时刻产生的多个输入数据分割为多个数据包。在下面的描述中,术语事件(event)是指一个涵盖类型,编码和参数值的单一输入事件。
input 协议是一个基于状态的协议,只有当相应事件编码对应的参数值发生变化时才会发送该事件。不过,状态是由 Linux 的输入子系统进行维护,驱动程序无需维护输入的状态,就算参数值没有变化时向输入子系统发出事件也不会有问题。用户空间可以用 linux/input.h 中定义的 EVIOCG*ioctls 来获得当前事件编码和参数的状态。
设备的所支持的上报事件种类也可以通过 sysfs 的 class/input/event*/device/capabilities/ 来获取,设备的特性和可以通过 class/input/event*/device/properties 来获取。
输入子系统的 input_dev 结构体的定义如下(节选事件):
struct input_dev {
/* ...省略... */
unsigned long evbit[NBITS(EV_MAX)]; /* 表示能产生哪类事件 */
unsigned long keybit[NBITS(KEY_MAX)]; /* 表示能产生哪些按键 */
unsigned long relbit[NBITS(REL_MAX)]; /* 表示能产生哪些相对位移事件 */
unsigned long absbit[NBITS(ABS_MAX)]; /* 表示能产生哪些绝对位移事件 */
unsigned long mscbit[NBITS(MSC_MAX)];
unsigned long ledbit[NBITS(LED_MAX)];
unsigned long sndbit[NBITS(SND_MAX)];
unsigned long ffbit[NBITS(FF_MAX)];
unsigned long swbit[NBITS(SW_MAX)];
/* ...省略... */
}
Event Types
evbit[NBITS(EV_MAX)]
:记录的是 Event types 对应于一个相同逻辑输入结构的一组 Codes。
每个 type 都有一组可用的 codes 用于产生输入事件。每个 type 可用的 codes 的详细信息请参考 Codes 一节的内容。
宏 | 值 | 描述 |
---|---|---|
EV_SYN | 0x00 | 用于事件间的分割标志。 事件可能按时间或空间进行分割,就像在多点触摸协议中的例子。 |
EV_KEY | 0x01 | 用来描述键盘,按键或者类似键盘设备的状态变化。 |
EV_REL | 0x02 | 用来描述相对坐标轴上数值的变化,例如:鼠标向左方移动了5个单位。 |
EV_ABS | 0x03 | 用来描述相对坐标轴上数值的变化,例如:描述触摸屏上坐标的值。 |
EV_MSC | 0x04 | 当不能匹配现有的类型时,使用该类型进行描述。 |
EV_SW | 0x05 | 用来描述具备两种状态的输入开关。 |
EV_LED | 0x11 | 用于控制设备上的 LED 灯的开和关。 |
EV_SND | 0x12 | 用来给设备输出提示声音。 |
EV_REP | 0x14 | 用于可以自动重复的设备(autorepeating)。 |
EV_FF | 0x15 | 用来给输入设备发送强制回馈命令。(震动?) |
EV_PWR | 0x16 | 特别用于电源开关的输入。. |
EV_FF_STATUS | 0x17 | 用于接收设备的强制反馈状态。 |
EV_MAX | 0x1f |
Event codes
keybit[NBITS(KEY_MAX)]
、relbit[NBITS(REL_MAX)]
、absbit[NBITS(ABS_MAX)]
等等至 swbit[NBITS(SW_MAX)]
中记录的都是 Event codes。
Event codes 用于对事件的 type 进行更精确的定义。
EV_SYN
EV_SYN 事件没有对 values 进行具体的定义, 它们的使用方式仅在发送 evdev 的事件串中有定义。
宏 | 描述 |
---|---|
SYN_REPORT | 当多个输入数据在同一时间发生变化时,SYN_REPORT 用于把这些数据进行打包和包同步。 例如,一次鼠标的移动可以上报 REL_X 和 REL_Y 两个数值,然后发出一个 SYN_REPORT。下一次鼠标移动可以再次发出 REL_X 和 REL_Y 两个数值,然后紧跟这另一个 SYN_REPORT。 |
SYN_CONFIG | TBD |
SYN_MT_REPORT | 用于同步和分离触摸事件。 更多的信息请参考内核文档:multi-touch-protocol.txt。 |
SYN_DROPPED | 用来指出 evdev 客户的事件队列的的缓冲区溢出。 客户端顶盖忽略所有的事件,包括下一个SYN_REPORT事件,并且要查询设备来获得它的状态(使用EVIOCG*ioctls)。 |
EV_KEY
keybit[NBITS(KEY_MAX)]
EV_KEY 事件采取 KEY_<name> 或 BTN_<name> 的形式。
比如:KEY_A 代表键盘上的A键,当一个按键被按下时,一个带有按键编码和 value 为1的事件被发出。当一个按键被释放时,一个带有按键编码和 value 为0的事件被发出。有些硬件当按键重复时会发出事件,这些事件的 value 值为2。
通常,KEY_<name> 用作键盘上的按键,而 BTN_<name> 则用于开关按钮事件。
几个 EV_KEY 的 codes 具有特别的意义:
宏 | 描述 |
---|---|
BTN_TOOL_<name> | 这些 codes 用于配合触控板,平板和触摸屏这些设备的输入,这些设备可以使用手指,笔或者其它工具。 当一个事件发生并且检测到某种工具在使用时,相应的BTN_TOOL_<name> code 事件应该把 value 设为1;当该工具不再和输入设备进行交互时,value 应该复位为0。 所有的触控板,当事件发生时,平板和触摸屏映泰至少使用一种BTN_TOOL_<name> code。 |
BTN_TOUCH | BTN_TOUCH 用于触摸接触事件。 当一个输入工具被判定为有意义的物理接触时,这一特性的 value 值应该设为1。所谓有意义的物理接触可以是任何的接触,又或者是满足某种定义条件的接触。 例如,触摸板可以当触摸的压力达到某一个值以上时才把 value 设为1,一个用笔的平板当笔划过但没有接触到平板的表面时,把 BTN_TOOL_PEN 的 value 设为1,而把B TN_TOUCH 的 value 设为0. 注意:为了配合一些老的传统 mousedev 模拟驱动程序可以工作,BTN_TOUCH 必须作为一个同步帧的第一个 evdevcode 发出。 注意:出于历史的原因,用户空间会把带有 BTN_TOOL_FINGER 和 BTN_TOUCH 的触摸设备解释为触摸板,而类似的不带 BTN_TOOL_FINGER 的触摸设备则被解释为触摸屏。为了与目前的用户空间应用向后兼容,建议遵循这一区分原则。以后,这一区分方法将会失效,而会使用设备属性 ioctl EVIOCGPROP(定义在linux/input.h)来传送设备的类型。 |
BTN_TOOL_FINGER BTN_TOOL_DOUBLETAP BTN_TOOL_TRIPLETAP BTN_TOOL_QUADTAP | 这些 codes表明一个、两个、三个和四个手指同时参与触摸板和触摸屏的操作。 例如,如果用户使用两只手指在触摸板上试图滚动屏幕上的内容,在运动期间,应该发送 value 为1的 BTN_TOOL_DOUBLETAP。 注意的是所有的 BTN_TOOL_<name> codes 和 BTN_TOUCH code 是用于正交目的的,一个触摸板由手指碰触时,应该在这两组中各生成一个事件 code,至少在一个同步帧中带有一个 value 为1的 BTN_TOOL_<name> code。 注意:出于历史原因,一些驱动会在同一个同步帧内发送多个 value 为1的上报手指数的 codes,但是这一方法现在已经过时了(不再使用)。 注意:在多手指触摸驱动中,应该使用 input_mt_report_finger_count() 函数来发出以上这些 codes,详情请参看内核文档:multi-touch-protocol.txt。 |
EV_REL
relbit[NBITS(REL_MAX)]
EV_REL 事件描述了某种特性的相对变化量。例如,鼠标向左方移动了几个单位距离,但是他的绝对位置是未知的。如果我们可以知道绝对位置,那我们应该使用 EV_ABS 而不是 EV_REL。
下面这些属于 EV_REL 的 codes 有特别的意义:
宏 | 描述 |
---|---|
REL_WHEEL REL_HWHEEL | 这两个codes用于对应的垂直方向和水平方向的滚轮 |
EV_ABS
absbit[NBITS(ABS_MAX)]
EV_ABS 事件描述了某一特性的绝对变化值,例如,触摸板会用它发出当前位置的绝对坐标值。
以下这些属于 EV_ABS 的 codes 有特殊的意义:
宏 | 描述 |
---|---|
ABS_DISTANCE | 用来描述触摸工具离触摸表面的距离。这一事件应该只有当触摸工具在表面悬空滑过时发出,也就是说,在靠经触摸表面,但是 BTN_TOUCH 的 value 是0的时候。如果输入设备可以工作在三维坐标时,应该考虑使用 ABS_Z 会更好。 |
ABS_MT_<name> | 用于描述多手指触摸输入设备。详情请参考内核文档:multi-touch-protocol.txt。 |
EV_SW
swbit[NBITS(SW_MAX)]
EV_SW 事件用于描述一个两态开关的状态。比如,SW_LID code 用来指出笔记本电脑的屏幕已经合上了。
当绑定一个设备或者从 suspend 状态中 resuming 回来,驱动程序必须上报开关的当前状态。从而保证设备,内核和用户空间的状态保持同步。
在 resume 时,如果开关的状态和 suspend 之前相同,input 子系统会这一重复的状态上报消息。驱动程序任何时候都无需记住开关的状态。
EV_MSC
mscbit[NBITS(MSC_MAX)]
当事件不能用其它事件类型描述时,使用 EV_MSC 是将进行输入和输出事件的上报。
EV_LED
ledbit[NBITS(LED_MAX)]
EV_LED 事件用来设置或查询设备上 LED 的状态。
EV_REP
EV_REP 用来指出自动重复事件(autorepeating)。
EV_SND
sndbit[NBITS(SND_MAX)]
EV_SND 用于对那些简单的发声设备发出发音指令。
EV_FF
ffbit[NBITS(FF_MAX)]
EV_FF 事件用来初始化具有强制反馈能力的设备,并可以让这些设备发出反馈动作。
EV_PWR
EV_PWR 事件是一个特殊的类型,它是电源管理的专用事件,目前没有对它做出良好的定义,将来会完善这一事件。
设备特性(Device properties)
正常情况下,用户空间基于设备发出的数据(比如事件的 types)来建立一个输入设备,当两个设备都发出相同的事件 types 时,这时设备特性就可以提供额外的识别信息。
INPUT_PROP_DIRECT + INPUT_PROP_POINTER
INPUT_PROP_DIRECT 特性表明设备的坐标直接和屏幕坐标向对应(无需琐碎的转换操作,像缩放,反转,旋转等)。非直接输入设备则需要一些必要的变换,比如触摸板上绝对到相对的变换。
典型的直接输入设备有:触摸屏,手写板;非直接输入设备有:触摸板,鼠标。
INPUT_PROP_POINTER 特性表明设备不是利用屏幕来获取输入信息,从而需要一个屏幕上的指针来跟踪用户的移动。
典型的指针设备有:触控板,鼠标;非指针设备:触摸屏。
如果 INPUT_PROP_DIRECT 或者 INPUT_PROP_POINTER 都没有设置,设备将会被认为是未定义,它的类型需要按传统的方式利用事件的 types 推导出来。
INPUT_PROP_BUTTONPAD
有些触摸板,它的按键位于触摸板的底部,这样按下触摸板会产生一次按键消息,对于这种设备,应该设置该特性。自2009年以来,配置这种触控板的 notebooks 和 macbooks 变多越来越普遍。
最初,这种按键特性是在 bcm5974 的驱动中通过名字的版本字段来进行编码,为了向后兼容性,用户空间有必要按这两种方法都进行检查。
INPUT_PROP_SEMI_MT
在2008年至2011年之间,很多触摸板只能检测到多个接触点,但是不知道它们的独立位置,只是知道触点的数量和包围它们的一个矩形。对于这样的设备,应该设置这个半多点触摸特性。
不同的设备,这个矩形可能包围所有的触控点,就像边界框一样,也可能只是包围了一部分触控点,比如最后的两个触控点。这种不确定性限制了这个矩形的用处,只是有些手势识别会对它进行分析。
如果没有设置 INPUT_PROP_SEMI_MT 特性,该设备被假设为全多点触控设备。
使用指引
以下的使用指引确保了单点触摸和多点触摸可以正常地工作,更详尽的信息请参考文档:multi-touch-protocol.txt。
鼠标
当鼠标移动时,REL_{X,Y}必须被上报。主键被按下时,BTN_LEFT必须被上报。 其它按键按下时,BTN_{MIDDLE,RIGHT,4,5,etc.} 应该被上报。鼠标上的滚轮滚动时,REL_WHEEL and REL_HWHEEL 事件应该被上报。
触摸屏
触摸发生时,必须要用 ABS_{X,Y} 上报触摸的位置。触摸有效时,BTN_TOUCH 必须被上报,而不必用BTN_{MOUSE,LEFT,MIDDLE,RIGHT} 来表明一次触摸事件。有可能的话,BTN_TOOL_<name> 事件也可以应该上报。
对于新的硬件,应该设置 INPUT_PROP_DIRECT 特性。
触控板
传统的触控板只是想上面鼠标所说那样上报相对位置信息即可。
具备绝对位置信息的触控板需要通过 ABS_{X,Y} 上报触控点的位置信息。同样,触摸有效时应该上报 BTN_TOUCH 事件。如果支持多点触摸,应该通过 BTN_TOOL_<name> 上报有效触摸的数量。
对于新的硬件,应该设置 INPUT_PROP_POINTER 特性。
Tablets
当笔或其它工具被有效检测后,必须上报 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 都应该被设置。
原文
Linux输入子系统:事件的编码 – event-codes.txt_DroidPhone的博客-CSDN博客_ev是什么意思
最后
以上就是奋斗帅哥为你收集整理的Linux内核输入子系统事件分析原文的全部内容,希望文章能够帮你解决Linux内核输入子系统事件分析原文所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复