usbhid_remap.txt 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. /*
  2. * usbhid_remap.c
  3. *
  4. * 功能:捕获 USB HID 键盘原始数据,重映射后通过 uinput 注入系统
  5. * 编译:gcc -o usbhid_remap usbhid_remap.c -lusb-1.0 -Wall -O2
  6. * 运行:sudo ./usbhid_remap
  7. */
  8. #define _GNU_SOURCE
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <stdint.h>
  13. #include <unistd.h>
  14. #include <signal.h>
  15. #include <errno.h>
  16. #include <fcntl.h>
  17. #include <linux/input.h>
  18. #include <linux/uinput.h>
  19. #include <libusb-1.0/libusb.h>
  20. #define VENDOR_ID 0x258a // SINO WEALTH
  21. #define PRODUCT_ID 0x002a // Keyboard
  22. #define INTERFACE 0 // 标准键盘接口
  23. #define ENDPOINT 0x81 // 输入端点
  24. #define HID_REPORT_SIZE 8
  25. #define MAX_KEYS 6
  26. // 运行标志
  27. volatile int running = 1;
  28. int uinput_fd = -1;
  29. // 当前按键状态(用于检测变化)
  30. uint8_t prev_keys[MAX_KEYS] = {0};
  31. uint8_t curr_keys[MAX_KEYS] = {0};
  32. // 修饰键状态
  33. uint8_t prev_mods = 0;
  34. uint8_t curr_mods = 0;
  35. // 信号处理
  36. void signal_handler(int sig) {
  37. running = 0;
  38. }
  39. // USB HID Usage ID 到 Linux 键码的标准映射
  40. static const int hid_to_linux[256] = {
  41. [0x00]=0, [0x01]=KEY_F1, [0x02]=KEY_F2, [0x03]=KEY_F3, [0x04]=KEY_F4, [0x05]=KEY_F5, [0x06]=KEY_F6, [0x07]=KEY_F7, [0x08]=KEY_F8, [0x09]=KEY_F9, [0x0A]=KEY_F10, [0x0B]=KEY_F11, [0x0C]=KEY_F12, [0x0D]=KEY_SYSRQ, [0x0E]=KEY_SCROLLLOCK, [0x0F]=KEY_ESC,
  42. [0x10]=KEY_GRAVE, [0x11]=KEY_1, [0x12]=KEY_2, [0x13]=KEY_3, [0x14]=KEY_4, [0x15]=KEY_5, [0x16]=KEY_6, [0x17]=KEY_7, [0x18]=KEY_8, [0x19]=KEY_9, [0x1A]=KEY_0, [0x1B]=KEY_MINUS, [0x1C]=KEY_EQUAL, [0x1D]=KEY_BACKSPACE, [0x1E]=KEY_INSERT, [0x1F]=KEY_HOME,
  43. [0x20]=KEY_TAB, [0x21]=KEY_Q, [0x22]=KEY_W, [0x23]=KEY_E, [0x24]=KEY_R, [0x25]=KEY_T, [0x26]=KEY_Y, [0x27]=KEY_U, [0x28]=KEY_I, [0x29]=KEY_O, [0x2A]=KEY_P, [0x2B]=KEY_LEFTBRACE, [0x2C]=KEY_RIGHTBRACE, [0x2D]=KEY_BACKSLASH, [0x2E]=KEY_DELETE, [0x2F]=KEY_END,
  44. [0x30]=KEY_CAPSLOCK, [0x31]=KEY_A, [0x32]=KEY_S, [0x33]=KEY_D, [0x34]=KEY_F, [0x35]=KEY_G, [0x36]=KEY_H, [0x37]=KEY_J, [0x38]=KEY_K, [0x39]=KEY_L, [0x3A]=KEY_SEMICOLON, [0x3B]=KEY_APOSTROPHE, [0x3C]=KEY_ENTER, [0x3D]=KEY_4, [0x3E]=KEY_5, [0x3F]=KEY_6,
  45. [0x40]=KEY_LEFTSHIFT, [0x41]=KEY_Z, [0x42]=KEY_X, [0x43]=KEY_C, [0x44]=KEY_V, [0x45]=KEY_B, [0x46]=KEY_N, [0x47]=KEY_M, [0x48]=KEY_COMMA, [0x49]=KEY_DOT, [0x4A]=KEY_SLASH, [0x4B]=KEY_RIGHTSHIFT, [0x4C]=KEY_UP, [0x4D]=KEY_1, [0x4E]=KEY_2, [0x4F]=KEY_3,
  46. [0x50]=KEY_LEFTCTRL, [0x51]=KEY_LEFTMETA, [0x52]=KEY_LEFTALT, [0x53]=KEY_SPACE, [0x54]=KEY_RIGHTALT, [0x55]=KEY_RIGHTMETA, [0x56]=KEY_COMPOSE, [0x57]=KEY_RIGHTCTRL, [0x58]=KEY_LEFT, [0x59]=KEY_DOWN, [0x5A]=KEY_RIGHT, [0x5B]=KEY_0, [0x5C]=KEY_DOT, [0x5D]=KEY_ENTER, [0x5E]=KEY_E, [0x5F]=KEY_F,
  47. [0x60]=KEY_0, [0x61]=KEY_1, [0x62]=KEY_2, [0x63]=KEY_3, [0x64]=KEY_4, [0x65]=KEY_5, [0x66]=KEY_6, [0x67]=KEY_7, [0x68]=KEY_8, [0x69]=KEY_9, [0x6A]=KEY_A, [0x6B]=KEY_B, [0x6C]=KEY_C, [0x6D]=KEY_D, [0x6E]=KEY_E, [0x6F]=KEY_F,
  48. [0x70]=KEY_0, [0x71]=KEY_1, [0x72]=KEY_2, [0x73]=KEY_3, [0x74]=KEY_4, [0x75]=KEY_5, [0x76]=KEY_6, [0x77]=KEY_7, [0x78]=KEY_8, [0x79]=KEY_9, [0x7A]=KEY_A, [0x7B]=KEY_B, [0x7C]=KEY_C, [0x7D]=KEY_D, [0x7E]=KEY_E, [0x7F]=KEY_F,
  49. };
  50. #if 0
  51. // USB HID Usage ID 到 Linux 键码的标准映射
  52. static const int hid_to_linux[256] = {
  53. [0x00]=0, [0x01] = KEY_ESC, [0x02] = KEY_1, [0x03] = KEY_2, [0x04] = KEY_3, [0x05] = KEY_4,
  54. [0x06] = KEY_5, [0x07] = KEY_6, [0x08] = KEY_7, [0x09] = KEY_8,
  55. [0x0A] = KEY_9, [0x0B] = KEY_0,
  56. [0x0C] = KEY_MINUS, [0x0D] = KEY_EQUAL, [0x0E] = KEY_BACKSPACE,
  57. [0x0F] = KEY_TAB, [0x10] = KEY_Q, [0x11] = KEY_W, [0x12] = KEY_E,
  58. [0x13] = KEY_R, [0x14] = KEY_T, [0x15] = KEY_Y, [0x16] = KEY_U,
  59. [0x17] = KEY_I, [0x18] = KEY_O, [0x19] = KEY_P,
  60. [0x1A] = KEY_LEFTBRACE, [0x1B] = KEY_RIGHTBRACE, [0x1C] = KEY_ENTER,
  61. [0x1D] = KEY_LEFTCTRL, [0x1E] = KEY_A, [0x1F] = KEY_S,
  62. [0x20] = KEY_D, [0x21] = KEY_F, [0x22] = KEY_G, [0x23] = KEY_H,
  63. [0x24] = KEY_J, [0x25] = KEY_K, [0x26] = KEY_L,
  64. [0x27] = KEY_SEMICOLON, [0x28] = KEY_APOSTROPHE, [0x29] = KEY_GRAVE,
  65. [0x2A] = KEY_LEFTSHIFT, [0x2B] = KEY_BACKSLASH,
  66. [0x2C] = KEY_Z, [0x2D] = KEY_X, [0x2E] = KEY_C, [0x2F] = KEY_V,
  67. [0x30] = KEY_B, [0x31] = KEY_N, [0x32] = KEY_M,
  68. [0x33] = KEY_COMMA, [0x34] = KEY_DOT, [0x35] = KEY_SLASH,
  69. [0x36] = KEY_RIGHTSHIFT, [0x37] = KEY_KPASTERISK,
  70. [0x38] = KEY_LEFTALT, [0x39] = KEY_SPACE, [0x3A] = KEY_CAPSLOCK,
  71. [0x3B] = KEY_F1, [0x3C] = KEY_F2, [0x3D] = KEY_F3, [0x3E] = KEY_F4,
  72. [0x3F] = KEY_F5, [0x40] = KEY_F6, [0x41] = KEY_F7, [0x42] = KEY_F8,
  73. [0x43] = KEY_F9, [0x44] = KEY_F10, [0x45] = KEY_F11, [0x46] = KEY_F12,
  74. [0x47] = KEY_SYSRQ, [0x48] = KEY_SCROLLLOCK, [0x49] = KEY_PAUSE,
  75. [0x4A] = KEY_INSERT, [0x4B] = KEY_HOME, [0x4C] = KEY_PAGEUP,
  76. [0x4D] = KEY_DELETE, [0x4E] = KEY_END, [0x4F] = KEY_PAGEDOWN,
  77. [0x50] = KEY_RIGHT, [0x51] = KEY_LEFT, [0x52] = KEY_DOWN, [0x53] = KEY_UP,
  78. [0x54] = KEY_NUMLOCK, [0x55] = KEY_KPSLASH, [0x56] = KEY_KPASTERISK,
  79. [0x57] = KEY_KPMINUS, [0x58] = KEY_KPPLUS, [0x59] = KEY_KPENTER,
  80. [0x5A] = KEY_KP1, [0x5B] = KEY_KP2, [0x5C] = KEY_KP3, [0x5D] = KEY_KP4,
  81. [0x5E] = KEY_KP5, [0x5F] = KEY_KP6, [0x60] = KEY_KP7, [0x61] = KEY_KP8,
  82. [0x62] = KEY_KP9, [0x63] = KEY_KP0, [0x64] = KEY_KPDOT,
  83. [0x65] = KEY_102ND,[0x66] = KEY_102ND,[0x67] = KEY_102ND,[0x68] = KEY_102ND,
  84. [0x69] = KEY_102ND,[0x6a] = KEY_102ND,[0x6b] = KEY_102ND,[0x6c] = KEY_102ND,
  85. [0x6d] = KEY_102ND,[0x6e] = KEY_102ND,[0x6f] = KEY_102ND,
  86. [0x70] = KEY_102ND,[0x71] = KEY_102ND,[0x72] = KEY_102ND,[0x73] = KEY_102ND,
  87. [0x74] = KEY_102ND,[0x75] = KEY_102ND,[0x76] = KEY_102ND,[0x77] = KEY_102ND,
  88. [0x78] = KEY_102ND,[0x79] = KEY_102ND,[0x7a] = KEY_102ND,[0x7b] = KEY_102ND,
  89. [0x7c] = KEY_102ND,[0x7d] = KEY_102ND,[0x7e] = KEY_102ND,[0x7f] = KEY_102ND,
  90. [0xE0] = KEY_LEFTCTRL, [0xE1] = KEY_LEFTSHIFT, [0xE2] = KEY_LEFTALT,
  91. [0xE3] = KEY_LEFTMETA, [0xE4] = KEY_RIGHTCTRL, [0xE5] = KEY_RIGHTSHIFT,
  92. [0xE6] = KEY_RIGHTALT, [0xE7] = KEY_RIGHTMETA,
  93. };
  94. #endif
  95. // 自定义重映射表(覆盖标准映射)
  96. // 修改这里来改变按键映射
  97. static const int custom_remap[256] = {
  98. // 示例:将 0x31 和 0x32 重新映射
  99. // [0x31] = KEY_RIGHTBRACE, // 取消注释并修改为你需要的键
  100. // [0x32] = KEY_BACKSLASH, // 取消注释并修改为你需要的键
  101. // 默认:0 表示使用标准映射
  102. [0 ... 255] = 0,
  103. };
  104. // 修饰键位定义
  105. #define MOD_LCTRL 0x01
  106. #define MOD_LSHIFT 0x02
  107. #define MOD_LALT 0x04
  108. #define MOD_LMETA 0x08
  109. #define MOD_RCTRL 0x10
  110. #define MOD_RSHIFT 0x20
  111. #define MOD_RALT 0x40
  112. #define MOD_RMETA 0x80
  113. // 获取映射后的键码
  114. int get_mapped_key(int hid_code) {
  115. if (hid_code < 0 || hid_code > 255) return 0;
  116. if (custom_remap[hid_code] != 0) return custom_remap[hid_code];
  117. return hid_to_linux[hid_code];
  118. }
  119. // 初始化 uinput 设备
  120. int init_uinput(void) {
  121. int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
  122. if (fd < 0) {
  123. perror("Failed to open /dev/uinput");
  124. return -1;
  125. }
  126. struct uinput_setup setup;
  127. memset(&setup, 0, sizeof(setup));
  128. // 设置设备信息
  129. snprintf(setup.name, UINPUT_MAX_NAME_SIZE, "USB HID Remapped Keyboard");
  130. setup.id.bustype = BUS_USB;
  131. setup.id.vendor = VENDOR_ID;
  132. setup.id.product = PRODUCT_ID;
  133. setup.id.version = 1;
  134. // 启用事件类型
  135. if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0) goto error;
  136. if (ioctl(fd, UI_SET_EVBIT, EV_SYN) < 0) goto error;
  137. if (ioctl(fd, UI_SET_EVBIT, EV_MSC) < 0) goto error;
  138. if (ioctl(fd, UI_SET_MSCBIT, MSC_SCAN) < 0) goto error;
  139. // 启用所有键
  140. for (int i = 0; i < 256; i++) {
  141. if (ioctl(fd, UI_SET_KEYBIT, i) < 0) goto error;
  142. }
  143. // 创建设备
  144. if (ioctl(fd, UI_DEV_SETUP, &setup) < 0) goto error;
  145. if (ioctl(fd, UI_DEV_CREATE) < 0) goto error;
  146. printf("uinput device created: %s\n", setup.name);
  147. return fd;
  148. error:
  149. perror("uinput setup failed");
  150. close(fd);
  151. return -1;
  152. }
  153. // 销毁 uinput 设备
  154. void destroy_uinput(int fd) {
  155. if (fd < 0) return;
  156. ioctl(fd, UI_DEV_DESTROY);
  157. close(fd);
  158. printf("uinput device destroyed\n");
  159. }
  160. // 发送按键事件
  161. void send_key_event(int fd, int code, int value, int scan_code) {
  162. struct input_event ev;
  163. // MSC_SCAN 事件(原始扫描码)
  164. if (scan_code >= 0) {
  165. memset(&ev, 0, sizeof(ev));
  166. gettimeofday(&ev.time, NULL);
  167. ev.type = EV_MSC;
  168. ev.code = MSC_SCAN;
  169. ev.value = scan_code;
  170. write(fd, &ev, sizeof(ev));
  171. }
  172. // KEY 事件
  173. memset(&ev, 0, sizeof(ev));
  174. gettimeofday(&ev.time, NULL);
  175. ev.type = EV_KEY;
  176. ev.code = code;
  177. ev.value = value;
  178. write(fd, &ev, sizeof(ev));
  179. // SYN 事件
  180. memset(&ev, 0, sizeof(ev));
  181. gettimeofday(&ev.time, NULL);
  182. ev.type = EV_SYN;
  183. ev.code = SYN_REPORT;
  184. ev.value = 0;
  185. write(fd, &ev, sizeof(ev));
  186. }
  187. // 发送修饰键事件
  188. void send_modifier_events(int fd, uint8_t prev, uint8_t curr) {
  189. struct {
  190. uint8_t mask;
  191. int keycode;
  192. } mods[] = {
  193. {MOD_LCTRL, KEY_LEFTCTRL}, {MOD_LSHIFT, KEY_LEFTSHIFT},
  194. {MOD_LALT, KEY_LEFTALT}, {MOD_LMETA, KEY_LEFTMETA},
  195. {MOD_RCTRL, KEY_RIGHTCTRL}, {MOD_RSHIFT, KEY_RIGHTSHIFT},
  196. {MOD_RALT, KEY_RIGHTALT}, {MOD_RMETA, KEY_RIGHTMETA},
  197. };
  198. for (int i = 0; i < 8; i++) {
  199. uint8_t mask = mods[i].mask;
  200. int prev_state = (prev & mask) ? 1 : 0;
  201. int curr_state = (curr & mask) ? 1 : 0;
  202. if (prev_state != curr_state) {
  203. printf(" Modifier %s: %s\n",
  204. mods[i].keycode == KEY_LEFTCTRL ? "LCtrl" :
  205. mods[i].keycode == KEY_LEFTSHIFT ? "LShift" :
  206. mods[i].keycode == KEY_LEFTALT ? "LAlt" :
  207. mods[i].keycode == KEY_LEFTMETA ? "LMeta" :
  208. mods[i].keycode == KEY_RIGHTCTRL ? "RCtrl" :
  209. mods[i].keycode == KEY_RIGHTSHIFT ? "RShift" :
  210. mods[i].keycode == KEY_RIGHTALT ? "RAlt" : "RMeta",
  211. curr_state ? "DOWN" : "UP");
  212. send_key_event(fd, mods[i].keycode, curr_state, -1);
  213. }
  214. }
  215. }
  216. // 处理 HID 报告
  217. void process_hid_report(int fd, const uint8_t *data, int len) {
  218. if (len < 8) return;
  219. curr_mods = data[0];
  220. // 提取按键(去重并排序)
  221. int key_count = 0;
  222. memset(curr_keys, 0, sizeof(curr_keys));
  223. for (int i = 2; i < 8 && key_count < MAX_KEYS; i++) {
  224. if (data[i] != 0) {
  225. // 检查是否已存在
  226. int exists = 0;
  227. for (int j = 0; j < key_count; j++) {
  228. if (curr_keys[j] == data[i]) { exists = 1; break; }
  229. }
  230. if (!exists) curr_keys[key_count++] = data[i];
  231. }
  232. }
  233. // 打印原始数据
  234. printf("Raw HID: ");
  235. for (int i = 0; i < len; i++) printf("%02X ", data[i]);
  236. printf("\n");
  237. // 处理修饰键变化
  238. if (prev_mods != curr_mods) {
  239. send_modifier_events(fd, prev_mods, curr_mods);
  240. }
  241. // 找出释放的键(在 prev 中但不在 curr 中)
  242. for (int i = 0; i < MAX_KEYS; i++) {
  243. if (prev_keys[i] == 0) continue;
  244. int found = 0;
  245. for (int j = 0; j < MAX_KEYS; j++) {
  246. if (curr_keys[j] == prev_keys[i]) { found = 1; break; }
  247. }
  248. if (!found) {
  249. int mapped = get_mapped_key(prev_keys[i]);
  250. if (mapped > 0) {
  251. printf(" Key UP: HID_%02X -> Linux_%d (%s)\n",
  252. prev_keys[i], mapped,
  253. mapped == KEY_A ? "A" : mapped == KEY_B ? "B" :
  254. mapped == KEY_ENTER ? "Enter" : mapped == KEY_SPACE ? "Space" :
  255. mapped == KEY_BACKSLASH ? "Backslash" :
  256. mapped == KEY_RIGHTBRACE ? "RightBrace" : "Other");
  257. send_key_event(fd, mapped, 0, 0x70000 | prev_keys[i]);
  258. }
  259. }
  260. }
  261. // 找出按下的键(在 curr 中但不在 prev 中)
  262. for (int i = 0; i < MAX_KEYS; i++) {
  263. if (curr_keys[i] == 0) continue;
  264. int found = 0;
  265. for (int j = 0; j < MAX_KEYS; j++) {
  266. if (prev_keys[j] == curr_keys[i]) { found = 1; break; }
  267. }
  268. if (!found) {
  269. int mapped = get_mapped_key(curr_keys[i]);
  270. if (mapped > 0) {
  271. const char *remap_note = (custom_remap[curr_keys[i]] != 0) ? " [REMAPPED]" : "";
  272. printf(" Key DOWN: HID_%02X -> Linux_%d (%s)%s\n",
  273. curr_keys[i], mapped,
  274. mapped == KEY_A ? "A" : mapped == KEY_B ? "B" :
  275. mapped == KEY_ENTER ? "Enter" : mapped == KEY_SPACE ? "Space" :
  276. mapped == KEY_BACKSLASH ? "Backslash" :
  277. mapped == KEY_RIGHTBRACE ? "RightBrace" : "Other",
  278. remap_note);
  279. send_key_event(fd, mapped, 1, 0x70000 | curr_keys[i]);
  280. } else {
  281. printf(" Key DOWN: HID_%02X -> (unmapped, ignored)\n", curr_keys[i]);
  282. }
  283. }
  284. }
  285. // 保存当前状态
  286. prev_mods = curr_mods;
  287. memcpy(prev_keys, curr_keys, sizeof(curr_keys));
  288. }
  289. // 打印用法
  290. void print_usage(const char *prog) {
  291. printf("Usage: %s [options]\n", prog);
  292. printf("Options:\n");
  293. printf(" -v VID Set vendor ID (hex, default: %04X)\n", VENDOR_ID);
  294. printf(" -p PID Set product ID (hex, default: %04X)\n", PRODUCT_ID);
  295. printf(" -i IFACE Set interface (default: %d)\n", INTERFACE);
  296. printf(" -d Detach kernel driver only, don't capture\n");
  297. printf(" -h Show this help\n");
  298. printf("\nExample:\n");
  299. printf(" sudo %s -v 258a -p 002a\n", prog);
  300. }
  301. int main(int argc, char *argv[]) {
  302. libusb_context *ctx = NULL;
  303. libusb_device_handle *handle = NULL;
  304. int ret;
  305. int opt;
  306. uint16_t vid = VENDOR_ID;
  307. uint16_t pid = PRODUCT_ID;
  308. int iface = INTERFACE;
  309. int detach_only = 0;
  310. // 解析参数
  311. while ((opt = getopt(argc, argv, "v:p:i:dh")) != -1) {
  312. switch (opt) {
  313. case 'v': vid = strtol(optarg, NULL, 16); break;
  314. case 'p': pid = strtol(optarg, NULL, 16); break;
  315. case 'i': iface = atoi(optarg); break;
  316. case 'd': detach_only = 1; break;
  317. case 'h': print_usage(argv[0]); return 0;
  318. default: print_usage(argv[0]); return 1;
  319. }
  320. }
  321. printf("=== USB HID Remapper ===\n");
  322. printf("Target: VID=%04X PID=%04X Interface=%d\n", vid, pid, iface);
  323. // 设置信号处理
  324. signal(SIGINT, signal_handler);
  325. signal(SIGTERM, signal_handler);
  326. // 初始化 libusb
  327. ret = libusb_init(&ctx);
  328. if (ret < 0) {
  329. fprintf(stderr, "libusb_init failed: %s\n", libusb_error_name(ret));
  330. return 1;
  331. }
  332. // 打开设备
  333. handle = libusb_open_device_with_vid_pid(ctx, vid, pid);
  334. if (!handle) {
  335. fprintf(stderr, "Failed to open device %04X:%04X\n", vid, pid);
  336. fprintf(stderr, "Check device connection and permissions (try sudo)\n");
  337. libusb_exit(ctx);
  338. return 1;
  339. }
  340. // 检查并分离内核驱动
  341. if (libusb_kernel_driver_active(handle, iface) == 1) {
  342. printf("Detaching kernel driver...\n");
  343. ret = libusb_detach_kernel_driver(handle, iface);
  344. if (ret < 0) {
  345. fprintf(stderr, "Failed to detach driver: %s\n", libusb_error_name(ret));
  346. libusb_close(handle);
  347. libusb_exit(ctx);
  348. return 1;
  349. }
  350. }
  351. if (detach_only) {
  352. printf("Kernel driver detached. Press Enter to reattach and exit...");
  353. getchar();
  354. libusb_attach_kernel_driver(handle, iface);
  355. libusb_close(handle);
  356. libusb_exit(ctx);
  357. return 0;
  358. }
  359. // 声明接口
  360. ret = libusb_claim_interface(handle, iface);
  361. if (ret < 0) {
  362. fprintf(stderr, "Failed to claim interface: %s\n", libusb_error_name(ret));
  363. libusb_attach_kernel_driver(handle, iface);
  364. libusb_close(handle);
  365. libusb_exit(ctx);
  366. return 1;
  367. }
  368. // 初始化 uinput
  369. uinput_fd = init_uinput();
  370. if (uinput_fd < 0) {
  371. libusb_release_interface(handle, iface);
  372. libusb_attach_kernel_driver(handle, iface);
  373. libusb_close(handle);
  374. libusb_exit(ctx);
  375. return 1;
  376. }
  377. printf("Capturing... Press Ctrl+C to exit\n\n");
  378. // 主循环
  379. uint8_t data[HID_REPORT_SIZE];
  380. int transferred;
  381. while (running) {
  382. ret = libusb_interrupt_transfer(handle, ENDPOINT | LIBUSB_ENDPOINT_IN,
  383. data, sizeof(data), &transferred, 100);
  384. if (ret == LIBUSB_ERROR_TIMEOUT) {
  385. continue; // 正常超时,检查 running 标志
  386. } else if (ret == LIBUSB_ERROR_NO_DEVICE) {
  387. printf("Device disconnected\n");
  388. break;
  389. } else if (ret < 0) {
  390. if (running) fprintf(stderr, "Transfer error: %s\n", libusb_error_name(ret));
  391. usleep(10000);
  392. continue;
  393. }
  394. if (transferred > 0) {
  395. process_hid_report(uinput_fd, data, transferred);
  396. fflush(stdout);
  397. }
  398. }
  399. printf("\nShutting down...\n");
  400. // 清理
  401. destroy_uinput(uinput_fd);
  402. libusb_release_interface(handle, iface);
  403. ret = libusb_attach_kernel_driver(handle, iface);
  404. if (ret < 0) {
  405. printf("Warning: Could not reattach kernel driver: %s\n", libusb_error_name(ret));
  406. } else {
  407. printf("Kernel driver reattached\n");
  408. }
  409. libusb_close(handle);
  410. libusb_exit(ctx);
  411. return 0;
  412. }