理解evdev

翻译自这里


理解evdev

这篇文章解释了evdev协议的工作原理。阅读本文后,您应该了解evdev是什么以及如何解释evdev事件dump以了解您的设备正在做什么。该帖子主要针对必须调试设备的用户,因此我将遗漏或简化一些技术细节。我将使用evemu-record的输出作为示例,因为这是evdev的主要调试工具。


什么是evdev?

evdev是一种仅限Linux的通用协议,内核使用该协议将有关输入设备的信息和事件转发给用户空间。这不只是对鼠标和键盘,而是任何形式的轴,键或按钮,包括像摄像头和遥控装置。每个设备都以/dev/input/event0的形式表示为设备节点, 随着您添加更多设备,尾随数字会增加。拔下设备后设备节点将会被其他设备重新使用,因此不要将设备节点硬编码到脚本中。设备节点也只能由root读取(新的内核中加入了capacity机制),因此您也需要以root身份运行任何调试工具。

evdev是与Linux上的输入设备通信的主要方式。Linux上的所有X.Org驱动程序都使用libinput并且以evdev作为协议。请注意,“evdev”也是xf86-input-evdev(用于处理通用evdev设备的X.Org驱动程序)的简称,因此当您在邮件列表中阅读到“evdev”时请注意上下文。


与evdev设备通信

与设备通信很简单:打开设备节点并从中读取。出来的任何数据都是struct input_event,在/usr/include/linux/input.h中定义 :

struct input_event {
 struct timeval time;
 __u16 type;
 __u16 code;
 __s32 value;
};

我稍后会描述内容,但你可以看到它是一个非常简单的结构。
可以使用一组ioctl查询有关设备的静态信息,例如其名称和功能 。请注意,您应该始终使用 ibevdev 与设备进行交互,它会简化evdev的使用。有关用法示例,请参阅libevdev文档。

evemu-record是我们用于evdev的主要调试工具,它非常易于使用。它读取并打印有关设备的静态信息,然后所做的仅仅是读取并打印所有事件。输出是机器可读的格式,但它列出了易于理解的有关设备的注释信息(以#开头)。您始终可以忽略非注释位。还有第二个命令evemu-describe,它只打印设备描述并退出而不等待事件。


相关设备和键盘

evemu-record输出的顶部是设备描述。这是一个静态属性列表,告诉我们设备的功能。例如,我插入的USB鼠标时打印除的信息如下:

# Input device name: "PIXART USB OPTICAL MOUSE"
# Input device ID: bus 0x03 vendor 0x93a product 0x2510 version 0x110
# Supported events:
#   Event type 0 (EV_SYN)
#     Event code 0 (SYN_REPORT)
#     Event code 1 (SYN_CONFIG)
#     Event code 2 (SYN_MT_REPORT)
#     Event code 3 (SYN_DROPPED)
#     Event code 4 ((null))
#     Event code 5 ((null))
#     Event code 6 ((null))
#     Event code 7 ((null))
#     Event code 8 ((null))
#     Event code 9 ((null))
#     Event code 10 ((null))
#     Event code 11 ((null))
#     Event code 12 ((null))
#     Event code 13 ((null))
#     Event code 14 ((null))
#   Event type 1 (EV_KEY)
#     Event code 272 (BTN_LEFT)
#     Event code 273 (BTN_RIGHT)
#     Event code 274 (BTN_MIDDLE)
#   Event type 2 (EV_REL)
#     Event code 0 (REL_X)
#     Event code 1 (REL_Y)
#     Event code 8 (REL_WHEEL)
#   Event type 4 (EV_MSC)
#     Event code 4 (MSC_SCAN)
# Properties:

设备名称(通常)是制造商设置的设备名称,供应商和产品ID也是如此。bus是/usr/include/linux/input.h中定义的“BUS_USB”和类似常量之一。该版本通常非常随意,只有少数设备在这里有一些有意义的东西。
我们还有一组受支持的事件,按“事件类型”和“事件代码”分类(注意类型和代码也是struct input_event的一部分)。type是一般类别,而 /usr/include/linux/input-event-codes.h定义了其中的一些。最重要的类型是EV_KEY(键和按钮),EV_REL(相对坐标)和EV_ABS(绝对坐标)。在上面的输出中,我们可以看到我们设置了EV_KEY和EV_REL。

作为每种类型的子项,我们有事件代码。此设备的事件代码不言自明:BTN_LEFT,BTN_RIGHT和BTN_MIDDLE是左,右和中间按钮。轴是相对x轴,相对y轴和轮轴(即鼠标轮)。EV_MSC / MSC_SCAN用于原始扫描码,您通常可以忽略它。最后我们有EV_SYN位但是忽略它们,它们总是为所有设备设置。

请注意,事件代码不能单独使用,它必须是(类型,代码)的元组。例如,REL_X和ABS_X具有相同的数值,没有类型,您将不知道哪一个是哪个。

这就是它。键盘将设置很多EV_KEY位,EV_REL一般是没有的(但并非总是…)。而不是BTN_LEFT,键盘将具有例如KEY_ESC,KEY_A,KEY_B等. 90%的设备调试是查看事件代码并确定哪些缺失或不应该在那里。

练习:您现在应该能够从连接到计算机的任何鼠标或键盘设备上读取evemu记录描述,并了解其含义。这也适用于大多数特殊设备,例如遥控器 - 唯一改变的是按键/按钮的名称。只需运行sudo evemu-describe并选择列表中的任何设备。

来自相关设备和键盘的事件

evdev是一个序列化协议。它发送一系列事件,然后发送同步事件,通知我们前面的事件都属于一起。此同步事件是EV_SYN SYN_REPORT,由内核而不是设备生成,因此所有EV_SYN代码始终可在所有设备上使用。

我们来看看鼠标移动。如上所述,一行的左半部分是机器代码,但我们可以忽略该位并查看右侧人类可理解的输出。

E: 0.335996 0002 0000 0001 # EV_REL / REL_X 1
E: 0.335996 0002 0001 -002 # EV_REL / REL_Y -2
E: 0.335996 0000 0000 0000 # ------------ SYN_REPORT (0) ----------

这意味着在一个硬件事件中,我们将1个设备单元向右移动(x轴),向上移动了两个设备单元(y轴)。请注意所有事件如何具有相同的时间戳(0.335996)。
我们来看看按钮按下:
E:0.656004 0004 0004 589825#EV_MSC / MSC_SCAN 589825
E:0.656004 0001 0110 0001#EV_KEY / BTN_LEFT 1
E:0.656004 0000 0000 0000#------------ SYN_REPORT(0)----------
E:0.727002 0004 0004 589825#EV_MSC / MSC_SCAN 589825
E:0.727002 0001 0110 0000#EV_KEY / BTN_LEFT 0
E:0.727002 0000 0000 0000#------------ SYN_REPORT(0)----------
对于按钮事件,值1意味着按钮按下,值0意味着按钮松开。
关键事件如下所示:

E:0.000000 0004 0004 458792#EV_MSC / MSC_SCAN 458792
E:0.000000 0001 001c 0000#EV_KEY / KEY_ENTER 0
E:0.000000 0000 0000 0000#------------ SYN_REPORT(0)----------
E:0.560004 0004 0004 458976#EV_MSC / MSC_SCAN 458976
E:0.560004 0001 001d 0001#EV_KEY / KEY_LEFTCTRL 1
E:0.560004 0000 0000 0000#------------ SYN_REPORT(0)----------
[…]
E:1.172732 0001 001d 0002#EV_KEY / KEY_LEFTCTRL 2
E:1.172732 0000 0000 0001#------------ SYN_REPORT(1)----------
E:1.200004 0004 0004 458758#EV_MSC / MSC_SCAN 458758
E:1.200004 0001 002e 0001#EV_KEY / KEY_C 1
E:1.200004 0000 0000 0000#------------ SYN_REPORT(0)----------
与按钮事件大致相同。但等等,有一个区别:我们的值也是2。对于键事件,值2表示“键重复”。如果你在tty上,那么这就是为你生成重复键的原因。在X和Wayland中,我们忽略这些重复事件,而是使用基于XKB的密钥重复。
现在再看一下键盘事件,看看你是否能理解序列。我们有一个Enter松开(但没有按下),然后按下ctrl和重复),然后按下’c’ - 但没有释放。解释很简单 - 只要我点击终端输入,evemu-record就开始录制,所以它也捕获了输入版本。一旦ctrl + c关闭,它就会停止录制,因为当它被终端取消时就会停止录制。这里有一个重要的要点:evdev协议不能保证平衡。你可能会看到一个你从未见过的按键的释放事件,并且你可能错过一个被按下按钮的的释放事件(当你停止录制时会发生这种情况)。哦,还有一个危险:如果您录制键盘并输入密码,键将显示在输出中。

练习:您现在应该能够从连接到计算机的任何鼠标或键盘设备读取evemu-record事件列表并了解事件序列。这也适用于大多数特殊设备,例如遥控器 - 唯一改变的是设备的名称(/dev/input/event*)。只需运行sudo evemu-record并选择列出的任何设备。

绝对的设备

当我们查看触摸屏或触摸板等绝对输入设备时,事情会变得复杂一些。是的,触摸板是硬件中的绝对设备,并且通过例如libinput在用户空间中完成对相对事件的转换。触摸板的输出如下。请注意,我手动删除了一些位以使其更容易理解,它们将在稍后的多点触控讨论中出现。

# Input device name: "SynPS/2 Synaptics TouchPad"
# Input device ID: bus 0x11 vendor 0x02 product 0x07 version 0x1b1
# Supported events:
#   Event type 0 (EV_SYN)
#     Event code 0 (SYN_REPORT)
#     Event code 1 (SYN_CONFIG)
#     Event code 2 (SYN_MT_REPORT)
#     Event code 3 (SYN_DROPPED)
#     Event code 4 ((null))
#     Event code 5 ((null))
#     Event code 6 ((null))
#     Event code 7 ((null))
#     Event code 8 ((null))
#     Event code 9 ((null))
#     Event code 10 ((null))
#     Event code 11 ((null))
#     Event code 12 ((null))
#     Event code 13 ((null))
#     Event code 14 ((null))
#   Event type 1 (EV_KEY)
#     Event code 272 (BTN_LEFT)
#     Event code 325 (BTN_TOOL_FINGER)
#     Event code 328 (BTN_TOOL_QUINTTAP)
#     Event code 330 (BTN_TOUCH)
#     Event code 333 (BTN_TOOL_DOUBLETAP)
#     Event code 334 (BTN_TOOL_TRIPLETAP)
#     Event code 335 (BTN_TOOL_QUADTAP)
#   Event type 3 (EV_ABS)
#     Event code 0 (ABS_X)
#       Value   2919
#       Min     1024
#       Max     5112
#       Fuzz       0
#       Flat       0
#       Resolution 42
#     Event code 1 (ABS_Y)
#       Value   3711
#       Min     2024
#       Max     4832
#       Fuzz       0
#       Flat       0
#       Resolution 42
#     Event code 24 (ABS_PRESSURE)
#       Value      0
#       Min        0
#       Max      255
#       Fuzz       0
#       Flat       0
#       Resolution 0
#     Event code 28 (ABS_TOOL_WIDTH)
#       Value      0
#       Min        0
#       Max       15
#       Fuzz       0
#       Flat       0
#       Resolution 0
# Properties:
#   Property  type 0 (INPUT_PROP_POINTER)
#   Property  type 2 (INPUT_PROP_BUTTONPAD)
#   Property  type 4 (INPUT_PROP_TOPBUTTONPAD)

我们再次有一个BTN_LEFT和一组其他按钮,我将很快解释它。在这之前首先我们来看看EV_ABS输出。我们有与上面相同的命名系统。ABS_X和ABS_Y是设备上的x和y轴,ABS_PRESSURE是(任意)范围压力值。
绝对轴比简单的位具有更多的状态。具体来说,它们具有最小值和最大值(并非所有硬件都以左上角为0/0原点,它可以是由最小值指定的任意位置)。值得注意的是,轴范围只是设备公布的范围 - 不能保证这些值落在这个范围内,实际上很多触摸板设备往往会略微超出该范围。可以安全地忽略模糊和扁平(Fuzz and flat),但分辨率很有趣。它以每毫米为单位给出,因此告诉我们设备的大小。在上述情况下:(5112 - 1024)/ 42表示该设备宽97mm。分辨率通常是错误的,很多轴覆盖( axis overrides)需要将分辨率更改为正确的值。

轴描述也列出了当前值。内核仅在值更改时发送事件,因此即使实际硬件不断发送事件,如果值保持不变,您也可能永远不会在输出中看到它们。换句话说,将手指完美地保持在触摸板上会产生大量硬件事件,但您不会看到任何事件从节点中传出。

最后,我们在此设备上有属性。这些用于指示有关设备的一般信息,这些信息并不明显。在这种情况下,INPUT_PROP_POINTER告诉我们我们需要一个指针来指示这个设备(毕竟它是一个触摸板,触摸屏将改为设置INPUT_PROP_DIRECT)。INPUT_PROP_BUTTONPAD意味着这是一个所谓的Clickpad,它没有单独的物理按钮,而是整个触摸板点击。忽略INPUT_PROP_TOPBUTTONPAD,因为它仅适用于Lenovo * 40系列设备。

好的,回到按钮:除了BTN_LEFT,我们有BTN_TOUCH。这个信号表示用户正在触摸触摸板的表面(具有一些内核定义的最小压力值)。它不只是用于手指触摸,它还用于图形平板手写笔触摸笔(这是它更像是接触”而不是“触摸”)。

BTN_TOOL_FINGER事件告诉我们手指处于可检测范围内。这给了我们两个信息:首先,我们有一个手指(平板电脑将有例如BTN_TOOL_PEN),其次,我们可能有一个手指接近而不接触。在许多触摸板上,BTN_TOOL_FINGER和BTN_TOUCH也会出现在同一事件中,但是其他触摸板也可以检测到手指悬停在触摸板上(在这种情况下,您也希望触摸板上有ABS_DISTANCE可用)。

最后,BTN_TOOL_DOUBLETAP直到BTN_TOOL_QUINTTAP告诉我们设备是否可以在触摸板上检测到2到5个手指。这实际上并不 跟踪手指,它只是在BTN_TOOL_TRIPLETAP的情况下告诉你“3个手指向下”。

练习:查看触摸板的描述,并根据轴信息[1]确定触摸板的大小是否正确。检查触摸板可以检测到的手指数量以及是否可以进行压力或距离检测。


来自绝对设备的事件

来自绝对轴的事件与我们已经涵盖的相关设备的事件没有任何不同。具有值和时间戳的相同类型/代码组合,全部由EV_SYN SYN_REPORT事件构成。这是我触摸触摸板的一个例子:
E:0.000001 0001 014a 0001#EV_KEY / BTN_TOUCH 1
E:0.000001 0003 0000 3335#EV_ABS / ABS_X 3335
E:0.000001 0003 0001 3308#EV_ABS / ABS_Y 3308
E:0.000001 0003 0018 0069#EV_ABS / ABS_PRESSURE 69
E:0.000001 0001 0145 0001#EV_KEY / BTN_TOOL_FINGER 1
E:0.000001 0000 0000 0000#------------ SYN_REPORT(0)---------- + 0ms
E:0.021751 0003 0018 0070#EV_ABS / ABS_PRESSURE 70
E:0.021751 0000 0000 0000#------------ SYN_REPORT(0)---------- + 21ms
E:0.043908 0003 0000 3334#EV_ABS / ABS_X 3334
E:0.043908 0003 0001 3309#EV_ABS / ABS_Y 3309
E:0.043908 0003 0018 0065#EV_ABS / ABS_PRESSURE 65
E:0.043908 0000 0000 0000#------------ SYN_REPORT(0)---------- + 22ms
E:0.052469 0001 014a 0000#EV_KEY / BTN_TOUCH 0
E:0.052469 0003 0018 0000#EV_ABS / ABS_PRESSURE 0
E:0.052469 0001 0145 0000#EV_KEY / BTN_TOOL_FINGER 0
E:0.052469 0000 0000 0000#------------ SYN_REPORT(0)---------- + 9ms
在第一个事件中,您会看到BTN_TOOL_FINGER和BTN_TOUCH设置(此触摸板不会检测悬停的手指)。x / y坐标对和压力值。第二个事件中的压力变化,第三个事件改变压力和位置。最后,我们手指向上释放BTN_TOOL_FINGER和BTN_TOUCH,压力值回到0.请注意第二个事件如何不包含任何x / y坐标?如上所述,内核仅在值更改时才会在绝对轴上发送更新。
好吧,让我们看一下三指点击(再次,减去ABS_MT_位):

E:0.000001 0001 014a 0001#EV_KEY / BTN_TOUCH 1
E:0.000001 0003 0000 2149#EV_ABS / ABS_X 2149
E:0.000001 0003 0001 3747#EV_ABS / ABS_Y 3747
E:0.000001 0003 0018 0066#EV_ABS / ABS_PRESSURE 66
E:0.000001 0001 014e 0001#EV_KEY / BTN_TOOL_TRIPLETAP 1
E:0.000001 0000 0000 0000#------------ SYN_REPORT(0)---------- + 0ms
E:0.034209 0003 0000 2148#EV_ABS / ABS_X 2148
E:0.034209 0003 0018 0064#EV_ABS / ABS_PRESSURE 64
E:0.034209 0000 0000 0000#------------ SYN_REPORT(0)---------- + 34ms
[…]
E:0.138510 0003 0000 4286#EV_ABS / ABS_X 4286
E:0.138510 0003 0001 3350#EV_ABS / ABS_Y 3350
E:0.138510 0003 0018 0055#EV_ABS / ABS_PRESSURE 55
E:0.138510 0001 0145 0001#EV_KEY / BTN_TOOL_FINGER 1
E:0.138510 0001 014e 0000#EV_KEY / BTN_TOOL_TRIPLETAP 0
E:0.138510 0000 0000 0000#------------ SYN_REPORT(0)---------- + 23ms
E:0.147834 0003 0000 4287#EV_ABS / ABS_X 4287
E:0.147834 0003 0001 3351#EV_ABS / ABS_Y 3351
E:0.147834 0003 0018 0037#EV_ABS / ABS_PRESSURE 37
E:0.147834 0000 0000 0000#------------ SYN_REPORT(0)---------- + 9ms
E:0.157151 0001 014a 0000#EV_KEY / BTN_TOUCH 0
E:0.157151 0003 0018 0000#EV_ABS / ABS_PRESSURE 0
E:0.157151 0001 0145 0000#EV_KEY / BTN_TOOL_FINGER 0
E:0.157151 0000 0000 0000#------------ SYN_REPORT(0)---------- + 10ms
在第一个事件中,触摸板同时检测到所有三个手指。因此,设置BTN_TOUCH,x / y /压力和BTN_TOOL_TRIPLETAP。注意,各种BTN_TOOL_ *位是互斥的。BTN_TOOL_FINGER意味着“恰好1个手指向下”,当你有三个手指向下时,你不可能只有1个手指向下。在第二个事件x和压力更新(y没有事件,它保持不变)。
在休息后的事件中,我们从三个手指切换到一个手指。BTN_TOOL_TRIPLETAP被释放,BTN_TOOL_FINGER被设置。这很常见。人类不是机器人,你无法在同一时间释放所有手指,因此根据硬件扫描输出速率,你有一个手指已经离开的中间状态,其他手指仍然处于中断状态。在这种情况下,我在扫描之间释放了两根手指,其中一根手指仍然朝下。从手指向下或手指向上看BTN_TOOL_FINGER到BTN_TOOL_DOUBLETAP到BTN_TOOL_TRIPLETAP的完整周期并不常见。

练习:测试触摸板上的压力值,看看你能达到实际宣布的范围的距离。通过用两根,三根,四根和五根手指敲击来检查多指检测的准确程度。(在这两种情况下,你都会发现它非常受欢迎)。


多点触控和插槽

现在我们处理有关evdev设备的最复杂的话题。对于多点触控设备,我们需要在同一轴上发送多个触摸。因此,我们需要一个额外的维度,称为多点触控插槽(还有另一种较旧的多点触控协议,它不使用插槽,但现在很少见,您不需要打扰)。

首先:所有具有多点触控功能的轴重复为ABS_MT_foo轴。因此,如果您有ABS_X,您还可以获得ABS_MT_POSITION_X,并且两个轴具有相同的轴范围和分辨率。这里的原因是向后兼容性:如果设备仅发送多点触控事件,则仅侦听ABS_X等事件的旧程序将不起作用。某些轴可能仅适用于单触(在这种情况下为ABS_MT_TOOL_WIDTH)。

让我们来看看我的触摸板,这次没有移除轴:

# Input device name: "SynPS/2 Synaptics TouchPad"
# Input device ID: bus 0x11 vendor 0x02 product 0x07 version 0x1b1
# Supported events:
#   Event type 0 (EV_SYN)
#     Event code 0 (SYN_REPORT)
#     Event code 1 (SYN_CONFIG)
#     Event code 2 (SYN_MT_REPORT)
#     Event code 3 (SYN_DROPPED)
#     Event code 4 ((null))
#     Event code 5 ((null))
#     Event code 6 ((null))
#     Event code 7 ((null))
#     Event code 8 ((null))
#     Event code 9 ((null))
#     Event code 10 ((null))
#     Event code 11 ((null))
#     Event code 12 ((null))
#     Event code 13 ((null))
#     Event code 14 ((null))
#   Event type 1 (EV_KEY)
#     Event code 272 (BTN_LEFT)
#     Event code 325 (BTN_TOOL_FINGER)
#     Event code 328 (BTN_TOOL_QUINTTAP)
#     Event code 330 (BTN_TOUCH)
#     Event code 333 (BTN_TOOL_DOUBLETAP)
#     Event code 334 (BTN_TOOL_TRIPLETAP)
#     Event code 335 (BTN_TOOL_QUADTAP)
#   Event type 3 (EV_ABS)
#     Event code 0 (ABS_X)
#       Value   5112
#       Min     1024
#       Max     5112
#       Fuzz       0
#       Flat       0
#       Resolution 41
#     Event code 1 (ABS_Y)
#       Value   2930
#       Min     2024
#       Max     4832
#       Fuzz       0
#       Flat       0
#       Resolution 37
#     Event code 24 (ABS_PRESSURE)
#       Value      0
#       Min        0
#       Max      255
#       Fuzz       0
#       Flat       0
#       Resolution 0
#     Event code 28 (ABS_TOOL_WIDTH)
#       Value      0
#       Min        0
#       Max       15
#       Fuzz       0
#       Flat       0
#       Resolution 0
#     Event code 47 (ABS_MT_SLOT)
#       Value      0
#       Min        0
#       Max        1
#       Fuzz       0
#       Flat       0
#       Resolution 0
#     Event code 53 (ABS_MT_POSITION_X)
#       Value      0
#       Min     1024
#       Max     5112
#       Fuzz       8
#       Flat       0
#       Resolution 41
#     Event code 54 (ABS_MT_POSITION_Y)
#       Value      0
#       Min     2024
#       Max     4832
#       Fuzz       8
#       Flat       0
#       Resolution 37
#     Event code 57 (ABS_MT_TRACKING_ID)
#       Value      0
#       Min        0
#       Max    65535
#       Fuzz       0
#       Flat       0
#       Resolution 0
#     Event code 58 (ABS_MT_PRESSURE)
#       Value      0
#       Min        0
#       Max      255
#       Fuzz       0
#       Flat       0
#       Resolution 0
# Properties:
#   Property  type 0 (INPUT_PROP_POINTER)
#   Property  type 2 (INPUT_PROP_BUTTONPAD)
#   Property  type 4 (INPUT_PROP_TOPBUTTONPAD)

我们有多点触控的x和y位置以及压力轴。还有两个特殊的多点触控轴,它们不是真正的轴。 ABS_MT_SLOT和ABS_MT_TRACKING_ID。前者指定当前活动的插槽,后者用于跟踪触摸点。
插槽是设备的静态属性。我在上面看到的触摸板支持2个插槽(最小0,最大1),因此可以一次跟踪2个手指。每当第一个手指放下时,它的坐标将在插槽0中被跟踪,第二个手指将在插槽1中被跟踪。当插槽0中的手指被抬起时,第二个手指继续在插槽1中被跟踪,如果是新的设置了手指,它将在插槽0中被跟踪。它听起来比较复杂,将其视为一系列可能的接触点的数组就好。

跟踪ID是一个递增的数字,可让我们分开触摸点,并告诉我们触摸何时开始以及何时结束。这两个值是-1或正数。任何正数表示“新触摸”,-1表示“触摸结束”。因此,当您将两根手指放下并再次抬起时,您将在插槽0中获得1的跟踪ID,在插槽1中获得2的跟踪ID,然后在两个插槽中的跟踪ID为-1以表示它们已结束。跟踪ID值本身没有意义,只是随着触摸的创建而增加。

我们来看一下:

E:0.000001 0003 0039 0387#EV_ABS / ABS_MT_TRACKING_ID 387
E:0.000001 0003 0035 2560#EV_ABS / ABS_MT_POSITION_X 2560
E:0.000001 0003 0036 2905#EV_ABS / ABS_MT_POSITION_Y 2905
E:0.000001 0003 003a 0059#EV_ABS / ABS_MT_PRESSURE 59
E:0.000001 0001 014a 0001#EV_KEY / BTN_TOUCH 1
E:0.000001 0003 0000 2560#EV_ABS / ABS_X 2560
E:0.000001 0003 0001 2905#EV_ABS / ABS_Y 2905
E:0.000001 0003 0018 0059#EV_ABS / ABS_PRESSURE 59
E:0.000001 0001 0145 0001#EV_KEY / BTN_TOOL_FINGER 1
E:0.000001 0000 0000 0000#------------ SYN_REPORT(0)---------- + 0ms
E:0.021690 0003 003a 0067#EV_ABS / ABS_MT_PRESSURE 67
E:0.021690 0003 0018 0067#EV_ABS / ABS_PRESSURE 67
E:0.021690 0000 0000 0000#------------ SYN_REPORT(0)---------- + 21ms
E:0.033482 0003 003a 0068#EV_ABS / ABS_MT_PRESSURE 68
E:0.033482 0003 0018 0068#EV_ABS / ABS_PRESSURE 68
E:0.033482 0000 0000 0000#------------ SYN_REPORT(0)---------- + 12ms
E:0.044268 0003 0035 2561#EV_ABS / ABS_MT_POSITION_X 2561
E:0.044268 0003 0000 2561#EV_ABS / ABS_X 2561
E:0.044268 0000 0000 0000#------------ SYN_REPORT(0)---------- + 11ms
E:0.054093 0003 0035 2562#EV_ABS / ABS_MT_POSITION_X 2562
E:0.054093 0003 003a 0067#EV_ABS / ABS_MT_PRESSURE 67
E:0.054093 0003 0000 2562#EV_ABS / ABS_X 2562
E:0.054093 0003 0018 0067#EV_ABS / ABS_PRESSURE 67
E:0.054093 0000 0000 0000#------------ SYN_REPORT(0)---------- + 10ms
E:0.064891 0003 0035 2569#EV_ABS / ABS_MT_POSITION_X 2569
E:0.064891 0003 0036 2903#EV_ABS / ABS_MT_POSITION_Y 2903
E:0.064891 0003 003a 0059#EV_ABS / ABS_MT_PRESSURE 59
E:0.064891 0003 0000 2569#EV_ABS / ABS_X 2569
E:0.064891 0003 0001 2903#EV_ABS / ABS_Y 2903
E:0.064891 0003 0018 0059#EV_ABS / ABS_PRESSURE 59
E:0.064891 0000 0000 0000#------------ SYN_REPORT(0)---------- + 10ms
E:0.073634 0003 0039 -001#EV_ABS / ABS_MT_TRACKING_ID -1
E:0.073634 0001 014a 0000#EV_KEY / BTN_TOUCH 0
E:0.073634 0003 0018 0000#EV_ABS / ABS_PRESSURE 0
E:0.073634 0001 0145 0000#EV_KEY / BTN_TOOL_FINGER 0
E:0.073634 0000 0000 0000#------------ SYN_REPORT(0)---------- + 9ms
我们有一个跟踪ID(387)信号指针向下,以及位置加压力。然后一些更新,最终跟踪ID为-1(信号指针向上)。注意这里没有ABS_MT_SLOT - 内核缓冲那些,当你停留在同一个槽(在这种情况下为0)时,你没有看到任何事件。另请注意如何在同一事件流中同时获得单指和多点触控。这是为了向后兼容[2]

好的,两指点击的时间:

E:0.000001 0003 0039 0496#EV_ABS / ABS_MT_TRACKING_ID 496
E:0.000001 0003 0035 2609#EV_ABS / ABS_MT_POSITION_X 2609
E:0.000001 0003 0036 3791#EV_ABS / ABS_MT_POSITION_Y 3791
E:0.000001 0003 003a 0054#EV_ABS / ABS_MT_PRESSURE 54
E:0.000001 0003 002f 0001#EV_ABS / ABS_MT_SLOT 1
E:0.000001 0003 0039 0497#EV_ABS / ABS_MT_TRACKING_ID 497
E:0.000001 0003 0035 3012#EV_ABS / ABS_MT_POSITION_X 3012
E:0.000001 0003 0036 3088#EV_ABS / ABS_MT_POSITION_Y 3088
E:0.000001 0003 003a 0056#EV_ABS / ABS_MT_PRESSURE 56
E:0.000001 0001 014a 0001#EV_KEY / BTN_TOUCH 1
E:0.000001 0003 0000 2609#EV_ABS / ABS_X 2609
E:0.000001 0003 0001 3791#EV_ABS / ABS_Y 3791
E:0.000001 0003 0018 0054#EV_ABS / ABS_PRESSURE 54
E:0.000001 0001 014d 0001#EV_KEY / BTN_TOOL_DOUBLETAP 1
E:0.000001 0000 0000 0000#------------ SYN_REPORT(0)---------- + 0ms
E:0.012909 0003 002f 0000#EV_ABS / ABS_MT_SLOT 0
E:0.012909 0003 0039 -001#EV_ABS / ABS_MT_TRACKING_ID -1
E:0.012909 0003 002f 0001#EV_ABS / ABS_MT_SLOT 1
E:0.012909 0003 0039 -001#EV_ABS / ABS_MT_TRACKING_ID -1
E:0.012909 0001 014a 0000#EV_KEY / BTN_TOUCH 0
E:0.012909 0003 0018 0000#EV_ABS / ABS_PRESSURE 0
E:0.012909 0001 014d 0000#EV_KEY / BTN_TOOL_DOUBLETAP 0
E:0.012909 0000 0000 0000#------------ SYN_REPORT(0)---------- + 12ms
这是一个非常快速的双指点击,很好地说明了跟踪ID。在第一个事件中,我们得到一个触点,然后是ABS_MT_SLOT事件。这告诉我们后续事件属于另一个槽,所以它是另一个手指。我们也有跟踪ID +位置。在下一个事件中,我们得到一个ABS_MT_SLOT切换回插槽0.跟踪ID为-1意味着触摸结束,然后我们看到插槽1中的触摸也结束了。
双指滚动的时间:

E:0.000001 0003 0039 0557#EV_ABS / ABS_MT_TRACKING_ID 557
E:0.000001 0003 0035 2589#EV_ABS / ABS_MT_POSITION_X 2589
E:0.000001 0003 0036 3363#EV_ABS / ABS_MT_POSITION_Y 3363
E:0.000001 0003 003a 0048#EV_ABS / ABS_MT_PRESSURE 48
E:0.000001 0003 002f 0001#EV_ABS / ABS_MT_SLOT 1
E:0.000001 0003 0039 0558#EV_ABS / ABS_MT_TRACKING_ID 558
E:0.000001 0003 0035 3512#EV_ABS / ABS_MT_POSITION_X 3512
E:0.000001 0003 0036 3028#EV_ABS / ABS_MT_POSITION_Y 3028
E:0.000001 0003 003a 0044#EV_ABS / ABS_MT_PRESSURE 44
E:0.000001 0001 014a 0001#EV_KEY / BTN_TOUCH 1
E:0.000001 0003 0000 2589#EV_ABS / ABS_X 2589
E:0.000001 0003 0001 3363#EV_ABS / ABS_Y 3363
E:0.000001 0003 0018 0048#EV_ABS / ABS_PRESSURE 48
E:0.000001 0001 014d 0001#EV_KEY / BTN_TOOL_DOUBLETAP 1
E:0.000001 0000 0000 0000#------------ SYN_REPORT(0)---------- + 0ms
E:0.027960 0003 002f 0000#EV_ABS / ABS_MT_SLOT 0
E:0.027960 0003 0035 2590#EV_ABS / ABS_MT_POSITION_X 2590
E:0.027960 0003 0036 3395#EV_ABS / ABS_MT_POSITION_Y 3395
E:0.027960 0003 003a 0046#EV_ABS / ABS_MT_PRESSURE 46
E:0.027960 0003 002f 0001#EV_ABS / ABS_MT_SLOT 1
E:0.027960 0003 0035 3511#EV_ABS / ABS_MT_POSITION_X 3511
E:0.027960 0003 0036 3052#EV_ABS / ABS_MT_POSITION_Y 3052
E:0.027960 0003 0000 2590#EV_ABS / ABS_X 2590
E:0.027960 0003 0001 3395#EV_ABS / ABS_Y 3395
E:0.027960 0003 0018 0046#EV_ABS / ABS_PRESSURE 46
E:0.027960 0000 0000 0000#------------ SYN_REPORT(0)---------- + 27ms
E:0.051720 0003 002f 0000#EV_ABS / ABS_MT_SLOT 0
E:0.051720 0003 0035 2609#EV_ABS / ABS_MT_POSITION_X 2609
E:0.051720 0003 0036 3447#EV_ABS / ABS_MT_POSITION_Y 3447
E:0.051720 0003 002f 0001#EV_ABS / ABS_MT_SLOT 1
E:0.051720 0003 0036 3080#EV_ABS / ABS_MT_POSITION_Y 3080
E:0.051720 0003 0000 2609#EV_ABS / ABS_X 2609
E:0.051720 0003 0001 3447#EV_ABS / ABS_Y 3447
E:0.051720 0000 0000 0000#------------ SYN_REPORT(0)---------- + 24ms
[…]
E:0.272034 0003 002f 0000#EV_ABS / ABS_MT_SLOT 0
E:0.272034 0003 0039 -001#EV_ABS / ABS_MT_TRACKING_ID -1
E:0.272034 0003 002f 0001#EV_ABS / ABS_MT_SLOT 1
E:0.272034 0003 0039 -001#EV_ABS / ABS_MT_TRACKING_ID -1
E:0.272034 0001 014a 0000#EV_KEY / BTN_TOUCH 0
E:0.272034 0003 0018 0000#EV_ABS / ABS_PRESSURE 0
E:0.272034 0001 014d 0000#EV_KEY / BTN_TOOL_DOUBLETAP 0
E:0.272034 0000 0000 0000#------------ SYN_REPORT(0)---------- + 30ms
请注意,“滚动”是在用户空间中处理的内容,因此您在此处看到的只是双指移动。那里的所有东西我都已经看过了,但要注意两个中间事件:当每个手指都有更新时,ABS_MT_SLOT会在发送upate之前发生变化。相同事件的内核过滤器仍然有效,因此在第三个事件中,我们没有获得插槽1上X位置的更新。过滤是每个接触点,因此在这种情况下这意味着插槽1位置x是仍然在3511,就像在上一次活动中一样。
这就是你必须要记住的,真的。如果你认为evdev是一种发送接触点数组的序列化方式,以插槽作为索引,那么它应该是相当清楚的。剩下的就是实际看看触摸位置并理解它们。

练习:在触控板上做一个捏动手势。看看你是否可以跟踪两个手指靠近在一起。然后做同样但只移动一根手指。了解不动的手指如何获得更少的更新。

而已。evdev还有一些细节,但其中很多只是更多的事件类型和代码。处理事件时您真正需要担心的一些细节要么记录在libevdev中,要么完全抽象出来。以上内容足以让您了解设备的功能以及设备无法正常运行时出现的问题。祝好运。

[1]如果没有,请提交一个针对systemd的hwdb和CC的错误,以便我们可以更正
[2]我们将一些具有MT功能的触摸板视为libinput中的单触设备,因为MT数据是垃圾

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值