将无效USB控制器事件码1:300映射为有效事件码的技术求助
问题描述
- 修复旧街机时遇到USB控制器事件解析问题:控制器发送无效事件码
EV_KEY:300(即1:300),街机软件无法识别 - 需求:拦截该事件并转换为有效事件码
EV_KEY:194(对应KEY_F24) - 尝试
evsieve工具失败,原因是工具不识别未知事件码300
相关输出
evtest输出
Event: time 1669313468.400824, type 4 (EV_MSC), code 4 (MSC_SCAN), value 9000d Event: time 1669313468.400824, type 1 (EV_KEY), code 300 (?), value 0
evsieve错误输出
While parsing the arguments "--map key:300 key:up": While parsing the key "key:300": Invalid argument: unknown event code "300".
解决方案
常规映射工具不支持处理未知事件码,需直接通过evdev接口编写自定义程序实现拦截与转换,以下提供两种可行方案:
方法一:Python脚本(基于python-evdev库)
- 安装依赖
sudo apt install python3-evdev
- 编写映射脚本(命名为
event_remap.py)
from evdev import InputDevice, UInput, ecodes # 替换为你的控制器实际设备路径(可通过evtest确认) device_path = '/dev/input/eventX' dev = InputDevice(device_path) # 创建虚拟输入设备,复制原设备能力并添加KEY_F24支持 capabilities = dev.capabilities() if ecodes.EV_KEY in capabilities: capabilities[ecodes.EV_KEY].append(ecodes.KEY_F24) else: capabilities[ecodes.EV_KEY] = [ecodes.KEY_F24] ui = UInput(capabilities, name='Remapped Arcade Controller') # 循环处理事件 for event in dev.read_loop(): if event.type == ecodes.EV_KEY and event.code == 300: # 将无效码300转换为KEY_F24(194) ui.write(ecodes.EV_KEY, ecodes.KEY_F24, event.value) ui.syn() else: # 转发其他正常事件 ui.write(event.type, event.code, event.value) ui.syn()
- 运行脚本(需root权限)
sudo python3 event_remap.py
方法二:C语言程序(基于libevdev库,性能更优)
- 安装依赖
sudo apt install libevdev-dev
- 编写代码(命名为
remap_event.c)
#include <libevdev/libevdev.h> #include <libevdev/libevdev-uinput.h> #include <stdio.h> #include <unistd.h> #include <string.h> int main() { struct libevdev *dev = NULL; struct libevdev_uinput *uidev = NULL; int fd, rc; // 替换为你的控制器实际设备路径 fd = open("/dev/input/eventX", O_RDONLY); rc = libevdev_new_from_fd(fd, &dev); if (rc < 0) { fprintf(stderr, "初始化libevdev失败: %s\n", strerror(-rc)); return 1; } // 创建虚拟输入设备 rc = libevdev_uinput_create_from_device(dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &uidev); if (rc < 0) { fprintf(stderr, "创建虚拟输入设备失败: %s\n", strerror(-rc)); libevdev_free(dev); close(fd); return 1; } // 处理事件循环 struct input_event ev; while ((rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev)) == 0) { if (ev.type == EV_KEY && ev.code == 300) { ev.code = KEY_F24; libevdev_uinput_write_event(uidev, ev.type, ev.code, ev.value); } else { libevdev_uinput_write_event(uidev, ev.type, ev.code, ev.value); } libevdev_uinput_write_event(uidev, EV_SYN, SYN_REPORT, 0); } // 清理资源 libevdev_uinput_destroy(uidev); libevdev_free(dev); close(fd); return 0; }
- 编译并运行
gcc remap_event.c -o remap_event -levdev sudo ./remap_event
注意事项
- 务必将代码中的
/dev/input/eventX替换为控制器实际设备路径,可通过evtest或ls /dev/input/命令确认 - 程序运行需要root权限,因为操作输入设备需特殊系统权限
- 可将脚本/程序设置为开机自启,确保街机启动时自动加载事件映射
内容的提问来源于stack exchange,提问作者JettDc
相关产品推荐
相关产品推荐

