|
|
@@ -614,8 +614,32 @@ void CSystem::HideSystemKeyboard()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 核心判断:是否为真实物理键盘
|
|
|
-bool IsRealPhysicalKeyboard(LPCWSTR szDevicePath, std::wstring* pDebugOut)
|
|
|
+// ============================================================
|
|
|
+// 新增2:已知扫码枪品牌 VID 黑名单(按实际设备扩充)
|
|
|
+// 常见:Honeywell=VID_0C2E, Zebra/Symbol=VID_05E0
|
|
|
+// 你的这台:VID_2010(Tectonica/USBKey 通用HID)
|
|
|
+// ============================================================
|
|
|
+bool IsKnownScannerPath(const wchar_t* szDevicePath)
|
|
|
+{
|
|
|
+ static const wchar_t* kScannerVidList[] = {
|
|
|
+ L"VID_0C2E", // Honeywell 霍尼韦尔
|
|
|
+ L"VID_05E0", // Zebra / Symbol 斑马
|
|
|
+ //L"VID_2010", // 你的当前扫码枪(通用HID)
|
|
|
+ };
|
|
|
+ if (szDevicePath == nullptr)
|
|
|
+ return false;
|
|
|
+ for (const wchar_t* vid : kScannerVidList)
|
|
|
+ {
|
|
|
+ if (wcsstr(szDevicePath, vid) != nullptr)
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+// ============================================================
|
|
|
+// 修改:IsRealPhysicalKeyboard 增加 hDevice 参数 + 两个新校验
|
|
|
+// ============================================================
|
|
|
+bool IsRealPhysicalKeyboard(HANDLE hDevice, LPCWSTR szDevicePath, std::wstring* pDebugOut)
|
|
|
{
|
|
|
std::wstring dbg;
|
|
|
|
|
|
@@ -627,17 +651,68 @@ bool IsRealPhysicalKeyboard(LPCWSTR szDevicePath, std::wstring* pDebugOut)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- // ========== 2. 打开HID设备 ==========
|
|
|
+ // ========== 2. 已知扫码枪品牌VID黑名单(保留) ==========
|
|
|
+ if (IsKnownScannerPath(szDevicePath))
|
|
|
+ {
|
|
|
+ dbg += L"HID: 命中扫码枪VID黑名单,过滤\n";
|
|
|
+ if (pDebugOut) *pDebugOut = dbg;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ========== 3. 过滤无VID_的内置主板/笔记本内置HID键盘 ==========
|
|
|
+ if (wcsstr(szDevicePath, L"VID_") == nullptr)
|
|
|
+ {
|
|
|
+ dbg += L"HID: 设备路径无VID_,判定为本机内置HID,过滤\n";
|
|
|
+ if (pDebugOut) *pDebugOut = dbg;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ========== 4. RIDI_DEVICEINFO:键位总数 + 指示灯数【核心判据】 ==========
|
|
|
+ {
|
|
|
+ RID_DEVICE_INFO info{};
|
|
|
+ info.cbSize = sizeof(info);
|
|
|
+ UINT size = sizeof(info);
|
|
|
+ UINT actual = GetRawInputDeviceInfoW(hDevice, RIDI_DEVICEINFO, &info, &size);
|
|
|
+ if (actual == (UINT)-1 || actual < sizeof(info))
|
|
|
+ {
|
|
|
+ dbg += L"RIDI_DEVICEINFO 获取失败\n";
|
|
|
+ if (pDebugOut) *pDebugOut = dbg;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ const DWORD kbdKeys = info.keyboard.dwNumberOfKeysTotal;
|
|
|
+ const DWORD kbdInd = info.keyboard.dwNumberOfIndicators;
|
|
|
+
|
|
|
+ dbg += L"[Debug] KbdMode=" + std::to_wstring(info.keyboard.dwKeyboardMode)
|
|
|
+ + L" FuncKeys=" + std::to_wstring(info.keyboard.dwNumberOfFunctionKeys)
|
|
|
+ + L" Indicators=" + std::to_wstring(kbdInd)
|
|
|
+ + L" KeysTotal=" + std::to_wstring(kbdKeys) + L"\n";
|
|
|
+
|
|
|
+ // 主判据:真实键盘一般 101+ 键;扫码枪/伪键盘通常 <30(Raymond Chen 方法)
|
|
|
+ constexpr DWORD kMinKeysTotal = 30;
|
|
|
+ if (kbdKeys < kMinKeysTotal)
|
|
|
+ {
|
|
|
+ dbg += L"KeysTotal<30,判定为扫码枪/伪键盘,过滤\n";
|
|
|
+ if (pDebugOut) *pDebugOut = dbg;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 次判据:真实键盘通常有键盘指示灯(你的罗技两台都是 Indicators=3,扫码枪多为0)
|
|
|
+ // 若以后发现某真实键盘被这条误杀,把 kRequireIndicators 改为 false 即可
|
|
|
+ constexpr bool kRequireIndicators = true;
|
|
|
+ if (kRequireIndicators && kbdInd < 1)
|
|
|
+ {
|
|
|
+ dbg += L"Indicators<1,判定为扫码枪/伪键盘,过滤\n";
|
|
|
+ if (pDebugOut) *pDebugOut = dbg;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // ========== 5. 打开HID设备:只校验顶层用法,不再用OutputReport/LED当过滤条件 ==========
|
|
|
HANDLE hTestOnline = CreateFileW(
|
|
|
- szDevicePath,
|
|
|
- 0,
|
|
|
+ szDevicePath, 0,
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
|
- nullptr,
|
|
|
- OPEN_EXISTING,
|
|
|
- 0,
|
|
|
- nullptr
|
|
|
- );
|
|
|
-
|
|
|
+ nullptr, OPEN_EXISTING, 0, nullptr);
|
|
|
if (hTestOnline == INVALID_HANDLE_VALUE)
|
|
|
{
|
|
|
dbg += L"CreateFileW 打开设备失败\n";
|
|
|
@@ -646,8 +721,7 @@ bool IsRealPhysicalKeyboard(LPCWSTR szDevicePath, std::wstring* pDebugOut)
|
|
|
}
|
|
|
|
|
|
PHIDP_PREPARSED_DATA pPreparse = nullptr;
|
|
|
- BOOLEAN bRet = HidD_GetPreparsedData(hTestOnline, &pPreparse);
|
|
|
- if (!bRet || pPreparse == nullptr)
|
|
|
+ if (!HidD_GetPreparsedData(hTestOnline, &pPreparse) || pPreparse == nullptr)
|
|
|
{
|
|
|
dbg += L"HidD_GetPreparsedData 获取PreparsedData失败\n";
|
|
|
CloseHandle(hTestOnline);
|
|
|
@@ -655,7 +729,6 @@ bool IsRealPhysicalKeyboard(LPCWSTR szDevicePath, std::wstring* pDebugOut)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- // ========== 3. 获取HID顶层能力 ==========
|
|
|
HIDP_CAPS caps{};
|
|
|
NTSTATUS ntStatus = HidP_GetCaps(pPreparse, &caps);
|
|
|
if (ntStatus != HIDP_STATUS_SUCCESS)
|
|
|
@@ -667,70 +740,24 @@ bool IsRealPhysicalKeyboard(LPCWSTR szDevicePath, std::wstring* pDebugOut)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- // ========== 4. 校验顶层必须是标准键盘 UsagePage=0x01, Usage=0x06 ==========
|
|
|
if (!(caps.UsagePage == 0x01 && caps.Usage == 0x06))
|
|
|
{
|
|
|
- dbg += L"HID: Top‑Level 不是标准键盘,过滤\n";
|
|
|
+ dbg += L"HID: Top-Level 不是标准键盘,过滤\n";
|
|
|
HidD_FreePreparsedData(pPreparse);
|
|
|
CloseHandle(hTestOnline);
|
|
|
if (pDebugOut) *pDebugOut = dbg;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- //=====新增:过滤没有VID_的内置主板/笔记本内置HID键盘=====
|
|
|
- if (wcsstr(szDevicePath, L"VID_") == nullptr)
|
|
|
- {
|
|
|
- dbg += L"HID: 设备路径无VID_,判定为本机内置HID,过滤\n";
|
|
|
- HidD_FreePreparsedData(pPreparse);
|
|
|
- CloseHandle(hTestOnline);
|
|
|
- if (pDebugOut) *pDebugOut = dbg;
|
|
|
- return false;
|
|
|
- }
|
|
|
+ // 仅诊断,不参与判定:
|
|
|
+ // 罗技等现代键盘的键盘集合 OutputReportByteLength 也可能=0,
|
|
|
+ // 手动扫标准LED用法(0x45/0x46/0x47)也可能扫不到,都不能拿来过滤
|
|
|
+ dbg += L"[Debug] OutputReportLen=" + std::to_wstring(caps.OutputReportByteLength) + L"\n";
|
|
|
|
|
|
- // ========== 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);
|
|
|
|
|
|
+ dbg += L"HID: 通过真实键盘判定\n";
|
|
|
if (pDebugOut) *pDebugOut = dbg;
|
|
|
return true;
|
|
|
}
|
|
|
@@ -770,7 +797,7 @@ bool CSystem::HasKeyboardDevice()
|
|
|
|
|
|
// 2. 调用IsRealPhysicalKeyboard,传入路径
|
|
|
std::wstring itemDebug;
|
|
|
- bool realKb = IsRealPhysicalKeyboard(devPath.c_str(), &itemDebug);
|
|
|
+ bool realKb = IsRealPhysicalKeyboard(devices[i].hDevice, devPath.c_str(), &itemDebug);
|
|
|
|
|
|
if (realKb)
|
|
|
{
|
|
|
@@ -837,7 +864,7 @@ void CSystem::ShowKeyboardDeviceNames()
|
|
|
devName.resize(realLen);
|
|
|
|
|
|
// 传入路径,拿到判定结果与子函数调试信息
|
|
|
- realKb = IsRealPhysicalKeyboard(devName.c_str(), &itemDebug);
|
|
|
+ realKb = IsRealPhysicalKeyboard(devices[i].hDevice, devName.c_str(), &itemDebug);
|
|
|
}
|
|
|
}
|
|
|
|