Browse Source

优化虚拟键盘现实

张洋 1 month ago
parent
commit
2df26a1c4d

BIN
bin/Win32/Debug/zhipuzi_pos_windows/DuiLib_d.dll


+ 12 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/setting_xianshi.xml

@@ -19,4 +19,16 @@
 			<Label name="xianshi_setting_wutu_name" text="无图模式" width="300" padding="10,0,0,0"/>
 		</HorizontalLayout>
 	</HorizontalLayout>
+
+	<HorizontalLayout height="30" padding="0,15,0,0">
+		<Label text="触摸键盘" width="180"/>
+		<HorizontalLayout padding="30,0,30,0" width="120" height="30">
+			<CheckBox name="xianshi_setting_chumo" group="setting_xianshi_chumojianpan_type" selected="true" padding="0,7,0,7" width="13" height="13" normalimage="file='RadioBtnNon.png'" hotimage="file='RadioBtnNon.png'" selectedimage="file='RadioBtnSel.png'"/>
+			<Label name="xianshi_setting_chumo_name" text="显示触摸键盘" width="300" padding="10,0,0,0"/>
+		</HorizontalLayout>
+		<HorizontalLayout padding="30,0,30,0" width="120" height="30">
+			<CheckBox name="xianshi_setting_buchumo" group="setting_xianshi_chumojianpan_type" padding="0,7,0,7" width="13" height="13" normalimage="file='RadioBtnNon.png'" hotimage="file='RadioBtnNon.png'" selectedimage="file='RadioBtnSel.png'"/>
+			<Label name="xianshi_setting_buchumo_name" text="不显示触摸键盘" width="300" padding="10,0,0,0"/>
+		</HorizontalLayout>
+	</HorizontalLayout>
 </Window>

BIN
bin/Win32/Release/zhipuzi_pos_windows/zhipuzi_pos_windows.exe


BIN
dll/debug/DuiLib_d.dll


+ 15 - 301
zhipuzi_pos_windows/helper/CSystem.cpp

@@ -615,321 +615,35 @@ void CSystem::HideSystemKeyboard()
 }
 
 // ============================================================
-// 新增2:已知扫码枪品牌 VID 黑名单(按实际设备扩充)
-// 常见:Honeywell=VID_0C2E, Zebra/Symbol=VID_05E0
-// 你的这台:VID_2010(Tectonica/USBKey 通用HID)
+// 精确检测:当前系统是否有"可触摸的屏幕"(排除触摸板)
 // ============================================================
-bool IsKnownScannerPath(const wchar_t* szDevicePath)
+bool CSystem::HasTouchScreenDevice()
 {
-	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;
-
-	// ========== 1. 过滤 Microsoft Keyboard RID 系统虚拟键盘 ==========
-	if (szDevicePath != nullptr && wcsstr(szDevicePath, L"Microsoft Keyboard RID") != nullptr)
-	{
-		dbg += L"RID虚拟键盘,直接过滤\n";
-		if (pDebugOut) *pDebugOut = dbg;
+	UINT deviceCount = 0;
+	if (GetRawInputDeviceList(nullptr, &deviceCount, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1 || deviceCount == 0)
 		return false;
-	}
 
-	// ========== 2. 已知扫码枪品牌VID黑名单(保留) ==========
-	if (IsKnownScannerPath(szDevicePath))
-	{
-		dbg += L"HID: 命中扫码枪VID黑名单,过滤\n";
-		if (pDebugOut) *pDebugOut = dbg;
+	std::vector<RAWINPUTDEVICELIST> devices(deviceCount);
+	if (GetRawInputDeviceList(devices.data(), &deviceCount, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1)
 		return false;
-	}
 
-	// ========== 3. 过滤无VID_的内置主板/笔记本内置HID键盘 ==========
-	if (wcsstr(szDevicePath, L"VID_") == nullptr)
+	for (UINT i = 0; i < deviceCount; i++)
 	{
-		dbg += L"HID: 设备路径无VID_,判定为本机内置HID,过滤\n";
-		if (pDebugOut) *pDebugOut = dbg;
-		return false;
-	}
+		if (devices[i].dwType != RIM_TYPEHID)
+			continue;
 
-	// ========== 4. RIDI_DEVICEINFO:键位总数 + 指示灯数【核心判据】 ==========
-	{
 		RID_DEVICE_INFO info{};
 		info.cbSize = sizeof(info);
 		UINT size = sizeof(info);
-		UINT actual = GetRawInputDeviceInfoW(hDevice, RIDI_DEVICEINFO, &info, &size);
+		UINT actual = GetRawInputDeviceInfoW(devices[i].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,
-		FILE_SHARE_READ | FILE_SHARE_WRITE,
-		nullptr, OPEN_EXISTING, 0, nullptr);
-	if (hTestOnline == INVALID_HANDLE_VALUE)
-	{
-		dbg += L"CreateFileW 打开设备失败\n";
-		if (pDebugOut) *pDebugOut = dbg;
-		return false;
-	}
-
-	PHIDP_PREPARSED_DATA pPreparse = nullptr;
-	if (!HidD_GetPreparsedData(hTestOnline, &pPreparse) || pPreparse == nullptr)
-	{
-		dbg += L"HidD_GetPreparsedData 获取PreparsedData失败\n";
-		CloseHandle(hTestOnline);
-		if (pDebugOut) *pDebugOut = dbg;
-		return false;
-	}
-
-	HIDP_CAPS caps{};
-	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 (!(caps.UsagePage == 0x01 && caps.Usage == 0x06))
-	{
-		dbg += L"HID: Top-Level 不是标准键盘,过滤\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";
-
-	HidD_FreePreparsedData(pPreparse);
-	CloseHandle(hTestOnline);
-
-	dbg += L"HID: 通过真实键盘判定\n";
-	if (pDebugOut) *pDebugOut = dbg;
-	return true;
-}
-
-bool CSystem::HasKeyboardDevice()
-{
-	UINT deviceCount = 0;
-	UINT ret = GetRawInputDeviceList(nullptr, &deviceCount, sizeof(RAWINPUTDEVICELIST));
-	if (ret == (UINT)-1 || deviceCount == 0)
-		return false;
-
-	std::vector<RAWINPUTDEVICELIST> devices(deviceCount);
-	ret = GetRawInputDeviceList(devices.data(), &deviceCount, sizeof(RAWINPUTDEVICELIST));
-	if (ret == (UINT)-1)
-		return false;
-
-	bool hasRealKeyboard = false; // 和ShowKeyboardDeviceNames保持一致:用布尔标记
-
-	for (UINT i = 0; i < deviceCount; i++)
-	{
-		if (devices[i].dwType != RIM_TYPEKEYBOARD)
 			continue;
-
-		// 1. 先获取设备路径
-		UINT pathLen = 0;
-		GetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICENAME, nullptr, &pathLen);
-		if (pathLen == 0)
+		if (info.dwType != RIM_TYPEHID)
 			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,传入路径
-		std::wstring itemDebug;
-		bool realKb = IsRealPhysicalKeyboard(devices[i].hDevice, devPath.c_str(), &itemDebug);
-
-		if (realKb)
-		{
-			hasRealKeyboard = true; // 只要有一个真实键盘就置true,与弹窗逻辑完全对齐
-			
-			break; // 找到一个真实键盘就可以退出循环
-		}
-	}
-
-	// 返回值完全对齐ShowKeyboardDeviceNames:只要IsRealPhysicalKeyboard有一个为true就返回true
-	return hasRealKeyboard;
-}
-
-void CSystem::ShowKeyboardDeviceNames()
-{
-	UINT deviceCount = 0;
-	UINT ret = ::GetRawInputDeviceList(nullptr, &deviceCount, sizeof(RAWINPUTDEVICELIST));
-	std::wostringstream oss;
-
-	if (ret == (UINT)-1 || deviceCount == 0)
-	{
-		oss << L"HasKeyboardDevice:\r\n";
-		oss << L"GetRawInputDeviceList 返回错误 或者 设备数量=0\r\n";
-		CLewaimaiLog::OutputMessageBox(oss.str());
-		return;
-	}
-
-	std::vector<RAWINPUTDEVICELIST> devices(deviceCount);
-	ret = ::GetRawInputDeviceList(devices.data(), &deviceCount, sizeof(RAWINPUTDEVICELIST));
-	if (ret == (UINT)-1)
-	{
-		oss << L"HasKeyboardDevice:\r\n";
-		oss << L"GetRawInputDeviceList 获取设备列表失败\r\n";
-		CLewaimaiLog::OutputMessageBox(oss.str());
-		return;
-	}
-
-	bool hasRealKeyboard = false;
-	oss << L"=== RawInput 键盘枚举结果 ===\r\n";
-	oss << L"总RawInput设备数:" << deviceCount << L"\r\n\r\n";
-
-	for (UINT i = 0; i < deviceCount; ++i)
-	{
-		oss << L"[" << i << L"] dwType=" << devices[i].dwType;
-		if (devices[i].dwType == RIM_TYPEKEYBOARD)
-		{
-			oss << L" (RIM_TYPEKEYBOARD)\r\n";
-
-			// 先获取DevicePath,不能直接传hDevice给IsRealPhysicalKeyboard
-			bool realKb = false;
-			std::wstring devName;
-			std::wstring itemDebug;
-
-			UINT nameLen = 0;
-			UINT riRet = GetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICENAME, nullptr, &nameLen);
-			if (riRet != (UINT)-1 && nameLen > 0)
-			{
-				devName.resize(nameLen, L'\0');
-				riRet = GetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICENAME, devName.data(), &nameLen);
-				if (riRet != (UINT)-1)
-				{
-					size_t realLen = devName.find(L'\0');
-					if (realLen != std::wstring::npos)
-						devName.resize(realLen);
-
-					// 传入路径,拿到判定结果与子函数调试信息
-					realKb = IsRealPhysicalKeyboard(devices[i].hDevice, 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;
-			}
-
-			// DevicePath
-			if (!devName.empty())
-			{
-				oss << L"  DevicePath: " << devName.c_str() << L"\r\n";
-			}
-			else
-			{
-				oss << L"  DevicePath: (获取失败)\r\n";
-			}
-
-			// FriendlyName
-			UINT friendlyLen = 0;
-			riRet = GetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICEFRIENDLYNAME, nullptr, &friendlyLen);
-			if (riRet != (UINT)-1 && friendlyLen > 0)
-			{
-				std::wstring friendlyName(friendlyLen, L'\0');
-				riRet = GetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICEFRIENDLYNAME, friendlyName.data(), &friendlyLen);
-				if (riRet != (UINT)-1)
-				{
-					size_t realLen = friendlyName.find(L'\0');
-					if (realLen != std::wstring::npos)
-						friendlyName.resize(realLen);
-					oss << L"  FriendlyName: " << friendlyName.c_str() << L"\r\n";
-				}
-				else
-				{
-					oss << L"  FriendlyName: (获取失败)\r\n";
-				}
-			}
-			else
-			{
-				oss << L"  FriendlyName: (无)\r\n";
-			}
-			oss << L"\r\n";
-		}
-		else if (devices[i].dwType == RIM_TYPEMOUSE)
-		{
-			oss << L" (RIM_TYPEMOUSE)\r\n\r\n";
-		}
-		else if (devices[i].dwType == RIM_TYPEHID)
-		{
-			oss << L" (RIM_TYPEHID)\r\n\r\n";
-		}
-		else
-		{
-			oss << L" (其他类型)\r\n\r\n";
-		}
+		// 用途页 0x0D=数字化仪,用途 0x04=触摸屏
+		if (info.hid.usUsagePage == 0x0D && info.hid.usUsage == 0x04)
+			return true;
 	}
-
-	oss << L"============================\r\n";
-	oss << L"检测到真实物理键盘:" << (hasRealKeyboard ? L"是" : L"否") << L"\r\n";
-	CLewaimaiLog::OutputMessageBox(oss.str());
+	return false;
 }

+ 2 - 5
zhipuzi_pos_windows/helper/CSystem.h

@@ -79,9 +79,6 @@ public:
 	//隐藏虚拟键盘,跟系统设置无关
 	static void HideSystemKeyboard();
 
-	// 检测系统当前是否存在键盘设备(有线/蓝牙都算)
-	static bool HasKeyboardDevice();
-
-	// 打印当前系统枚举到的键盘输入设备名称
-	static void ShowKeyboardDeviceNames();
+	//系统是否有触摸屏
+	static bool HasTouchScreenDevice();
 };

+ 0 - 3
zhipuzi_pos_windows/page/CDiandanPageUI.cpp

@@ -824,9 +824,6 @@ void CDiandanPageUI::HandleClickMsg(TNotifyUI& msg)
 	}
 	else if (name == L"btn_diandan_qingkong")
 	{
-		//纯粹用于调试物理键盘
-		CSystem::ShowKeyboardDeviceNames();
-
 		this->ClickQingkong();
 	}
 	else if (name == L"btn_diandan_zhengdanbeizhu")

+ 23 - 1
zhipuzi_pos_windows/page/CSettingPageUI.cpp

@@ -998,6 +998,20 @@ void CSettingPageUI::InitControl()
 		box_youtu_3->Selected(false, false);
 		box_wutu->Selected(true, false);
 	}
+
+	//初始化触摸键盘设置
+	CCheckBoxUI* box_chumo = static_cast<CCheckBoxUI*>(this->FindSubControl(_T("xianshi_setting_chumo")));
+	CCheckBoxUI* box_buchumo = static_cast<CCheckBoxUI*>(this->FindSubControl(_T("xianshi_setting_buchumo")));
+	if (CSetting::GetInstance()->GetParam("setting_xianshi_is_chumojianpan") == "1")
+	{
+		box_chumo->Selected(true, false);
+		box_buchumo->Selected(false, false);
+	}
+	else
+	{
+		box_chumo->Selected(false, false);
+		box_buchumo->Selected(true, false);
+	}
 	
 	//初始化快捷键展示
 	this->InitKuaijiejianShow();
@@ -1764,6 +1778,14 @@ void CSettingPageUI::HandleSelectChangeMsg(TNotifyUI& msg)
 	{
 		CSetting::GetInstance()->SetParam("setting_xianshi_is_youtu", "0");
 	}
+	else if (name == _T("xianshi_setting_chumo"))
+	{
+		CSetting::GetInstance()->SetParam("setting_xianshi_is_chumojianpan", "1");
+	}
+	else if (name == _T("xianshi_setting_buchumo"))
+	{
+		CSetting::GetInstance()->SetParam("setting_xianshi_is_chumojianpan", "0");
+	}
 	else if (name == _T("setting_dianzicheng_yilianjie"))
 	{
 		CSetting::GetInstance()->SetParam("setting_dianzicheng_is_lianjie", "1");
@@ -3891,4 +3913,4 @@ bool CSettingPageUI::HandleVideoBorderMouseMessage(UINT uMsg, WPARAM wParam, LPA
 	}
 
 	return false;
-}
+}

BIN
zhipuzi_pos_windows/resource/skin.zip


+ 17 - 0
zhipuzi_pos_windows/tool/CSetting.cpp

@@ -354,6 +354,23 @@ void CSetting::Init()
 		m_paramsMap[setting_xianshi_is_youtu] = "1";
 	}
 
+	//触摸键盘相关的
+	std::string setting_xianshi_is_chumojianpan = "setting_xianshi_is_chumojianpan";
+	if (m_paramsMap.find(setting_xianshi_is_chumojianpan) == m_paramsMap.end())
+	{
+		//根据是否有触屏来设置
+		if (CSystem::HasTouchScreenDevice())
+		{
+			//如果有触摸屏,默认显示触摸键盘
+			m_paramsMap[setting_xianshi_is_chumojianpan] = "1";
+		}
+		else
+		{
+			//如果没有触摸屏,默认不显示触摸键盘(这种一般都有外接的键盘了)
+			m_paramsMap[setting_xianshi_is_chumojianpan] = "0";
+		}
+	}
+
 	//功能菜单的参数
 	std::string setting_gongneng_changyong_string = "setting_gongneng_changyong_string";
 	if (m_paramsMap.find(setting_gongneng_changyong_string) == m_paramsMap.end())

+ 2 - 3
zhipuzi_pos_windows/ui/CModalWnd.cpp

@@ -22,8 +22,7 @@ void CModalWnd::Notify(DuiLib::TNotifyUI& msg)
 
 	if (msg.sType == _T("setfocus"))
 	{
-		// 只有没有物理键盘时,才弹虚拟键盘
-		if (!CSystem::HasKeyboardDevice())
+		if (CSetting::GetInstance()->GetParam("setting_xianshi_is_chumojianpan") == "1")
 		{
 			CSystem::ShowSystemKeyboard(m_hWnd);
 		}
@@ -32,4 +31,4 @@ void CModalWnd::Notify(DuiLib::TNotifyUI& msg)
 	{
 		CSystem::HideSystemKeyboard();
 	}
-}
+}

+ 1 - 2
zhipuzi_pos_windows/wnd/CLoginWnd.cpp

@@ -160,8 +160,7 @@ void CLoginWnd::Notify(TNotifyUI& msg)
 	{
 		if (senderClassName == L"EditUI")
 		{
-			// 只有没有物理键盘时,才弹虚拟键盘
-			if (!CSystem::HasKeyboardDevice())
+			if (CSetting::GetInstance()->GetParam("setting_xianshi_is_chumojianpan") == "1")
 			{
 				CSystem::ShowSystemKeyboard(m_hWnd);
 			}

+ 1 - 2
zhipuzi_pos_windows/wnd/CMainWnd.cpp

@@ -270,8 +270,7 @@ void CMainWnd::Notify(TNotifyUI& msg)
 	{
 		if (senderClassName == L"EditUI")
 		{
-			// 只有没有物理键盘时,才弹虚拟键盘
-			if (!CSystem::HasKeyboardDevice())
+			if (CSetting::GetInstance()->GetParam("setting_xianshi_is_chumojianpan") == "1")
 			{
 				CSystem::ShowSystemKeyboard(m_hWnd);
 			}