usbhid_remap.c 18 KB

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