str*_*ika 6 linux usb keyboard
我最近买了一个 USB 键盘。它有 12 个额外的按钮,但只有 5 个在工作。日志中没有“未知扫描码”消息。Evtest 无法检测到它们,甚至无法检测到有效的 5(仅常规键)。Xev 检测到正在工作的 5 而不是其他。"cat /dev/input/by-path/pci-0000:00:02.0-usb-0:4:1.0-event-kbd" 与 evtest 相同,但输出更丑陋。事实上,我能够检测到其他 7 个键的唯一方法是使用 Wireshark 进行 USB 嗅探。所以我的键盘没有缺陷。
我正在使用带有 gentoo-sources-2.6.30-r4 内核、xorg-server-1.6.2-r1 和 xf86-input-evdev 驱动程序版本 1.6.2-r1 的 Gentoo Linux。这是相关的 xorg.conf 部分:
Section "InputDevice"
Identifier "Keyboard0"
Driver "evdev"
Option "Device" "/dev/input/by-path/pci-0000:00:02.0-usb-0:4:1.0-event-kbd"
Option "XkbLayout" "hu"
EndSection
Run Code Online (Sandbox Code Playgroud)
我试图找到更多关于 XkbModel 等选项的信息,但手册页并不是很有帮助。我在这里搜索了每个 [键盘] 问题,但只在 Windows 上找到了类似的问题。
我该怎么做才能使钥匙正常工作?如果这是一个错误,我应该在哪里报告?
更新:这是 showkeys -s 输出。当我这样做时,X 服务器没有运行。
kb mode was UNICODE
[ if you are trying this under X, it might not work
since the X server is also reading /dev/console ]
press any key (program terminates 10s after last keypress)...
0xe0 0x22
0xe0 0xa2
0xe0 0x24
0xe0 0xa4
0xe0 0x20
0xe0 0xa0
0xe0 0x32
0xe0 0xb2
0xe0 0x6c
0xe0 0xec
Run Code Online (Sandbox Code Playgroud)
我从左到右按下了额外的键。每个键有 2 行(我猜是按下和释放),并且只检测到有效的 5 行。
更新:我想出了一个非常糟糕的方法。我可以在后台运行 tshark(wireshark 的命令行界面),解析输出并在正确的 USB 数据包上执行任意程序。有一个严重的安全问题:任何被允许使用额外密钥的用户都能够看到任何 USB 和网络流量。这种方法的唯一优点是它有效。在进行一些清理后,我将发布完整的程序。
好的,所以我的程序运行了一个晚上,它仍然有效,所以我发布了代码。它有点笨拙但有效。我还将写下我是如何做到的,因为它对那些不完全使用我的键盘的人很有用。该程序需要足够新的 libpcap 和wireshark。需要挂载 debugfs (mount -t debugfs none_debugs /sys/kernel/debug) 并加载 usbmon 模块 (modprobe -v usbmon)。
这是在后台运行的程序:
#!/usr/bin/python
# This program should be run as the logged in user. The user must have
# permissions to execute tshark as root.
from pexpect import spawn
from pexpect import TIMEOUT
from subprocess import PIPE
from subprocess import Popen
# Configuration variables
## Device ID from lsusb output
deviceID = "0458:0708"
## Output filter for tshark
filter = "usb.endpoint_number == 0x82 && usb.data != 00:00:00:00"
## Tshark command to execute
tsharkCmd = "/home/stribika/bin/tshark-wrapper"
## Keypress - command mapping
### Key: USB Application data in hex ":" between bytes "\r\n" at the end.
### Value: The command to execute. See subprocess.Popen.
commands = {
"00:00:20:00\r\n":[
"qdbus", "org.freedesktop.ScreenSaver", "/ScreenSaver",
"org.freedesktop.ScreenSaver.Lock"
],
"00:00:40:00\r\n":[
"qdbus", "org.kde.amarok", "/Player", "org.freedesktop.MediaPlayer.Prev"
],
"00:00:10:00\r\n":[
"qdbus", "org.kde.amarok", "/Player", "org.freedesktop.MediaPlayer.Next"
],
"02:00:00:00\r\n":[
"qdbus", "org.kde.amarok", "/Player", "org.freedesktop.MediaPlayer.Pause"
],
"04:00:00:00\r\n":[
"qdbus", "org.kde.amarok", "/Player", "org.freedesktop.MediaPlayer.Stop"
],
"00:04:00:00\r\n":[
"qdbus", "org.kde.amarok", "/Player", "org.freedesktop.MediaPlayer.Mute"
],
"20:00:00:00\r\n":[
"qdbus", "org.kde.kwin", "/KWin", "org.kde.KWin.setCurrentDesktop", "1"
],
"40:00:00:00\r\n":[
"qdbus", "org.kde.kwin", "/KWin", "org.kde.KWin.setCurrentDesktop", "2"
],
"00:00:80:00\r\n":[
"qdbus", "org.kde.kwin", "/KWin", "org.kde.KWin.setCurrentDesktop", "3"
],
"00:00:00:08\r\n":[
"qdbus", "org.kde.kwin", "/KWin", "org.kde.KWin.setCurrentDesktop", "4"
],
"00:00:00:20\r\n":[
"qdbus", "org.kde.kwin", "/KWin", "org.kde.KWin.setCurrentDesktop", "5"
],
"00:00:00:10\r\n":[
"qdbus", "org.kde.kwin", "/KWin", "org.kde.KWin.setCurrentDesktop", "6"
],
}
# USB interface names change across reboots. This determines what is the correct
# interface called this week. If this turns out to be the case with endpoint
# numbers lsusb can tell that too.
lsusbCmd = [ "lsusb", "-d", deviceID ]
sedCmd = [
"sed", "-r",
"s/^Bus ([0-9]{3}) Device [0-9]{3}: ID " + deviceID + ".*$/\\1/;s/^0+/usbmon/"
]
lsusb = Popen(lsusbCmd, stdin = PIPE, stdout = PIPE, stderr = PIPE)
sed = Popen(sedCmd, stdin = lsusb.stdout, stdout = PIPE, stderr = PIPE)
usbIface = sed.stdout.readline().rstrip()
# Arguments for Tshark
## -i is the interface (usbmon[0-9]+)
## -R is the output filter
tsharkArgs = [
"-T", "fields", "-e", "usb.data",
"-i", usbIface,
"-R", filter
]
# Start capturing
## pexpect is needed to disable buffering. (Nothing else actally disables it
## don't belive the lies about Popen's bufsize=0)
tshark = spawn(tsharkCmd, tsharkArgs, timeout = 3600)
line = "----"
# Read keypresses while tshark is running and execute the proper command.
while line != "":
try:
line = tshark.readline()
Popen(commands[line], stdin = PIPE, stdout = PIPE, stderr = PIPE)
# We do not care about timeout.
except TIMEOUT:
pass
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,有一个很大的命令数组,索引来自 USB 数据包的应用程序数据。这些值是发出的命令。我正在使用 DBus 来做需要做的事情,但您可以使用 xvkbd 来生成真正的按键事件(我发现 xvkbd 非常慢,发送一个简单的组合键需要几秒钟)。tshark-wrapper 是一个围绕 tshark 的简单包装器,它以 root 身份执行 tshark 并禁用 stderr。
#!/bin/sh
sudo tshark "$@" 2> /dev/null
Run Code Online (Sandbox Code Playgroud)
有问题。用户需要在没有密码的情况下以 root 身份执行 tshark 的权限。这真的是非常糟糕的事情。通过在包装器中放置更多参数并在 python 脚本中放置更少参数并允许用户以 root 用户身份执行包装器,可以降低风险。
现在关于使用其他键盘执行此操作的过程。我对 USB 几乎一无所知,但仍然没有那么难。我的大部分时间都花在弄清楚如何从管道中进行无缓冲读取。我从 lsusb 输出中知道我的键盘在第二个 USB 接口上。所以我开始在usbmon2上使用wireshark进行捕获。鼠标和其他硬件会产生大量噪音,因此请拔下它们或至少不要移动鼠标。
我注意到的第一件事是额外密钥的端点 ID 为 0x82,而普通密钥的端点 ID 为 0x81。有一些数据包以 0x80 开头。这很好,可以轻松过滤:
usb.endpoint_number == 0x82
Run Code Online (Sandbox Code Playgroud)
正常按键:

额外按键:

很容易看出,一次按键会生成 4 个 USB 数据包:2 个用于按下,2 个用于释放。在每一对中,第一个数据包由键盘发送到 PC,第二个数据包相反。它看起来像 TCP 的 ACK-s。“ACK”是URB-SUBMIT,普通数据包是URB-COMPLETE 类型。所以我决定过滤“ACK”并只显示正常数据包:
usb.urb_type == "C\x01\x82\x03\x02"
Run Code Online (Sandbox Code Playgroud)
USB“确认”:

现在每个按键只有 2 个数据包。每一秒都有零应用价值领域,其他一切都有不同的价值。所以我过滤了零并使用其他值来识别键。
usb.data != 00:00:00:00
Run Code Online (Sandbox Code Playgroud)
额外的密钥发布:

我的键盘是 Slimstar 220(我希望这不会被视为垃圾邮件,如果确实如此,我将其删除。)如果您的键盘类型相同,则未修改的程序可能会起作用。否则我认为至少应用价值的东西会有所不同。
如果有人想根据这些数据编写真正的驱动程序,请告诉我。我不喜欢我丑陋的黑客。
更新:该代码现在有望防止重启。
| 归档时间: |
|
| 查看次数: |
3299 次 |
| 最近记录: |