244 lines
7.6 KiB
C++
244 lines
7.6 KiB
C++
#include "MID/Mid_Def.h"
|
|
|
|
#include <QtCore/QStringList>
|
|
#include <QtCore/QVector>
|
|
#include <Windows.h>
|
|
#include <SetupAPI.h>
|
|
#include <hidsdi.h>
|
|
#include <hidpi.h>
|
|
|
|
#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<wchar_t> Buffer(static_cast<int>(NeedLength) + 1, 0);
|
|
return SetupDiGetDeviceInstanceIdW(
|
|
DeviceInfoSet,
|
|
p_DeviceInfoData,
|
|
Buffer.data(),
|
|
static_cast<DWORD>(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<int>(NeedLength), 0);
|
|
auto* p_Detail = reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_W*>(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<quint8>(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");
|
|
}
|
|
}
|
|
|