Push layered Qt host source files

This commit is contained in:
2026-04-17 16:25:19 +08:00
parent b576d3f19d
commit 89b23b2291
58 changed files with 10349 additions and 2461 deletions

View File

@@ -1,5 +1,7 @@
#include "MID/Mid_Def.h"
#include "MID/Mid_Def.h"
#include <QtCore/QStringList>
#include <QtCore/QVector>
#include <Windows.h>
#include <SetupAPI.h>
#include <hidsdi.h>
@@ -8,62 +10,47 @@
#pragma comment(lib, "hid.lib")
#pragma comment(lib, "setupapi.lib")
/*
* MID 层:介于逻辑与 DRI 之间,负责描述 HID 设备匹配与数据格式。
* 高密注释用于教学,逐条解释如何把固件接口映射为 Win32 API 调用。
*/
/* 构造 NKRO 接口的匹配条件Usage Page / Usage 固定) */
Mid_Struct_DeviceMatch Mid_Func_GetNkroMatch(const Mid_Struct_DeviceConfig& DeviceConfig)
namespace
{
Mid_Struct_DeviceMatch Match;
Match.VendorId = DeviceConfig.VendorId;
Match.ProductId = DeviceConfig.ProductId;
Match.UsagePage = MID_CONST_USAGE_PAGE_NKRO;
Match.Usage = MID_CONST_USAGE_NKRO;
Match.Name = QStringLiteral("NKRO Keyboard Interface");
return Match;
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();
}
/* 构造 Consumer 接口的匹配条件 */
Mid_Struct_DeviceMatch Mid_Func_GetConsumerMatch(const Mid_Struct_DeviceConfig& DeviceConfig)
{
Mid_Struct_DeviceMatch Match;
Match.VendorId = DeviceConfig.VendorId;
Match.ProductId = DeviceConfig.ProductId;
Match.UsagePage = MID_CONST_USAGE_PAGE_CONSUMER;
Match.Usage = MID_CONST_USAGE_CONSUMER;
Match.Name = QStringLiteral("Consumer Interface");
return Match;
}
} // namespace
/* 构造 Vendor状态镜像接口的匹配条件 */
Mid_Struct_DeviceMatch Mid_Func_GetVendorMatch(const Mid_Struct_DeviceConfig& DeviceConfig)
{
Mid_Struct_DeviceMatch Match;
Match.VendorId = DeviceConfig.VendorId;
Match.ProductId = DeviceConfig.ProductId;
Match.UsagePage = MID_CONST_USAGE_PAGE_VENDOR;
Match.Usage = MID_CONST_USAGE_VENDOR;
Match.Name = QStringLiteral("Vendor State Mirror Interface");
return Match;
}
/*
* Mid_Func_FindHidInterface按照匹配条件扫描系统中的 HID 接口。
* 步骤1) 获取 HID GUID 2) SetupAPI 列举接口 3) CreateFile 查询属性 4) 命中后返回路径和报文长度。
*/
bool Mid_Func_FindHidInterface(
// 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)
quint16* p_OutputLength,
QString* p_DeviceInstanceId)
{
/* Win32 提供的 HID GUID列举所有 HID 接口都靠它 */
GUID HidGuid;
HidD_GetHidGuid(&HidGuid);
/* 构建“当前存在 + 暴露接口”的设备集合 */
HDEVINFO DeviceInfoSet = SetupDiGetClassDevsW(&HidGuid, nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (DeviceInfoSet == INVALID_HANDLE_VALUE)
{
@@ -78,25 +65,36 @@ bool Mid_Func_FindHidInterface(
SetupDiEnumDeviceInterfaces(DeviceInfoSet, nullptr, &HidGuid, Index, &InterfaceData);
++Index)
{
/* Query 设备路径前先得到所需缓冲区长度 */
DWORD NeedLength = 0;
SetupDiGetDeviceInterfaceDetailW(DeviceInfoSet, &InterfaceData, nullptr, 0, &NeedLength, nullptr);
SP_DEVINFO_DATA DeviceInfoData = {};
DeviceInfoData.cbSize = sizeof(DeviceInfoData);
SetupDiGetDeviceInterfaceDetailW(
DeviceInfoSet,
&InterfaceData,
nullptr,
0,
&NeedLength,
&DeviceInfoData);
if (NeedLength == 0)
{
continue;
}
/* 申请一段缓冲区存储 SP_DEVICE_INTERFACE_DETAIL_DATA_W */
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, nullptr))
if (!SetupDiGetDeviceInterfaceDetailW(
DeviceInfoSet,
&InterfaceData,
p_Detail,
NeedLength,
nullptr,
&DeviceInfoData))
{
continue;
}
/* 只需 0 访问权限即可读取属性 */
HANDLE HandleQuery = CreateFileW(
p_Detail->DevicePath,
0,
@@ -114,15 +112,14 @@ bool Mid_Func_FindHidInterface(
Attributes.Size = sizeof(Attributes);
PHIDP_PREPARSED_DATA p_Preparsed = nullptr;
HIDP_CAPS Caps = {};
/* 通过 Attributes + Caps 对比 VID / PID / Usage Page / Usage */
const bool IsMatch =
const bool IsExactMatch =
HidD_GetAttributes(HandleQuery, &Attributes) &&
HidD_GetPreparsedData(HandleQuery, &p_Preparsed) &&
(HidP_GetCaps(p_Preparsed, &Caps) == HIDP_STATUS_SUCCESS) &&
(Attributes.VendorID == Match.VendorId) &&
(Attributes.ProductID == Match.ProductId) &&
(Caps.UsagePage == Match.UsagePage) &&
(Caps.Usage == Match.Usage);
(Caps.Usage == Match.Usage) &&
(Attributes.VendorID == Match.VendorId) &&
(Attributes.ProductID == Match.ProductId);
if (p_Preparsed != nullptr)
{
@@ -130,36 +127,43 @@ bool Mid_Func_FindHidInterface(
}
CloseHandle(HandleQuery);
if (!IsMatch)
if (IsExactMatch)
{
continue;
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;
}
/* 命中:写回设备路径及报文长度 */
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;
}
IsFound = true;
break;
}
/* 枚举结束释放句柄 */
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
return IsFound;
}
/* 调试输出把字节数组格式化成“AA BB CC” */
QString Mid_Func_GetHexText(const QByteArray& ByteArray)
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)
@@ -171,8 +175,7 @@ QString Mid_Func_GetHexText(const QByteArray& ByteArray)
return TextList.join(QLatin1Char(' '));
}
/* 把 Modifier 位图翻译成人类可读的组合 */
QString Mid_Func_GetModifierText(quint8 Modifier)
QString Mid_GetModifierText(quint8 Modifier)
{
QStringList TextList;
if (Modifier == 0)
@@ -191,8 +194,7 @@ QString Mid_Func_GetModifierText(quint8 Modifier)
return TextList.join(QStringLiteral(", "));
}
/* 键盘 Usage -> 中文/英文标签,方便 UI 展示 */
QString Mid_Func_GetKeyboardUsageText(quint16 Usage)
QString Mid_GetKeyboardUsageText(quint16 Usage)
{
switch (Usage)
{
@@ -226,8 +228,7 @@ QString Mid_Func_GetKeyboardUsageText(quint16 Usage)
}
}
/* Consumer Usage -> UI 标签 */
QString Mid_Func_GetConsumerUsageText(quint16 Usage)
QString Mid_GetConsumerUsageText(quint16 Usage)
{
switch (Usage)
{
@@ -239,3 +240,4 @@ QString Mid_Func_GetConsumerUsageText(quint16 Usage)
return QStringLiteral("未知 Consumer Usage");
}
}