|
@@ -19,6 +19,10 @@
|
|
|
#define RIDI_PREPARSEDDATA 0x20000005
|
|
#define RIDI_PREPARSEDDATA 0x20000005
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
|
|
+#ifndef SPDRP_PARENT_DEVICE_ID
|
|
|
|
|
+#define SPDRP_PARENT_DEVICE_ID 0x19
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
int CSystem::get_CPU_core_num()
|
|
int CSystem::get_CPU_core_num()
|
|
|
{
|
|
{
|
|
|
#ifdef _WIN32
|
|
#ifdef _WIN32
|
|
@@ -605,100 +609,276 @@ void CSystem::HideSystemKeyboard()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// 判断是否是真正物理键盘,排除鼠标侧键虚拟键盘接口
|
|
|
|
|
-static bool IsRealKeyboard(HANDLE hRawDevice)
|
|
|
|
|
|
|
+// 递归遍历PNP树,查找是否存在BTH\开头的蓝牙硬件子设备
|
|
|
|
|
+// 递归遍历PNP树,查找是否存在BTH\开头的蓝牙硬件子设备
|
|
|
|
|
+static bool HasBluetoothChildDevice(HDEVINFO hDevInfo, SP_DEVINFO_DATA* parentDevInfo)
|
|
|
{
|
|
{
|
|
|
- UINT pathLen = 0;
|
|
|
|
|
- UINT ret = GetRawInputDeviceInfoW(hRawDevice, RIDI_DEVICENAME, nullptr, &pathLen);
|
|
|
|
|
- if (ret == (UINT)-1 || pathLen == 0)
|
|
|
|
|
|
|
+ WCHAR parentInstanceId[4096]{};
|
|
|
|
|
+ if (!SetupDiGetDeviceInstanceIdW(hDevInfo, parentDevInfo, parentInstanceId, _countof(parentInstanceId), nullptr))
|
|
|
return false;
|
|
return false;
|
|
|
|
|
|
|
|
- std::wstring devPath(pathLen, L'\0');
|
|
|
|
|
- ret = GetRawInputDeviceInfoW(hRawDevice, RIDI_DEVICENAME, devPath.data(), &pathLen);
|
|
|
|
|
- if (ret == (UINT)-1)
|
|
|
|
|
|
|
+ SP_DEVINFO_DATA childInfo{};
|
|
|
|
|
+ childInfo.cbSize = sizeof(SP_DEVINFO_DATA);
|
|
|
|
|
+
|
|
|
|
|
+ for (DWORD i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &childInfo); i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ WCHAR childParentId[4096]{};
|
|
|
|
|
+ DWORD propType = 0;
|
|
|
|
|
+ // SPDRP_PARENT_DEVICE_ID 0x19
|
|
|
|
|
+ if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, &childInfo, SPDRP_PARENT_DEVICE_ID,
|
|
|
|
|
+ &propType, (PBYTE)childParentId, sizeof(childParentId), nullptr))
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ if (_wcsicmp(childParentId, parentInstanceId) != 0)
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ WCHAR hwIds[4096]{};
|
|
|
|
|
+ if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, &childInfo, SPDRP_HARDWAREID,
|
|
|
|
|
+ &propType, (PBYTE)hwIds, sizeof(hwIds), nullptr))
|
|
|
|
|
+ {
|
|
|
|
|
+ std::wstring hwStr(hwIds);
|
|
|
|
|
+ if (hwStr.find(L"BTH\\") != std::wstring::npos)
|
|
|
|
|
+ {
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (HasBluetoothChildDevice(hDevInfo, &childInfo))
|
|
|
|
|
+ {
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return false;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 根据RawInput hDevice 判断设备是否挂在虚拟总线上(Oray VHID / VHF)
|
|
|
|
|
+static bool IsRawInputDeviceOnVirtualBus(HANDLE hRawDevice)
|
|
|
|
|
+{
|
|
|
|
|
+ UINT bufLen = 0;
|
|
|
|
|
+ GetRawInputDeviceInfoW(hRawDevice, RIDI_DEVICENAME, nullptr, &bufLen);
|
|
|
|
|
+ if (bufLen == 0) return false;
|
|
|
|
|
+
|
|
|
|
|
+ std::wstring devName(bufLen, L'\0');
|
|
|
|
|
+ bufLen = (UINT)devName.size();
|
|
|
|
|
+ UINT ret = GetRawInputDeviceInfoW(hRawDevice, RIDI_DEVICENAME, devName.data(), &bufLen);
|
|
|
|
|
+ if (ret == (UINT)-1) return false;
|
|
|
|
|
+
|
|
|
|
|
+ HDEVINFO hDevInfo = SetupDiGetClassDevsW(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES);
|
|
|
|
|
+ if (hDevInfo == INVALID_HANDLE_VALUE)
|
|
|
return false;
|
|
return false;
|
|
|
|
|
|
|
|
- //截断末尾'\0',纯STL,不依赖wcslen
|
|
|
|
|
- size_t realLen = devPath.find(L'\0');
|
|
|
|
|
- if (realLen != std::wstring::npos)
|
|
|
|
|
|
|
+ SP_DEVINFO_DATA devInfoData{};
|
|
|
|
|
+ devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
|
|
|
|
+ bool isVirtual = false;
|
|
|
|
|
+
|
|
|
|
|
+ for (DWORD i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &devInfoData); i++)
|
|
|
{
|
|
{
|
|
|
- devPath.resize(realLen);
|
|
|
|
|
|
|
+ WCHAR szInstanceId[4096]{};
|
|
|
|
|
+ if (!SetupDiGetDeviceInstanceIdW(hDevInfo, &devInfoData, szInstanceId, _countof(szInstanceId), nullptr))
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ if (wcsstr(devName.c_str(), szInstanceId) != nullptr)
|
|
|
|
|
+ {
|
|
|
|
|
+ WCHAR szLocation[1024]{};
|
|
|
|
|
+ DWORD propType = 0;
|
|
|
|
|
+ if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, &devInfoData, SPDRP_LOCATION_INFORMATION,
|
|
|
|
|
+ &propType, (PBYTE)szLocation, sizeof(szLocation), nullptr))
|
|
|
|
|
+ {
|
|
|
|
|
+ std::wstring locStr(szLocation);
|
|
|
|
|
+ if (locStr.find(L"Oray VHID") != std::wstring::npos
|
|
|
|
|
+ || locStr.find(L"VHF") != std::wstring::npos)
|
|
|
|
|
+ {
|
|
|
|
|
+ isVirtual = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+ SetupDiDestroyDeviceInfoList(hDevInfo);
|
|
|
|
|
+ return isVirtual;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 核心判断:是否为真实物理键盘
|
|
|
|
|
+bool IsRealPhysicalKeyboard(LPCWSTR szDevicePath, std::wstring* pDebugOut)
|
|
|
|
|
+{
|
|
|
|
|
+ std::wstring dbg;
|
|
|
|
|
|
|
|
- //微软蓝牙键盘特殊路径,无法CreateFile打开,直接判定真实键盘
|
|
|
|
|
- if (devPath.find(L"Microsoft Keyboard RID") != std::wstring::npos)
|
|
|
|
|
|
|
+ // ========== 1. 过滤 Microsoft Keyboard RID 系统虚拟键盘 ==========
|
|
|
|
|
+ if (szDevicePath != nullptr && wcsstr(szDevicePath, L"Microsoft Keyboard RID") != nullptr)
|
|
|
{
|
|
{
|
|
|
- return true;
|
|
|
|
|
|
|
+ dbg += L"RID虚拟键盘,直接过滤\n";
|
|
|
|
|
+ if (pDebugOut) *pDebugOut = dbg;
|
|
|
|
|
+ return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- HANDLE hHid = CreateFileW(
|
|
|
|
|
- devPath.c_str(),
|
|
|
|
|
- 0, // 不要GENERIC_READ!仅获取HID描述,不需要访问权限
|
|
|
|
|
|
|
+ // ========== 2. 打开HID设备 ==========
|
|
|
|
|
+ HANDLE hTestOnline = CreateFileW(
|
|
|
|
|
+ szDevicePath,
|
|
|
|
|
+ 0,
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
|
nullptr,
|
|
nullptr,
|
|
|
OPEN_EXISTING,
|
|
OPEN_EXISTING,
|
|
|
0,
|
|
0,
|
|
|
nullptr
|
|
nullptr
|
|
|
);
|
|
);
|
|
|
- if (hHid == INVALID_HANDLE_VALUE)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if (hTestOnline == INVALID_HANDLE_VALUE)
|
|
|
{
|
|
{
|
|
|
|
|
+ dbg += L"CreateFileW 打开设备失败\n";
|
|
|
|
|
+ if (pDebugOut) *pDebugOut = dbg;
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- PHIDP_PREPARSED_DATA pPreparsed = nullptr;
|
|
|
|
|
- BOOL bOk = HidD_GetPreparsedData(hHid, &pPreparsed);
|
|
|
|
|
- CloseHandle(hHid);
|
|
|
|
|
-
|
|
|
|
|
- if (!bOk || pPreparsed == nullptr)
|
|
|
|
|
|
|
+ PHIDP_PREPARSED_DATA pPreparse = nullptr;
|
|
|
|
|
+ BOOLEAN bRet = HidD_GetPreparsedData(hTestOnline, &pPreparse);
|
|
|
|
|
+ if (!bRet || pPreparse == nullptr)
|
|
|
{
|
|
{
|
|
|
|
|
+ dbg += L"HidD_GetPreparsedData 获取PreparsedData失败\n";
|
|
|
|
|
+ CloseHandle(hTestOnline);
|
|
|
|
|
+ if (pDebugOut) *pDebugOut = dbg;
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // ========== 3. 获取HID顶层能力 ==========
|
|
|
HIDP_CAPS caps{};
|
|
HIDP_CAPS caps{};
|
|
|
- LONG status = HidP_GetCaps(pPreparsed, &caps);
|
|
|
|
|
- HidD_FreePreparsedData(pPreparsed);
|
|
|
|
|
|
|
+ NTSTATUS ntStatus = HidP_GetCaps(pPreparse, &caps);
|
|
|
|
|
+ if (ntStatus != HIDP_STATUS_SUCCESS)
|
|
|
|
|
+ {
|
|
|
|
|
+ dbg += L"HidP_GetCaps 获取Caps失败\n";
|
|
|
|
|
+ HidD_FreePreparsedData(pPreparse);
|
|
|
|
|
+ CloseHandle(hTestOnline);
|
|
|
|
|
+ if (pDebugOut) *pDebugOut = dbg;
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (status != 0)
|
|
|
|
|
|
|
+ // ========== 4. 校验顶层必须是标准键盘 UsagePage=0x01, Usage=0x06 ==========
|
|
|
|
|
+ if (!(caps.UsagePage == 0x01 && caps.Usage == 0x06))
|
|
|
{
|
|
{
|
|
|
|
|
+ dbg += L"HID: Top‑Level 不是标准键盘,过滤\n";
|
|
|
|
|
+ HidD_FreePreparsedData(pPreparse);
|
|
|
|
|
+ CloseHandle(hTestOnline);
|
|
|
|
|
+ if (pDebugOut) *pDebugOut = dbg;
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (caps.UsagePage == 0x01 && caps.Usage == 0x06)
|
|
|
|
|
|
|
+ //=====新增:过滤没有VID_的内置主板/笔记本内置HID键盘=====
|
|
|
|
|
+ if (wcsstr(szDevicePath, L"VID_") == nullptr)
|
|
|
{
|
|
{
|
|
|
- return true;
|
|
|
|
|
|
|
+ dbg += L"HID: 设备路径无VID_,判定为本机内置HID,过滤\n";
|
|
|
|
|
+ HidD_FreePreparsedData(pPreparse);
|
|
|
|
|
+ CloseHandle(hTestOnline);
|
|
|
|
|
+ if (pDebugOut) *pDebugOut = dbg;
|
|
|
|
|
+ return false;
|
|
|
}
|
|
}
|
|
|
- return false;
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // ========== 5. OutputReportByteLength == 0 拦截鼠标侧键虚拟键盘 ==========
|
|
|
|
|
+ if (caps.OutputReportByteLength == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ dbg += L"HID: OutputReport长度为0,判定鼠标侧键虚拟键盘,过滤\n";
|
|
|
|
|
+ HidD_FreePreparsedData(pPreparse);
|
|
|
|
|
+ CloseHandle(hTestOnline);
|
|
|
|
|
+ if (pDebugOut) *pDebugOut = dbg;
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ========== 6. LED指示灯检测【仅调试打印,不做过滤条件】 ==========
|
|
|
|
|
+ bool hasKeyboardLed = false;
|
|
|
|
|
+ USHORT valueCapsCount = 0;
|
|
|
|
|
+ ntStatus = HidP_GetValueCaps(HidP_Output, nullptr, &valueCapsCount, pPreparse);
|
|
|
|
|
+ if (ntStatus == HIDP_STATUS_SUCCESS && valueCapsCount > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ std::vector<HIDP_VALUE_CAPS> valueCaps(valueCapsCount);
|
|
|
|
|
+ ntStatus = HidP_GetValueCaps(HidP_Output, valueCaps.data(), &valueCapsCount, pPreparse);
|
|
|
|
|
+ if (ntStatus == HIDP_STATUS_SUCCESS)
|
|
|
|
|
+ {
|
|
|
|
|
+ for (USHORT i = 0; i < valueCapsCount; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ auto& vc = valueCaps[i];
|
|
|
|
|
+ if (vc.UsagePage == 0x01 && !vc.IsRange)
|
|
|
|
|
+ {
|
|
|
|
|
+ USAGE u = vc.NotRange.Usage;
|
|
|
|
|
+ if (u == 0x45 || u == 0x46 || u == 0x47)
|
|
|
|
|
+ {
|
|
|
|
|
+ hasKeyboardLed = true;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ dbg += L"[Debug] HasKeyboardLed=" + std::to_wstring(hasKeyboardLed) + L"\n";
|
|
|
|
|
+
|
|
|
|
|
+ // ========== 全部校验通过,判定真实物理键盘 ==========
|
|
|
|
|
+ dbg += L"HID: 通过真实键盘判定\n";
|
|
|
|
|
+
|
|
|
|
|
+ // 资源释放
|
|
|
|
|
+ HidD_FreePreparsedData(pPreparse);
|
|
|
|
|
+ CloseHandle(hTestOnline);
|
|
|
|
|
+
|
|
|
|
|
+ if (pDebugOut) *pDebugOut = dbg;
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool CSystem::HasKeyboardDevice()
|
|
bool CSystem::HasKeyboardDevice()
|
|
|
{
|
|
{
|
|
|
UINT deviceCount = 0;
|
|
UINT deviceCount = 0;
|
|
|
- UINT ret = ::GetRawInputDeviceList(nullptr, &deviceCount, sizeof(RAWINPUTDEVICELIST));
|
|
|
|
|
|
|
+ UINT ret = GetRawInputDeviceList(nullptr, &deviceCount, sizeof(RAWINPUTDEVICELIST));
|
|
|
if (ret == (UINT)-1 || deviceCount == 0)
|
|
if (ret == (UINT)-1 || deviceCount == 0)
|
|
|
- {
|
|
|
|
|
return false;
|
|
return false;
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
std::vector<RAWINPUTDEVICELIST> devices(deviceCount);
|
|
std::vector<RAWINPUTDEVICELIST> devices(deviceCount);
|
|
|
- ret = ::GetRawInputDeviceList(devices.data(), &deviceCount, sizeof(RAWINPUTDEVICELIST));
|
|
|
|
|
|
|
+ ret = GetRawInputDeviceList(devices.data(), &deviceCount, sizeof(RAWINPUTDEVICELIST));
|
|
|
if (ret == (UINT)-1)
|
|
if (ret == (UINT)-1)
|
|
|
- {
|
|
|
|
|
return false;
|
|
return false;
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- bool hasRealKeyboard = false;
|
|
|
|
|
- for (UINT i = 0; i < deviceCount; ++i)
|
|
|
|
|
|
|
+ std::unordered_set<std::wstring> uniqueUsbId;
|
|
|
|
|
+
|
|
|
|
|
+ for (UINT i = 0; i < deviceCount; i++)
|
|
|
{
|
|
{
|
|
|
- if (devices[i].dwType == RIM_TYPEKEYBOARD)
|
|
|
|
|
|
|
+ if (devices[i].dwType != RIM_TYPEKEYBOARD)
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 先获取设备路径
|
|
|
|
|
+ UINT pathLen = 0;
|
|
|
|
|
+ GetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICENAME, nullptr, &pathLen);
|
|
|
|
|
+ if (pathLen == 0)
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ std::wstring devPath(pathLen, L'\0');
|
|
|
|
|
+ GetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICENAME, devPath.data(), &pathLen);
|
|
|
|
|
+
|
|
|
|
|
+ // 截断末尾多余'\0'
|
|
|
|
|
+ size_t zeroPos = devPath.find(L'\0');
|
|
|
|
|
+ if (zeroPos != std::wstring::npos)
|
|
|
|
|
+ devPath.resize(zeroPos);
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 调用IsRealPhysicalKeyboard,传入路径;调试输出传nullptr(不需要调试就传nullptr)
|
|
|
|
|
+ std::wstring itemDebug;
|
|
|
|
|
+ if (!IsRealPhysicalKeyboard(devPath.c_str(), &itemDebug))
|
|
|
{
|
|
{
|
|
|
- if (IsRealKeyboard(devices[i].hDevice))
|
|
|
|
|
- {
|
|
|
|
|
- hasRealKeyboard = true;
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 提取uniqueId,保留你原来的解析逻辑
|
|
|
|
|
+ std::wstring uniqueId;
|
|
|
|
|
+ size_t usbTag = devPath.find(L"#7&");
|
|
|
|
|
+ if (usbTag != std::wstring::npos)
|
|
|
|
|
+ {
|
|
|
|
|
+ size_t endTag = devPath.find(L"&0&", usbTag);
|
|
|
|
|
+ if (endTag != std::wstring::npos)
|
|
|
|
|
+ uniqueId = devPath.substr(0, endTag);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (devPath.find(L"Microsoft Keyboard RID") != std::wstring::npos)
|
|
|
|
|
+ {
|
|
|
|
|
+ uniqueId = L"BT_KB";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!uniqueId.empty())
|
|
|
|
|
+ {
|
|
|
|
|
+ uniqueUsbId.insert(uniqueId);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- return hasRealKeyboard;
|
|
|
|
|
|
|
+
|
|
|
|
|
+ return uniqueUsbId.size() > 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CSystem::ShowKeyboardDeviceNames()
|
|
void CSystem::ShowKeyboardDeviceNames()
|
|
@@ -735,29 +915,62 @@ void CSystem::ShowKeyboardDeviceNames()
|
|
|
if (devices[i].dwType == RIM_TYPEKEYBOARD)
|
|
if (devices[i].dwType == RIM_TYPEKEYBOARD)
|
|
|
{
|
|
{
|
|
|
oss << L" (RIM_TYPEKEYBOARD)\r\n";
|
|
oss << L" (RIM_TYPEKEYBOARD)\r\n";
|
|
|
- bool realKb = IsRealKeyboard(devices[i].hDevice);
|
|
|
|
|
- oss << L" IsRealKeyboard: " << (realKb ? L"YES(真实键盘)" : L"NO(鼠标侧键/虚拟键盘)") << L"\r\n";
|
|
|
|
|
|
|
|
|
|
- if (realKb)
|
|
|
|
|
- {
|
|
|
|
|
- hasRealKeyboard = true;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 先获取DevicePath,不能直接传hDevice给IsRealPhysicalKeyboard
|
|
|
|
|
+ bool realKb = false;
|
|
|
|
|
+ std::wstring devName;
|
|
|
|
|
+ std::wstring itemDebug;
|
|
|
|
|
|
|
|
UINT nameLen = 0;
|
|
UINT nameLen = 0;
|
|
|
UINT riRet = GetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICENAME, nullptr, &nameLen);
|
|
UINT riRet = GetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICENAME, nullptr, &nameLen);
|
|
|
if (riRet != (UINT)-1 && nameLen > 0)
|
|
if (riRet != (UINT)-1 && nameLen > 0)
|
|
|
{
|
|
{
|
|
|
- std::wstring devName(nameLen, L'\0');
|
|
|
|
|
|
|
+ devName.resize(nameLen, L'\0');
|
|
|
riRet = GetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICENAME, devName.data(), &nameLen);
|
|
riRet = GetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICENAME, devName.data(), &nameLen);
|
|
|
if (riRet != (UINT)-1)
|
|
if (riRet != (UINT)-1)
|
|
|
{
|
|
{
|
|
|
size_t realLen = devName.find(L'\0');
|
|
size_t realLen = devName.find(L'\0');
|
|
|
if (realLen != std::wstring::npos)
|
|
if (realLen != std::wstring::npos)
|
|
|
devName.resize(realLen);
|
|
devName.resize(realLen);
|
|
|
- oss << L" DevicePath: " << devName.c_str() << L"\r\n";
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 传入路径,拿到判定结果与子函数调试信息
|
|
|
|
|
+ realKb = IsRealPhysicalKeyboard(devName.c_str(), &itemDebug);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ oss << L" IsRealKeyboard: " << (realKb ? L"YES(真实键盘)" : L"NO(鼠标侧键/虚拟键盘)") << L"\r\n";
|
|
|
|
|
+ // 输出IsRealPhysicalKeyboard内部调试(可选,方便排错)
|
|
|
|
|
+ if (!itemDebug.empty())
|
|
|
|
|
+ {
|
|
|
|
|
+ oss << L" [SubDebug] " << itemDebug << L"\r\n";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (realKb)
|
|
|
|
|
+ {
|
|
|
|
|
+ hasRealKeyboard = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 打印是否虚拟总线(保留原有逻辑)
|
|
|
|
|
+ if (IsRawInputDeviceOnVirtualBus(devices[i].hDevice))
|
|
|
|
|
+ {
|
|
|
|
|
+ oss << L" BusCheck: [Virtual Bus Detected!]\r\n";
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ oss << L" BusCheck: [Physical Bus]\r\n";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // DevicePath
|
|
|
|
|
+ if (!devName.empty())
|
|
|
|
|
+ {
|
|
|
|
|
+ oss << L" DevicePath: " << devName.c_str() << L"\r\n";
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ oss << L" DevicePath: (获取失败)\r\n";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // FriendlyName
|
|
|
UINT friendlyLen = 0;
|
|
UINT friendlyLen = 0;
|
|
|
riRet = GetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICEFRIENDLYNAME, nullptr, &friendlyLen);
|
|
riRet = GetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICEFRIENDLYNAME, nullptr, &friendlyLen);
|
|
|
if (riRet != (UINT)-1 && friendlyLen > 0)
|
|
if (riRet != (UINT)-1 && friendlyLen > 0)
|