使用libusb库访问USB游戏控制器时遇设备打开错误
解决libusb打开游戏控制器时的"Error opening device"问题
我在基于libusb库开发游戏控制器输入数据获取程序时,遇到了"Error opening device"错误。已经确认VENDOR_ID和PRODUCT_ID正确,也更换过USB端口,但问题依旧。相关代码如下:
#include <stdio.h> #include "libusb-1.0.26/libusb-1.0.26/libusb/libusb.h" #define VENDOR_ID 0x045E // Replace with your controller's vendor ID #define PRODUCT_ID 0x028E // Replace with your controller's product ID #define FILENAME "controller_data.txt" int main() { libusb_device_handle *dev_handle; libusb_context *ctx = NULL; // Initialize libusb if (libusb_init(&ctx) < 0) { fprintf(stderr, "Error initializing libusb\n"); return 1; } // Open the device with the specified vendor and product IDs dev_handle = libusb_open_device_with_vid_pid(ctx, VENDOR_ID, PRODUCT_ID); if (dev_handle == NULL) { fprintf(stderr, "Error opening device\n"); libusb_exit(ctx); return 1; } // Claim the interface (assuming interface 0) if (libusb_claim_interface(dev_handle, 0) < 0) { fprintf(stderr, "Error claiming interface\n"); libusb_close(dev_handle); libusb_exit(ctx); return 1; } FILE *file = fopen(FILENAME, "w"); if (file == NULL) { fprintf(stderr, "Error opening file\n"); libusb_release_interface(dev_handle, 0); libusb_close(dev_handle); libusb_exit(ctx); return 1; } // Read data from the controller, print to console, and write to file unsigned char data[64]; int transferred; while (1) { int result = libusb_interrupt_transfer(dev_handle, 0x81, data, sizeof(data), &transferred, 0); if (result == 0) { // Process and print data to console for (int i = 0; i < transferred; ++i) { printf("%02X ", data[i]); } printf("\n"); // Write data to file fwrite(data, 1, transferred, file); fflush(file); } else { fprintf(stderr, "Error reading data: %d\n", result); break; } } // Release the interface, close the device, and close the file libusb_release_interface(dev_handle, 0); libusb_close(dev_handle); fclose(file); // Deinitialize libusb libusb_exit(ctx); return 0; }
可能的原因及解决方法
权限不足:
多数系统中普通用户无直接访问USB设备的权限:- Linux:创建
/etc/udev/rules.d/99-controller.rules文件,写入:
执行SUBSYSTEM=="usb", ATTRS{idVendor}=="045e", ATTRS{idProduct}=="028e", MODE="0666"sudo udevadm control --reload-rules && sudo udevadm trigger,重启程序或重新插拔设备。 - Windows:用Zadig工具将控制器的默认HID驱动替换为libusb兼容驱动,避免系统驱动占用设备。
- macOS:尝试用
sudo运行程序,或在「安全性与隐私」中授予程序USB访问权限。
- Linux:创建
设备被其他进程占用:
关闭Steam、游戏客户端、系统自带的控制器管理工具等可能占用设备的程序,再重试。接口/端点号错误:
代码默认使用接口0和端点0x81,但部分控制器的输入接口不是0。用lsusb -v(Linux)或Zadig(Windows)查看设备实际的接口和端点信息,修改对应参数。libusb路径/链接问题:
代码中嵌套的头文件路径容易导致编译/运行错误,建议将libusb安装到系统默认路径,编译时用gcc -o controller controller.c -lusb-1.0指定链接库。设备兼容性问题:
部分控制器用专有协议,先用libusb_list_devices枚举设备,确认libusb能识别到目标设备,检查设备配置和接口状态。
优化后的代码(增加错误排查细节)
#include <stdio.h> #include <libusb-1.0/libusb.h> #define VENDOR_ID 0x045E // 替换为你的控制器厂商ID #define PRODUCT_ID 0x028E // 替换为你的控制器产品ID #define FILENAME "controller_data.txt" int main() { libusb_device_handle *dev_handle; libusb_context *ctx = NULL; int r; // 初始化libusb并开启调试日志 r = libusb_init(&ctx); if (r < 0) { fprintf(stderr, "初始化libusb失败: %s\n", libusb_error_name(r)); return 1; } libusb_set_debug(ctx, 3); // 打开设备 dev_handle = libusb_open_device_with_vid_pid(ctx, VENDOR_ID, PRODUCT_ID); if (dev_handle == NULL) { fprintf(stderr, "打开设备失败,请检查权限或驱动\n"); libusb_exit(ctx); return 1; } // 分离占用设备的内核驱动(如果存在) if (libusb_kernel_driver_active(dev_handle, 0)) { r = libusb_detach_kernel_driver(dev_handle, 0); if (r < 0) { fprintf(stderr, "分离内核驱动失败: %s\n", libusb_error_name(r)); libusb_close(dev_handle); libusb_exit(ctx); return 1; } } // 声明接口 r = libusb_claim_interface(dev_handle, 0); if (r < 0) { fprintf(stderr, "声明接口失败: %s\n", libusb_error_name(r)); libusb_close(dev_handle); libusb_exit(ctx); return 1; } FILE *file = fopen(FILENAME, "w"); if (file == NULL) { perror("打开文件失败"); libusb_release_interface(dev_handle, 0); libusb_close(dev_handle); libusb_exit(ctx); return 1; } unsigned char data[64]; int transferred; while (1) { r = libusb_interrupt_transfer(dev_handle, 0x81, data, sizeof(data), &transferred, 1000); if (r == 0) { for (int i = 0; i < transferred; ++i) { printf("%02X ", data[i]); } printf("\n"); fwrite(data, 1, transferred, file); fflush(file); } else if (r == LIBUSB_ERROR_TIMEOUT) { // 超时属于正常情况,继续等待输入 continue; } else { fprintf(stderr, "读取数据失败: %s\n", libusb_error_name(r)); break; } } // 清理资源,恢复内核驱动 libusb_release_interface(dev_handle, 0); libusb_attach_kernel_driver(dev_handle, 0); libusb_close(dev_handle); fclose(file); libusb_exit(ctx); return 0; }
内容的提问来源于stack exchange,提问作者Quanta
相关产品推荐
相关产品推荐

