如何在Linux上捕获原始HID输入?

40

我想要实现的简短版本:我有一个脚踏板(INFINITY-IN-USB-1,如果这有任何兴趣),它被实现为通用HID设备,我希望它在Linux上表现为CtrlAlt键。 我正在寻找X级别的解决方案,即不仅仅是单个程序。

更长版本:通过调用DLL函数RegisterRawInputDevicesGetRawInputData并在隐藏窗口中监听输入,在Windows XP中已经设置好了。所有这些都可以通过相当简单的AutoHotkey脚本完成(如果有人感兴趣,我可以在这里发布)。 关键是,没有任何额外的驱动程序等需求; 只需要本机的Windows DLL文件。

我希望在Linux上(更具体地说是Ubuntu下的GNOME,但我偶尔也会使用其他发行版/窗口管理器)使此设置工作。 这个脚踏板不会注册为键盘甚至游戏手柄,而是作为UsagePage 12、Usage 3的HID设备。

我注意到最新的Ubuntu可以检测并使用Microsoft Natural Keyboard上的喜爱键,这些键也被注册为HID设备。在Windows上,我使用与踏板相同的方法使用这些键(即不使用捆绑软件)。因此,我认为这个踏板也可以在Linux上工作,但问题是如何操作?
(我对Linux底层的东西还很陌生,请在适当时候提供介绍或教程的链接。)
注:* 对于那些不知道的人,Microsoft Natural Keyboard既注册为常规键盘,又注册为通用HID设备。如果没有某些应用程序(例如捆绑应用程序)知道如何解释HID输入,则常规键将起作用,但喜爱键和特殊功能键无效。

为了澄清,Linux并没有将踏板按下视为输入。它确实识别USB设备,但xev在踏板按下时没有输出。我已经看到有人成功地在Wine下使用踏板进行转录软件,但那必须按照Windows的方式工作,不能满足我的需求(即使踏板对于所有本地Linux应用程序都像键盘一样)。是否需要一些低级Linux键盘驱动程序?


以下是更多信息:如果我在终端中发出这个命令

cat /dev/usb/hiddev0

dev/usb/hiddev0 是我的踏板),我得到了与我的踏板按下相对应的原始代码。这是一个开端。我知道这些原始代码的含义:在二进制中,0001、0010、0100 分别对应于每个踏板,并且踏板按下的组合会发送这些二进制数的组合,而踏板的释放会触发任何一个踏板仍然被按下的输入(如果所有踏板都松开,则发送 0000)。
我如何让 X 监听 dev/usb/hiddev0 并将原始代码转换成特殊的键码,以便我可以使用 xmodmap 或其他东西来映射它们?
6个回答

23
您需要使用。您需要在/dev/usb/hiddev0上进行监听,然后创建新的事件并将其发送到/dev/input/uinput
这篇文章解释了如何操作,并提供了一些教程: 使用Linux-2.6.x中的uinput驱动程序发送用户输入 {这是EInfochips的“Dashboard”出版物2007年1月份的“本月提示”文章,在存档页面上提到}。

7
您能详细说明一下吗?如何通过程序监听/dev/usb/hiddev0(您提供的文章只涉及uinput)?最终的程序(监听hiddev并通过uinput发送键盘/鼠标事件)需要作为守护进程运行,我猜想是这样吗? - polyglot
2
是的,我从你的问题中推断出你已经知道如何读取hiddev0。你可能会编写一个守护进程。首先编写一个程序,不断读取hiddev0并打印出按键事件。然后你可以修改它通过uinput发出新的事件。这基本上会将这些事件重新注入到内核中,但作为键盘或鼠标事件(由你选择)。不需要对X进行任何更改。 - Adam Goode

6
我在我的博客中写了关于如何让我的Infinity IN-USB-1(又名“VEC USB Footpedal”)在X下发送任意键值的文章: 使用VEC / Infinity USB脚踏板作为Linux下的键盘 (它也适用于IN-USB-2,以及由VEC和P.I. Engineering销售的一些其他USB脚控制器型号和它们的克隆版本。)
以下是简短版本:
获取X识别踏板
踏板是符合HID标准的USB设备,内核没有问题发现它,并通过/dev/input/eventX节点将其事件提供给用户空间。您可以运行evtest程序(在Debian上:sudo apt install evtest)查看。因此,您不需要进入HID级别即可使用脚踏板。
问题在于udev没有将其标记为键盘或鼠标,因此X会忽略它。可以通过一行udev规则文件来解决这个问题(感谢Parlatype开发者Gabor Karsay在Parlatype Issue 28中提供了这个解决方案)。
ACTION=="add|change", KERNEL=="event[0-9]*", ATTRS{idVendor}=="05f3", ATTRS{idProduct}=="00ff", ENV{ID_INPUT_KEYBOARD}="1"

将该行代码放入名为/etc/udev/rules.d/10-vec-usb-footpedal.rules的文件中。无需重新启动任何内容,udev应自动检测该文件。
现在,当您拔下并重新插入USB踏板时,它应该被X识别(并发送鼠标按钮事件)。要验证,请运行xev
使用udev hwdb重新映射keysyms
具有仅发送鼠标单击的踏板可能不是您想要的。可以使用udev hwdb文件重新映射踏板开关发送的键代码。
/etc/udev/hwdb.d/下创建一个文件(我将其放在/etc/udev/hwdb.d/60-usb-footpedal.hwdb中),其中包含以下行: /etc/udev/hwdb.d/60-usb-footpedal.hwdb
evdev:input:b*v05F3p00FF*
 KEYBOARD_KEY_90001=f14
 KEYBOARD_KEY_90002=f15
 KEYBOARD_KEY_90003=f16

这次我们需要通知系统更新二进制hwdb文件:
$ sudo systemd-hwdb update

然后拔掉并重新插入设备。

hwdb文件的第一行匹配我们的设备(厂商05F3,产品00FF),随后的行将一个扫描码(十六进制)映射到一个按键码。我选择了F14、F15和F16功能键,但可用按键码的列表在/usr/include/linux/input-event-codes.h中定义;要将那个文件中#defined的名称作为hwdb按键码使用,只需将它们转换为小写并删除key_前缀。

我的电脑上默认的(pc+us) xkb键盘布局将F14F15F16映射到XF86Launch5XF86Launch6XF86Launch7键符号。如果现在打开xev并按下踏板,您应该会看到这些键符号被发出。使用这些键符号,每个踏板开关可以在您的桌面或窗口管理器中映射为热键。

你还可以使用类似于xmodmap的工具将XF86*键码映射到其他按键上。更多细节,包括如何在vim中映射这些按键,文档链接,指向直接读取HID设备的阅读指南,以及Mac OS X的解决方案,请参见我的博客文章

足控器

最后要提到的是一个名为footcontroller的Python程序,它从evdev设备(/dev/input/eventX)读取事件,并可配置为响应踏下踏板时发出按键(通过xdotool)或运行脚本。它可以用来替代xmodmap,让你的踏板发送任何你想要的按键。

4
如果设备出现在/dev/input中,请使用“evdev”X驱动程序来连接它,就像您为键盘或鼠标所做的一样。

evdev 在 TinyCore 上不可用,有什么想法吗? - Abbas

2

我也遇到了同样的问题,但是是在使用无线键盘上特殊按键时出现的。我理解你的痛苦。

不过,为了让它正常工作,这是我的方法:

  1. sleep 10; killall cat,然后在另一个终端中迅速输入:cat /dev/usb/hiddevice0 > key1.usbdump,然后按下/使用设备。这将转储hiddevice的二进制输出以获取该键的信息。
  2. 我快速地编写了一个Python脚本来读取hiddevice的输入并触发事件。到目前为止,它仅适用于第一次按下该键。这与Adam所建议的类似,但我认为uinput更难编程/使用,尽管可能更优雅,而且Python易于获取。

所以这还在不断改进中(仅适用于第一次按下),但也许像这样的东西对你有用:

sf1 = open("test.usbdump").read() # Read the earlier USB dump from hiddevice
kb = open("/dev/usb/hiddev0")
while 1:
    # Prints true if the specific key has been read.
    print (kb.read(len(sf1)) == sf1)
    # Basically all that has to be done is if ^ is true, then fire off the event you want.

如果有人能帮我解决程序问题或者我做错了什么,请告诉我。 ;)
我意识到在hid设备的初始转储中包含了一些标题。使用一些十六进制编辑和位差分,可以找到哪些值是重要的,并在Python中进行检查。(例如,十六进制数"B0"表示我的键盘上按下了一个特殊功能键,稍后会有更多关于按下的键的信息等。)
我的最终结果是:hiddevice0似乎会在一段时间后停止提供数据,不确定原因,但是我使用了/dev/input/event* (这也可能适用于您),这似乎效果更好。同样,相同的十六进制编辑和低级解析会导致成功。在此过程中,我发现sudo cat /dev/input/event3 | hexdump对于确定对您重要的字节非常有帮助。
因此,如果您有一个SK-8812 IBM键盘,并且想使用特殊键,您可以与我交谈以获取我使用的脚本。

在同一个终端中,您可以输入(sleep 10; killall cat)&cat /usb/dev/hiddev0> key1.usbdump。 - John Allsup

2
你应该调查一下LIRC。它可以解释来自遥控器的输入。一些支持的遥控器显然表现为通用的HID设备,因此你可以尝试让你的设备与LIRC通信。

0

在我的绑定/快捷键中,我使用了Compiz, easystroke和xmacro的组合。

对于您的需求,我认为缺失的部分可能是xbindkeys。我为您找到了这个链接,可以帮助您进行设置:

http://linux-trackball.dreamhosters.com/

我想知道是否有一种方法可以区分多个鼠标设备。


3
我已经了解了xbindkeys等内容,但问题是X无法识别我的踏板按键,所以现在xbindkeys是无用的。即使你提供的链接的作者也有一些轨迹球上的按钮仍然无法工作。我的问题是如何让那些无法工作的按键正常工作,而不是如何使用已经工作的按键。抱歉造成困惑。 - polyglot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接