#include "MID/Mid_Def.h" #include #include #include #include #include #include #pragma comment(lib, "hid.lib") #pragma comment(lib, "setupapi.lib") namespace { QString Mid_GetDeviceInstanceId(HDEVINFO DeviceInfoSet, SP_DEVINFO_DATA* p_DeviceInfoData) { DWORD NeedLength = 0; SetupDiGetDeviceInstanceIdW( DeviceInfoSet, p_DeviceInfoData, nullptr, 0, &NeedLength); if (NeedLength == 0) { return QString(); } QVector Buffer(static_cast(NeedLength) + 1, 0); return SetupDiGetDeviceInstanceIdW( DeviceInfoSet, p_DeviceInfoData, Buffer.data(), static_cast(Buffer.size()), nullptr) ? QString::fromWCharArray(Buffer.constData()).trimmed() : QString(); } } // namespace // Find the HID interface that matches VID/PID plus usage page/usage. bool Mid_FindHidInterface( const Mid_Struct_DeviceMatch& Match, QString* p_DevicePath, quint16* p_InputLength, quint16* p_OutputLength, QString* p_DeviceInstanceId) { GUID HidGuid; HidD_GetHidGuid(&HidGuid); HDEVINFO DeviceInfoSet = SetupDiGetClassDevsW(&HidGuid, nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (DeviceInfoSet == INVALID_HANDLE_VALUE) { return false; } bool IsFound = false; SP_DEVICE_INTERFACE_DATA InterfaceData = {}; InterfaceData.cbSize = sizeof(InterfaceData); for (DWORD Index = 0; SetupDiEnumDeviceInterfaces(DeviceInfoSet, nullptr, &HidGuid, Index, &InterfaceData); ++Index) { DWORD NeedLength = 0; SP_DEVINFO_DATA DeviceInfoData = {}; DeviceInfoData.cbSize = sizeof(DeviceInfoData); SetupDiGetDeviceInterfaceDetailW( DeviceInfoSet, &InterfaceData, nullptr, 0, &NeedLength, &DeviceInfoData); if (NeedLength == 0) { continue; } QByteArray Buffer(static_cast(NeedLength), 0); auto* p_Detail = reinterpret_cast(Buffer.data()); p_Detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); if (!SetupDiGetDeviceInterfaceDetailW( DeviceInfoSet, &InterfaceData, p_Detail, NeedLength, nullptr, &DeviceInfoData)) { continue; } HANDLE HandleQuery = CreateFileW( p_Detail->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); if (HandleQuery == INVALID_HANDLE_VALUE) { continue; } HIDD_ATTRIBUTES Attributes = {}; Attributes.Size = sizeof(Attributes); PHIDP_PREPARSED_DATA p_Preparsed = nullptr; HIDP_CAPS Caps = {}; const bool IsExactMatch = HidD_GetAttributes(HandleQuery, &Attributes) && HidD_GetPreparsedData(HandleQuery, &p_Preparsed) && (HidP_GetCaps(p_Preparsed, &Caps) == HIDP_STATUS_SUCCESS) && (Caps.UsagePage == Match.UsagePage) && (Caps.Usage == Match.Usage) && (Attributes.VendorID == Match.VendorId) && (Attributes.ProductID == Match.ProductId); if (p_Preparsed != nullptr) { HidD_FreePreparsedData(p_Preparsed); } CloseHandle(HandleQuery); if (IsExactMatch) { if (p_DevicePath != nullptr) { *p_DevicePath = QString::fromWCharArray(p_Detail->DevicePath); } if (p_InputLength != nullptr) { *p_InputLength = Caps.InputReportByteLength; } if (p_OutputLength != nullptr) { *p_OutputLength = Caps.OutputReportByteLength; } if (p_DeviceInstanceId != nullptr) { *p_DeviceInstanceId = Mid_GetDeviceInstanceId(DeviceInfoSet, &DeviceInfoData); } IsFound = true; break; } } SetupDiDestroyDeviceInfoList(DeviceInfoSet); return IsFound; } bool Mid_IsBluetoothHidInstanceId(const QString& DeviceInstanceId) { const QString UpperId = DeviceInstanceId.trimmed().toUpper(); return UpperId.contains(QStringLiteral("BTHLEDEVICE")) || UpperId.contains(QStringLiteral("{00001812-0000-1000-8000-00805F9B34FB}")); } QString Mid_GetHexText(const QByteArray& ByteArray) { QStringList TextList; for (int Index = 0; Index < ByteArray.size(); ++Index) { TextList.append(QStringLiteral("%1") .arg(static_cast(ByteArray.at(Index)), 2, 16, QLatin1Char('0')) .toUpper()); } return TextList.join(QLatin1Char(' ')); } QString Mid_GetModifierText(quint8 Modifier) { QStringList TextList; if (Modifier == 0) { return QStringLiteral("无"); } if ((Modifier & 0x01) != 0) TextList.append(QStringLiteral("Left Ctrl")); if ((Modifier & 0x02) != 0) TextList.append(QStringLiteral("Left Shift")); if ((Modifier & 0x04) != 0) TextList.append(QStringLiteral("Left Alt")); if ((Modifier & 0x08) != 0) TextList.append(QStringLiteral("Left GUI")); if ((Modifier & 0x10) != 0) TextList.append(QStringLiteral("Right Ctrl")); if ((Modifier & 0x20) != 0) TextList.append(QStringLiteral("Right Shift")); if ((Modifier & 0x40) != 0) TextList.append(QStringLiteral("Right Alt")); if ((Modifier & 0x80) != 0) TextList.append(QStringLiteral("Right GUI")); return TextList.join(QStringLiteral(", ")); } QString Mid_GetKeyboardUsageText(quint16 Usage) { switch (Usage) { case 0x0053: return QStringLiteral("Num Lock"); case 0x0054: return QStringLiteral("小键盘 /"); case 0x0055: return QStringLiteral("小键盘 *"); case 0x0056: return QStringLiteral("小键盘 -"); case 0x0057: return QStringLiteral("小键盘 +"); case 0x0058: return QStringLiteral("小键盘 Enter"); case 0x0059: return QStringLiteral("小键盘 1"); case 0x005A: return QStringLiteral("小键盘 2"); case 0x005B: return QStringLiteral("小键盘 3"); case 0x005C: return QStringLiteral("小键盘 4"); case 0x005D: return QStringLiteral("小键盘 5"); case 0x005E: return QStringLiteral("小键盘 6"); case 0x005F: return QStringLiteral("小键盘 7"); case 0x0060: return QStringLiteral("小键盘 8"); case 0x0061: return QStringLiteral("小键盘 9"); case 0x0062: return QStringLiteral("小键盘 0"); case 0x0063: return QStringLiteral("小键盘 ."); case 0x00E0: return QStringLiteral("Left Ctrl"); case 0x00E1: return QStringLiteral("Left Shift"); case 0x00E2: return QStringLiteral("Left Alt"); case 0x00E3: return QStringLiteral("Left GUI"); case 0x00E4: return QStringLiteral("Right Ctrl"); case 0x00E5: return QStringLiteral("Right Shift"); case 0x00E6: return QStringLiteral("Right Alt"); case 0x00E7: return QStringLiteral("Right GUI"); default: return QStringLiteral("未知 HID Usage"); } } QString Mid_GetConsumerUsageText(quint16 Usage) { switch (Usage) { case 0x0000: return QStringLiteral("释放"); case 0x00E2: return QStringLiteral("Mute"); case 0x00E9: return QStringLiteral("Volume Up"); case 0x00EA: return QStringLiteral("Volume Down"); default: return QStringLiteral("未知 Consumer Usage"); } }