一.input设置事件类型
__set_bit 是一个位操作函数,用于设置一个位图中的特定位,例如可以通过下面的代码将 输入设备设置为支持按键事件:
__set_bit(EV_KEY,myinput_dev->evbit)
第一位为设置设置事件类型。
第二位为输入设备的能力 和支持的功能。
设置事件类型
在头文件 include/uapi/linux/input-event-codes.h 中,Linux 内核已经为我们定义了一些输入 事件类型,它们的含义如下:
(1)EV_SYN (0x00): 用于同步事件,表示一组输入事件的结束。
(2)EV_KEY (0x01): 用于按键事件,表示按下、释放或重复一个键。
(3)EV_REL (0x02): 用于相对位移事件,表示设备的相对位置变化,例如鼠标的移动。
(4)EV_ABS (0x03): 用于绝对位移事件,表示设备的绝对位置变化,例如触摸屏的坐标。
(5)EV_MSC (0x04): 用于杂项事件,包含一些特殊目的的事件类型,例如设备状态变化等。
(6)EV_SW (0x05): 用于开关事件,表示开关的状态变化,例如电源按钮、开合盖等。
(7)EV_LED (0x11): 用于 LED 事件,表示 LED 灯的状态变化。
(8)EV_SND (0x12): 用于声音事件,表示声音的播放相关事件。
(9)EV_REP (0x14): 用于重复事件,表示键盘重复发送事件。
(10)EV_FF (0x15): 用于力反馈事件,表示力反馈设备的输出事件。
(11)EV_PWR (0x16): 用于电源事件,表示电源状态变化。
(12)EV_FF_STATUS (0x17): 用于力反馈状态事件,表示力反馈设备的状态变化。
(13)EV_MAX (0x1f): 输入事件类型的最大值。
(14)EV_CNT: 输入事件类型的数量。
在 input_dev 结构体中定义了一系列的位图,在输入子系统中用于表示输入设备的能力 和支持的功能,具体定义如下所示:
unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; // 设备的属性位图
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; // 设备支持的事件类型位图
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; // 设备支持的按键位图
unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; // 设备支持的相对坐标位图
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; // 设备支持的绝对坐标位图
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; // 设备支持的杂项事件位图
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; // 设备支持的 LED 位图
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; // 设备支持的声音位图
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; // 设备支持的力反馈位图
(1)evbit(事件类型位图)是一个长度为 EV_CNT 的数组,每个元素对应一个事件类型。 通过设置相应的位,可以指示设备支持的事件类型,如按键事件、相对位移事件、绝对位移事 件、杂项事件等。 (2)keybit(按键类型位图)表示输入设备支持的按键类型,通常与 EV_KEY 事件类型 相关。通过设置相应的位,可以指示设备支持的按键。
(3)relbit(相对位移类型位图)表示输入设备支持的相对位移类型,通常与 EV_REL 事 件类型相关。通过设置相应的位,可以指示设备支持的相对位移,例如鼠标的移动。
(4)absbit(绝对位移类型位图)表示输入设备支持的绝对位移类型,通常与 EV_ABS 事 件类型相关。通过设置相应的位,可以指示设备支持的绝对位移,例如触摸屏的坐标。
(5)mscbit(杂项类型位图)表示输入设备支持的杂项类型,通常与 EV_MSC 事件类 型相关。通过设置相应的位,可以指示设备支持的杂项事件,例如设备状态变化等。
(6)ledbit(LED 类型位图)表示输入设备支持的 LED 类型,通常与 EV_LED 事件类 型相关。通过设置相应的位,可以指示设备支持的 LED 灯控制。
(7)sndbit(声音类型位图)表示输入设备支持的声音类型,通常与 EV_SND 事件类型 相关。通过设置相应的位,可以指示设备支持的声音事件。
(8)ffbit(力反馈类型位图)表示输入设备支持的力反馈类型,通常与 EV_FF 事件类 型相关。通过设置相应的位,可以指示设备支持的力反馈事件。
(9)swbit(开关类型位图)表示输入设备支持的开关类型,通常与 EV_SW 事件类型相 关。通过设置相应的位,可以指示设备支持的开关状态变化。
二.上报事件
上报事件是指在设备驱动层中,当输入设备产生事件时,将该事件通知给输入子系统。在 上报事件之前,首先要确定要上报的事件类型。事件类型可以是按键事件、相对位置事件、绝 对位置事件等,取决于输入设备的特性和能力。在 Linux 内核中,事件类型由预定义的常量表 示,如 EV_KEY 表示按键事件,EV_REL 表示相对位置事件,EV_ABS 表示绝对位置事件等。
而在确定事件类型之后,就需要使用相应的上报函数将事件数据传递给输入子系统。 常用的上报函数包括:
input_report_key():上报按键事件,用于通知按键的按下和释放状态。
input_report_rel():上报相对位置事件,用于通知设备的相对移动量,如鼠标的移动。
input_report_abs():上报绝对位置事件,用于通知设备的绝对位置,如触摸屏的坐标。
input_report_key 函数:
函数原型:input_report_key(struct input_dev *dev, unsigned int code, int value):
功能:上报按键事件。
参数:dev:输入设备结构体指针,表示要发送事件的输入设备。 code:按键码,表示按下或释放的具体按键。 value:按键状态,0 表示按键释放,非零值表示按键按下。
input_report_rel 函数:
函数原型:input_report_rel(struct input_dev *dev, unsigned int code, int value):
功能:上报相对位置事件。
参数:dev:输入设备结构体指针,表示要发送事件的输入设备。 code:位置码,表示相对位置的具体类型。 value:位置偏移量,表示设备相对于先前位置的移动量。
input_report_abs 函数:
函数原型:input_report_abs(struct input_dev *dev, unsigned int code, int value):
功能:上报绝对位置事件。
参数:dev:输入设备结构体指针,表示要发送事件的输入设备。 code:位置码,表示绝对位置的具体类型。 value:位置值,表示设备的绝对位置。
input_report_ff_status 函数:
input_report_ff_status(struct input_dev *dev, unsigned int code, int value):
功能:上报力反馈状态事件。
参数:dev:输入设备结构体指针,表示要发送事件的输入设备。 code:力反馈码,表示力反馈的具体类型。 value:力反馈状态,0 表示停止,非零值表示运行中。
input_report_switch 函数:
函数原型:input_report_switch(struct input_dev *dev, unsigned int code, int value):
功能:上报开关事件。
参数:dev:输入设备结构体指针,表示要发送事件的输入设备。 code:开关码,表示开关的具体类型。 value:开关状态,0 表示关闭,非零值表示打开。
input_sync 函数:
函数原型:input_sync(struct input_dev *dev):
功能:同步事件。 参数:dev:输入设备结构体指针,表示要发送事件的输入设备。
每个上报函数都是内联函数,通过调用 input_event()函数将事件数据添加到输入事件队列 中。这些函数的参数中包含了事件类型(如 EV_KEY、EV_REL 等)、事件码(如按键码、位 置码等)以及事件的具体值(如按键状态、位置偏移量等)。这些参数用于构造输入事件,并 将其添加到输入事件队列中,以便后续的处理。 在使用上报函数之后,通常会调用 input_sync()函数进行同步。同步事件的目的是告知输入 子系统事件的结束,以便子系统可以将事件传递给相应的应用程序或系统组件进行处理。同步 事件的调用可以防止事件数据的丢失或混乱。
三.上报数据格式分析
可以使用 命令“hexdump /dev/input/event4”来查看上报的信息。实际上,使用 hexdump 命令查看到的 数据也是 input_event 数据包。
接下来我们再来看一下 input_event 数据包中的成员
在 input_event 数据包中,有四个成员变量:time,type,code,value。这些成员变量的 值在使用 hexdump 命令获取到的数据中是以字节的形式存储的每个字节都以十六进制的形式 表示。为了将 hexdump 输出的数据与 input_event 数据包中的成员值对应起来,你需要了解数 据包的字节顺序(即字节序)和每个成员的字节大小。
time.tv_sec 和 time.tv_usec 的类型是 long int,占 8 个字节
__u16 type 的类型是 unsigned short int,占 2 个字节
__u16 code 的类型是 unsigned short int,占 2 个字节
__s32 value 的类型是 unsigned int,占 4 个字节。
一个 input_event 数据包所占字节的大小为 8+8+2+2+4 =24 个字节。
如下图所示为一个 input_event 数据包。
对应的成员值如下:
tv_sec: 0f09 65d3 0000 0000
tv_usec: 36fb 0001 0000 0000
type: 0003
code:0039
value: 0000 0000