如何在 Linux 中调试 USB HID scancode-keycode 翻译

How to debug USB HID scancode-keycode translation in Linux

我最近将一个 122 键终端键盘转换为 USB 作为 configfs USB 小工具(键盘部分使用 HID 代码),它工作得很好,除了我似乎无法让我的 Archlinux 安装识别某些HID 代码(特别是目前 F13-F24)并将它们转换为我可以在 X 中使用的事件代码。

正确接收 HID 代码

我可以通过 /dev/hidraw2 看到计算机正在接收 HID(下面的输出是按 F24 时,HID 代码 0x73 基于:https://gist.github.com/MightyPork/6da26e382a7ad91b5496ee55fdc73db2.

    sudo hexdump -C /dev/hidraw2
00000000  00 00 00 00 00 00 00 00  00 00 73 00 00 00 00 00  |..........s.....|

HID 代码未转换为事件

然而,当我尝试 showkey -sevtestxev 时,我什么也得不到,就好像我没有按任何键。所有 "normal" HID 代码都有效(事实上,这条消息现在正在键盘上输入)所以它一定是在收到 HID 代码和它的翻译之间。

有趣的是,我的 evtest 功能没有列出 F13-F24 的事件代码(见下文),但我看到这些功能在其他人的输出中列出(例如 https://unix.stackexchange.com/questions/130656/how-to-get-all-my-keys-to-send-keycodes)。

    Input driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x1d6b product 0x104 version 0x101
Input device name: "CPMH 122 Gadget"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 1 (KEY_ESC)
    Event code 2 (KEY_1)
    Event code 3 (KEY_2)
    Event code 4 (KEY_3)
    Event code 5 (KEY_4)
    Event code 6 (KEY_5)
    Event code 7 (KEY_6)
    Event code 8 (KEY_7)
    Event code 9 (KEY_8)
    Event code 10 (KEY_9)
    Event code 11 (KEY_0)
    Event code 12 (KEY_MINUS)
    Event code 13 (KEY_EQUAL)
    Event code 14 (KEY_BACKSPACE)
    Event code 15 (KEY_TAB)
    Event code 16 (KEY_Q)
    Event code 17 (KEY_W)
    Event code 18 (KEY_E)
    Event code 19 (KEY_R)
    Event code 20 (KEY_T)
    Event code 21 (KEY_Y)
    Event code 22 (KEY_U)
    Event code 23 (KEY_I)
    Event code 24 (KEY_O)
    Event code 25 (KEY_P)
    Event code 26 (KEY_LEFTBRACE)
    Event code 27 (KEY_RIGHTBRACE)
    Event code 28 (KEY_ENTER)
    Event code 29 (KEY_LEFTCTRL)
    Event code 30 (KEY_A)
    Event code 31 (KEY_S)
    Event code 32 (KEY_D)
    Event code 33 (KEY_F)
    Event code 34 (KEY_G)
    Event code 35 (KEY_H)
    Event code 36 (KEY_J)
    Event code 37 (KEY_K)
    Event code 38 (KEY_L)
    Event code 39 (KEY_SEMICOLON)
    Event code 40 (KEY_APOSTROPHE)
    Event code 41 (KEY_GRAVE)
    Event code 42 (KEY_LEFTSHIFT)
    Event code 43 (KEY_BACKSLASH)
    Event code 44 (KEY_Z)
    Event code 45 (KEY_X)
    Event code 46 (KEY_C)
    Event code 47 (KEY_V)
    Event code 48 (KEY_B)
    Event code 49 (KEY_N)
    Event code 50 (KEY_M)
    Event code 51 (KEY_COMMA)
    Event code 52 (KEY_DOT)
    Event code 53 (KEY_SLASH)
    Event code 54 (KEY_RIGHTSHIFT)
    Event code 55 (KEY_KPASTERISK)
    Event code 56 (KEY_LEFTALT)
    Event code 57 (KEY_SPACE)
    Event code 58 (KEY_CAPSLOCK)
    Event code 59 (KEY_F1)
    Event code 60 (KEY_F2)
    Event code 61 (KEY_F3)
    Event code 62 (KEY_F4)
    Event code 63 (KEY_F5)
    Event code 64 (KEY_F6)
    Event code 65 (KEY_F7)
    Event code 66 (KEY_F8)
    Event code 67 (KEY_F9)
    Event code 68 (KEY_F10)
    Event code 69 (KEY_NUMLOCK)
    Event code 70 (KEY_SCROLLLOCK)
    Event code 71 (KEY_KP7)
    Event code 72 (KEY_KP8)
    Event code 73 (KEY_KP9)
    Event code 74 (KEY_KPMINUS)
    Event code 75 (KEY_KP4)
    Event code 76 (KEY_KP5)
    Event code 77 (KEY_KP6)
    Event code 78 (KEY_KPPLUS)
    Event code 79 (KEY_KP1)
    Event code 80 (KEY_KP2)
    Event code 81 (KEY_KP3)
    Event code 82 (KEY_KP0)
    Event code 83 (KEY_KPDOT)
    Event code 86 (KEY_102ND)
    Event code 87 (KEY_F11)
    Event code 88 (KEY_F12)
    Event code 96 (KEY_KPENTER)
    Event code 97 (KEY_RIGHTCTRL)
    Event code 98 (KEY_KPSLASH)
    Event code 99 (KEY_SYSRQ)
    Event code 100 (KEY_RIGHTALT)
    Event code 102 (KEY_HOME)
    Event code 103 (KEY_UP)
    Event code 104 (KEY_PAGEUP)
    Event code 105 (KEY_LEFT)
    Event code 106 (KEY_RIGHT)
    Event code 107 (KEY_END)
    Event code 108 (KEY_DOWN)
    Event code 109 (KEY_PAGEDOWN)
    Event code 110 (KEY_INSERT)
    Event code 111 (KEY_DELETE)
    Event code 119 (KEY_PAUSE)
    Event code 125 (KEY_LEFTMETA)
    Event code 126 (KEY_RIGHTMETA)
    Event code 127 (KEY_COMPOSE)
  Event type 4 (EV_MSC)
    Event code 4 (MSC_SCAN)
  Event type 17 (EV_LED)
    Event code 0 (LED_NUML) state 1
    Event code 1 (LED_CAPSL) state 0
    Event code 2 (LED_SCROLLL) state 0
    Event code 3 (LED_COMPOSE) state 0
    Event code 4 (LED_KANA) state 0
Key repeat handling:
  Repeat type 20 (EV_REP)
    Repeat code 0 (REP_DELAY)
      Value    250
    Repeat code 1 (REP_PERIOD)
      Value     33

是driver吗?

根据我的 evtest EV_KEY 功能与我看到的其他功能之间的差异,我认为可能是我的 driver 无法将 USB HID 代码映射到适当的事件代码。

使用 hwinfo 我可以看出我的键盘正在使用 hid-generic driver。查看 hid-input.c (http://elixir.free-electrons.com/linux/v3.5.2/source/drivers/hid/hid-input.c) I can see that the mapping is indeed there (the HID code 0x73 maps to 194 which maps to the KEY_F24 event, at least according to what I found here: https://github.com/wayland-project/libinput/blob/master/include/linux/input-event-codes.h) 的源代码。因此,根据我在网上阅读的内容,我相信问题出在 hid-generic 和 libinput 之间的某个地方。

我不确定从这里到哪里去,evtest 没有任何结果,我不确定将键映射到什么。只是这些键的功能没有定义吗?有没有办法将我的键盘的功能指定给 evdev?

找到问题了。在查看了 usbhid 的代码后,我意识到这是分配 evtest 发现的可用事件代码的原因。为此,它会读取 HID 描述符。事实证明,我使用了一个通用的 HID 描述符,并且逻辑最大值和使用最大值切断了更高编号的 HID 代码。我使用 https://github.com/DIGImend/hidrd 获取二进制描述符的可编辑版本,然后将最大使用量和逻辑最大值更改为我使用的最高 HID 代码。将其重新转换为二进制格式,上传并启动键盘。现在 evtest 识别所有键。

这是我的原始规格:

Usage Page (Desktop),               ; Generic desktop controls (01h)
Usage (Keyboard),                   ; Keyboard (06h, application collection)
Collection (Application),
    Usage Page (Keyboard),          ; Keyboard/keypad (07h)
    Usage Minimum (KB Leftcontrol), ; Keyboard left control (E0h, dynamic value)
    Usage Maximum (KB Right GUI),   ; Keyboard right GUI (E7h, dynamic value)
    Logical Minimum (0),
    Logical Maximum (1),
    Report Size (1),
    Report Count (8),
    Input (Variable),
    Report Count (1),
    Report Size (8),
    Input (Constant, Variable),
    Report Count (5),
    Report Size (1),
    Usage Page (LED),               ; LEDs (08h)
    Usage Minimum (01h),
    Usage Maximum (05h),
    Output (Variable),
    Report Count (1),
    Report Size (3),
    Output (Constant, Variable),
    Report Count (6),
    Report Size (8),
    Logical Minimum (0),
    Logical Maximum (101),
    Usage Page (Keyboard),          ; Keyboard/keypad (07h)
    Usage Minimum (None),           ; No event (00h, selector)
    Usage Maximum (KB Application), ; Keyboard Application (65h, selector)
    Input,
End Collection

我更新的规格:

Usage Page (Desktop),               ; Generic desktop controls (01h)
Usage (Keyboard),                   ; Keyboard (06h, application collection)
Collection (Application),
    Usage Page (Keyboard),          ; Keyboard/keypad (07h)
    Usage Minimum (KB Leftcontrol), ; Keyboard left control (E0h, dynamic value)
    Usage Maximum (KB Right GUI),   ; Keyboard right GUI (E7h, dynamic value)
    Logical Minimum (0),
    Logical Maximum (1),
    Report Size (1),
    Report Count (8),
    Input (Variable),
    Report Count (1),
    Report Size (8),
    Input (Constant, Variable),
    Report Count (5),
    Report Size (1),
    Usage Page (LED),               ; LEDs (08h)
    Usage Minimum (01h),
    Usage Maximum (05h),
    Output (Variable),
    Report Count (1),
    Report Size (3),
    Output (Constant, Variable),
    Report Count (6),
    Report Size (8),
    Logical Minimum (0),
    Logical Maximum (115),
    Usage Page (Keyboard),          ; Keyboard/keypad (07h)
    Usage Minimum (None),           ; No event (00h, selector)
    Usage Maximum (KB F24),         ; Keyboard F24 (73h, selector)
    Input,
End Collection