Ubuntu系统下如何将蓝牙键盘作为非系统HID设备连接并通过Python捕获按键以自定义功能
没问题,完全可以做到!既然你的键盘是标准HID设备,我们只需要两步核心操作:先让系统别把它当成普通输入键盘,再用Python直接读取它的原始HID数据来实现自定义功能。下面是详细步骤:
一、阻止系统将键盘识别为常规输入设备
默认情况下,Ubuntu会自动把HID键盘纳入输入子系统,导致按键直接输出字符。我们可以通过udev规则来屏蔽这个行为:
找到键盘的Vendor ID和Product ID
先配对你的蓝牙键盘,然后打开终端执行命令:udevadm info --name=/dev/input/eventX --attribute-walk这里的
eventX需要替换成你键盘对应的输入设备号(可以用ls /dev/input/event*查看,或者通过evtest工具确认哪个是你的蓝牙键盘)。在输出里找到类似ATTRS{idVendor}=="1234"和ATTRS{idProduct}=="5678"的行,记下这两个十六进制值。也可以用后面Python代码里的
hid.enumerate()来枚举设备,直接获取这两个ID。创建udev规则文件
用文本编辑器创建规则文件:sudo nano /etc/udev/rules.d/99-bluetooth-custom-keyboard.rules写入以下内容(替换
xxxx和yyyy为你刚才拿到的Vendor ID和Product ID):ACTION=="add", ATTRS{idVendor}=="xxxx", ATTRS{idProduct}=="yyyy", ENV{ID_INPUT_KEYBOARD}="0", MODE="0666"这条规则会告诉系统:这个设备不是常规键盘,同时给普通用户读写权限。
重新加载udev规则
执行命令让规则生效:sudo udevadm control --reload-rules sudo udevadm trigger之后重新连接蓝牙键盘,它就不会再输出字符了。
二、用Python 3捕获并处理按键
我们可以用hidapi库直接和HID设备通信,读取键盘的原始按键报告。
安装依赖
先安装系统级的hidapi库:sudo apt install libhidapi-hidraw0然后安装Python的hidapi绑定:
pip install hidapi编写Python代码示例
下面是一个基础示例,它会枚举设备、连接键盘,实时读取并解析按键:import hid # 替换成你的键盘的Vendor ID和Product ID(十进制或十六进制都可以) VENDOR_ID = 0x1234 PRODUCT_ID = 0x5678 def find_keyboard(): # 枚举所有HID设备,找到目标设备 for device in hid.enumerate(VENDOR_ID, PRODUCT_ID): if device['interface_number'] == 0: # 一般HID键盘的接口号是0 return device['path'] return None def parse_hid_report(report): # HID键盘报告通常是8字节: # 字节0:修饰键(Ctrl/Shift/Alt等,每个位对应一个修饰键) # 字节1:保留位 # 字节2-7:按下的按键码(最多同时6个按键) modifiers = report[0] keys = report[2:8] # 修饰键映射(根据HID规范) modifier_map = { 0x01: 'Left Ctrl', 0x02: 'Left Shift', 0x04: 'Left Alt', 0x08: 'Left GUI', 0x10: 'Right Ctrl', 0x20: 'Right Shift', 0x40: 'Right Alt', 0x80: 'Right GUI' } # 常用按键码映射(可根据HID Usage Table补充更多) key_map = { 0x04: 'a', 0x05: 'b', 0x06: 'c', 0x07: 'd', 0x08: 'e', 0x09: 'f', 0x0a: 'g', 0x0b: 'h', 0x0c: 'i', 0x0d: 'j', 0x0e: 'k', 0x0f: 'l', 0x10: 'm', 0x11: 'n', 0x12: 'o', 0x13: 'p', 0x14: 'q', 0x15: 'r', 0x16: 's', 0x17: 't', 0x18: 'u', 0x19: 'v', 0x1a: 'w', 0x1b: 'x', 0x1c: 'y', 0x1d: 'z', 0x1e: '1', 0x1f: '2', 0x20: '3', 0x21: '4', 0x22: '5', 0x23: '6', 0x24: '7', 0x25: '8', 0x26: '9', 0x27: '0', 0x28: 'Enter', 0x29: 'Escape', 0x2a: 'Backspace', 0x2b: 'Tab', 0x2c: 'Space', 0x2d: '-', 0x2e: '=', 0x2f: '[', 0x30: ']', 0x31: '\\', 0x32: '#', 0x33: ';', 0x34: '\'', 0x35: '`', 0x36: ',', 0x37: '.', 0x38: '/' } pressed_modifiers = [name for bit, name in modifier_map.items() if modifiers & bit] pressed_keys = [key_map.get(key, f'Unknown(0x{key:02x})') for key in keys if key != 0] return pressed_modifiers, pressed_keys def main(): device_path = find_keyboard() if not device_path: print("找不到目标蓝牙键盘!") return try: with hid.Device(path=device_path) as h: print(f"已连接到键盘:{h.get_manufacturer_string()} {h.get_product_string()}") print("开始监听按键(按Ctrl+C退出)...") while True: # 读取HID报告,超时时间1000ms report = h.read(64, timeout=1000) if report: modifiers, keys = parse_hid_report(report) if keys or modifiers: print(f"修饰键: {modifiers} | 按键: {keys}") # 在这里添加你的自定义功能逻辑 if 'a' in keys: print("执行自定义功能:打开浏览器!") # 示例:调用系统命令 # import subprocess # subprocess.run(['xdg-open', 'https://google.com']) elif 'Enter' in keys: print("执行自定义功能:暂停音乐!") except KeyboardInterrupt: print("\n已退出监听") except Exception as e: print(f"错误:{e}") if __name__ == "__main__": main()代码说明
find_keyboard():根据设置的ID找到目标设备的路径parse_hid_report():把HID原始字节数据转换成可读的按键名称- 在
main()的循环里,你可以根据pressed_keys和pressed_modifiers添加任意自定义功能,比如调用系统命令、启动程序等
三、注意事项
- 如果运行代码提示权限不足,检查udev规则里的
MODE="0666"是否正确,或者暂时用sudo运行脚本 - 不同键盘的HID报告格式可能略有差异,如果解析不对,可以用
hidapi的get_report_descriptor()方法获取键盘的HID描述符,调整解析逻辑 - 如果蓝牙键盘断开重连,可能需要重新运行脚本,你可以添加重连逻辑来优化
内容的提问来源于stack exchange,提问作者xnsdfgr

