You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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访问权限。
  • 设备被其他进程占用:
    关闭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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 14:35:05