Qt获取hid设备信息

发布于:2025-07-22 ⋅ 阅读:(16) ⋅ 点赞:(0)

Qt 中通过 HID(Human Interface Device)接口获取指定的 USB 设备,并读取其数据。资源文件中包含了 hidapi.h、hidapi.dll 和 hidapi.lib。通过这些文件,您可以在 Qt 项目中实现对 USB 设备的 HID 接口调用。

#include <QObject>
// #include <hidapi.h>
#include <QMap>
#include <QTimer>

class GameControllerHID : public QObject
{
    Q_OBJECT
public:
    explicit GameControllerHID(QObject *parent = nullptr);
    ~GameControllerHID();

    // 尝试连接游戏控制器
    Q_INVOKABLE bool connectController(unsigned short vendorId = 0, unsigned short productId = 0);
    Q_INVOKABLE void disconnectController();
    Q_INVOKABLE bool isConnected() const;

    // 按钮状态查询
    Q_INVOKABLE bool buttonState(int buttonId) const;
    Q_INVOKABLE QMap<int, bool> allButtonStates() const;

    // 摇杆状态查询 (返回 -1.0 到 1.0 的范围)
    Q_INVOKABLE double axisState(int axisId) const;
    Q_INVOKABLE QMap<int, double> allAxisStates() const;

    // 设置轮询间隔 (毫秒)
    Q_INVOKABLE void setPollInterval(int interval);

signals:
    void controllerConnected();
    void controllerDisconnected();
    void buttonStateChanged(int buttonId, bool pressed);
    void axisStateChanged(int axisId, double value);
    void rawDataReceived(const QByteArray &data);

private slots:
    void pollController();

private:
    bool parseInputReport(const unsigned char *data, size_t length);
    void setupDefaultMapping();

    hid_device *m_device;
    QTimer *m_pollTimer;
    bool m_isConnected;

    // 设备信息
    unsigned short m_vendorId;
    unsigned short m_productId;
    QString m_manufacturer;
    QString m_product;

    // 输入状态
    QMap<int, bool> m_buttonStates;
    QMap<int, double> m_axisStates;

    // 输入报告缓冲区
    unsigned char *m_inputReportBuffer;
    size_t m_inputReportLength;

    // 设备映射配置
    struct AxisMapping {
        int byteOffset;
        int bitOffset;
        bool isSigned;
        double scale;
        double offset;
    };

    struct ButtonMapping {
        int byteOffset;
        int bitMask;
    };

    std::thread m_readThd;
    std::atomic_bool m_isStopThd = false;

    QMap<int, AxisMapping> m_axisMappings;
    QMap<int, ButtonMapping> m_buttonMappings;

    // bool isBut13StatChged = false;
};


bool GameControllerHID::connectController(unsigned short vendorId, unsigned short productId)
{
    if (m_isConnected) {
        disconnectController();
    }

    // 如果未指定VID/PID,尝试查找第一个游戏控制器
    if (vendorId == 0 || productId == 0) {

        struct hid_device_info *devs = hid_enumerate(0, 0);
        struct hid_device_info *cur_dev = devs;

        while (cur_dev) {
            // 简单判断是否是游戏控制器 (可根据需要调整)
            if (cur_dev->usage_page == 1 && cur_dev->usage == 5) {
                vendorId = cur_dev->vendor_id;
                productId = cur_dev->product_id;
                break;
            }
            cur_dev = cur_dev->next;
        }

        hid_free_enumeration(devs);

        if (vendorId == 0 || productId == 0) {
            qWarning() << "No game controller found";
            return false;
        }
    }

    // 打开设备
    m_device = hid_open(vendorId, productId, nullptr);
    if (!m_device) {
        qWarning() << "Failed to open HID device" << QString::number(vendorId, 16) << QString::number(productId, 16);
        return false;
    }


    // 获取设备信息
    wchar_t wstr[256];
    if (hid_get_manufacturer_string(m_device, wstr, 256) >= 0) {
        m_manufacturer = QString::fromWCharArray(wstr);
    }
    if (hid_get_product_string(m_device, wstr, 256) >= 0) {
        m_product = QString::fromWCharArray(wstr);
    }

    m_vendorId = vendorId;
    m_productId = productId;
    m_isConnected = true;

    // 设置默认映射 (需要根据实际控制器调整)
    setupDefaultMapping();

    // 开始轮询
    // m_pollTimer->start();

    emit controllerConnected();
    return true;
}

初始化 HID API: 在调用 HID 接口之前,首先需要初始化 HID API。

int res;
res = hid_init();

打开设备: 使用设备的 VID(Vendor ID)和 PID(Product ID)打开指定的 USB 设备。

wchar_t wstr[MAX_STR];
int i;
// Open the device using the VID, PID, and optionally the Serial number.
handle = hid_open(0x0483, 0x5750, NULL);
if(handle == NULL)
{
    qDebug() << "NULL-----------------------NULL";
    return;
}
else
{
    qDebug() << "not ------------NULL-----------------------NULL";
}

读取设备信息: 读取设备的制造商字符串、产品字符串和序列号字符串。

// Read the Manufacturer String
res = hid_get_manufacturer_string(handle, wstr, MAX_STR);
wprintf(L"Manufacturer String: %s\n", wstr);
 
// Read the Product String
res = hid_get_product_string(handle, wstr, MAX_STR);
wprintf(L"Product String: %s\n", wstr);
 
// Read the Serial Number String
res = hid_get_serial_number_string(handle, wstr, MAX_STR);
wprintf(L"Serial Number String: (%d) %s\n", wstr[0], wstr);
 
// Read Indexed String 1
res = hid_get_indexed_string(handle, 1, wstr, MAX_STR);
wprintf(L"Indexed String 1: %s\n", wstr);

读取数据: 设置非阻塞模式并循环读取设备数据。

qDebug("hid read start");
int res = hid_set_nonblocking(handle, 0);
while (1)
{
    res = hid_read(handle, buf, sizeof(buf));
    QString asd;
    for(int i = 0; i < sizeof(buf); i++)
    {
        char str[20];
        sprintf(str, "%02x", buf[i]);
        asd += str;
    }
    if(!cardInfo.contains(asd.toUpper()))
    {
        cardInfo.append(asd.toUpper());
        for(int i = 0; i < cardInfo.size(); i++)
        {
            dealWithData(cardInfo[i]);
        }
    }
}

注意事项

  • 适用于 Windows 10 系统,使用 MSVC编译的 Release 版本。
  • 在使用过程中,请确保设备的 VID 和 PID 正确无误。
  • 读取数据时,建议使用非阻塞模式以避免程序卡死。

网站公告

今日签到

点亮在社区的每一天
去签到