c++調(diào)用windows鍵盤代碼詳情
1、何為windows鍵盤
windows
管這個(gè)長(zhǎng)得有點(diǎn)兒丑的叫屏幕鍵盤
windows
管這個(gè)長(zhǎng)得好看的叫觸摸鍵盤
當(dāng)然上面的截圖是win10的鍵盤效果,在win7上是有一些差別的,這里就不截圖放出來(lái)了
2、如何調(diào)用這些windows鍵盤
似乎很簡(jiǎn)單,我們用Spy++
抓下窗口,找到窗口句柄所關(guān)聯(lián)的進(jìn)程句柄,再查看下是哪個(gè)進(jìn)程以及命令行信息,然后我們就可以愉快地執(zhí)行命令調(diào)用進(jìn)程了
屏幕鍵盤進(jìn)程信息:
觸摸鍵盤進(jìn)程信息:
命令行走起,運(yùn)行exe,此時(shí)如果兩個(gè)鍵盤你都能順利調(diào)起的話,我只能告訴你,你被你的系統(tǒng)蒙蔽了雙眼
3、巨(wei)硬(ruan)搞事情
當(dāng)系統(tǒng)版本大于等于win10 10.0.14393.0時(shí),觸摸鍵盤你調(diào)用TabTip.exe
并不會(huì)顯示出來(lái),也就是說(shuō)它的內(nèi)部實(shí)現(xiàn)方式變了。
到這里你會(huì)不會(huì)覺(jué)得很詫異,這不是標(biāo)準(zhǔn)玩法嗎?為什么毫無(wú)預(yù)兆就不行了呢?
我只能說(shuō)你太傻太天真,微軟官網(wǎng)本身就沒(méi)有說(shuō)明鍵盤調(diào)用的正確姿勢(shì),也就是說(shuō)觸摸鍵盤對(duì)微軟來(lái)說(shuō)并非開(kāi)放給你的。當(dāng)然互聯(lián)網(wǎng)無(wú)所不能,有大神還是想方法逆向了觸摸鍵盤調(diào)用的方式
4、具體代碼
// 4ce576fa-83dc-4F88-951c-9d0782b4e376 DEFINE_GUID(CLSID_UIHostNoLaunch, 0x4CE576FA, 0x83DC, 0x4f88, 0x95, 0x1C, 0x9D, 0x07, 0x82, 0xB4, 0xE3, 0x76); // 37c994e7_432b_4834_a2f7_dce1f13b834b DEFINE_GUID(IID_ITipInvocation, 0x37c994e7, 0x432b, 0x4834, 0xa2, 0xf7, 0xdc, 0xe1, 0xf1, 0x3b, 0x83, 0x4b); struct ITipInvocation : IUnknown { virtual HRESULT STDMETHODCALLTYPE Toggle(HWND wnd) = 0; }; namespace { constexpr auto kKeyboardWindowClass = L"IPTip_Main_Window"; constexpr auto kWindowParentClass = L"ApplicationFrameWindow"; constexpr auto kWindowClass = L"Windows.UI.Core.CoreWindow"; constexpr auto kWindowCaption = L"Microsoft Text Input Application"; constexpr auto kTabTipPath = L"C:\\Program Files\\Common Files\\Microsoft Shared\\ink\\TabTip.exe"; constexpr auto kTabletTipSubKey = "Software\\Microsoft\\TabletTip"; constexpr auto kTabletTipOption = "EnableDesktopModeAutoInvoke"; }
調(diào)用屏幕鍵盤
bool ScreenKeyBoard::OpenOskKeyboard() { if (!PublicUtils::Process::FindProcess("osk.exe").empty()) { return true; } PVOID OldValue = NULL; //64位系統(tǒng)中32位程序要訪問(wèn)本機(jī)system32文件夾,需取消重定向到Syswow64 BOOL bRet = Wow64DisableWow64FsRedirection(&OldValue); ShellExecuteW(NULL, L"open", L"osk.exe", NULL, NULL, SW_SHOWNORMAL); if (bRet) { Wow64RevertWow64FsRedirection(OldValue); return true; } else { std::cerr << "Wow64DisableWow64FsRedirection fail err code:" << GetLastError() << std::endl; return false; } }
調(diào)用觸摸鍵盤
bool ScreenKeyBoard::OpenTabTipByProcess(const std::wstring& tabTipPath) { //將進(jìn)程TabTip.exe拉起,如果是進(jìn)程存在的情況下,再次調(diào)用會(huì)直接顯示鍵盤界面 if (!ShellExecuteW(NULL, L"open", tabTipPath.c_str(), NULL, NULL, SW_SHOWNORMAL)) { std::cerr << "ShellExecuteW tabTip err:" << GetLastError() << std::endl; return false; } std::cout << "ShellExecuteW tabTip success"; return true; }
調(diào)用觸摸鍵盤
COM調(diào)用方式,不知道COM的需要自己惡補(bǔ)下知識(shí),和windows打交道還是很香的,但坑也多
bool ScreenKeyBoard::OpenTabTipByProcess(const std::wstring& tabTipPath) { //將進(jìn)程TabTip.exe拉起,如果是進(jìn)程存在的情況下,再次調(diào)用會(huì)直接顯示鍵盤界面 if (!ShellExecuteW(NULL, L"open", tabTipPath.c_str(), NULL, NULL, SW_SHOWNORMAL)) { std::cerr << "ShellExecuteW tabTip err:" << GetLastError() << std::endl; return false; } std::cout << "ShellExecuteW tabTip success"; return true; }
根據(jù)系統(tǒng)版本選擇調(diào)用觸摸鍵盤的方式
bool ScreenKeyBoard::OpenScreenKeyboard() { if (!IsTabTipAutoInvokeOnDesktopMode()) { return OpenTabTip(); } //觸摸鍵盤有一設(shè)置項(xiàng):不處于平板電腦模式且未連接鍵盤時(shí)顯示觸摸鍵盤,增加延遲避開(kāi)系統(tǒng)調(diào)用鍵盤 std::thread([]() { PublicUtils::Sleep(std::chrono::milliseconds(500)); OpenTabTip(); }).detach(); return true; } bool ScreenKeyBoard::OpenTabTip() { auto version = PublicUtils::Environment::OsVersion(); std::cout << "os version:" << version.ToString() << std::endl; if (IsNewTabTipKeyboardVisable() || IsOldTabTipKeyboardVisable()) { std::cout << "keyboard is visible" << std::endl; return true; } //系統(tǒng)版本大于等于win10 10.0.14393.0,需要使用com組件的接口才能將鍵盤界面顯示出來(lái) if (10 == version.GetMajor() && version.GetPatch() >= 14393) { return OpenTabTipByCom(kTabTipPath); } else { return OpenTabTipByProcess(kTabTipPath); } }
在調(diào)用觸摸鍵盤前有一個(gè)代碼片段用來(lái)判斷觸摸鍵盤是否處于顯示狀態(tài),這是為什么呢?
因?yàn)橛|摸鍵盤TabTip沒(méi)有明確的接口區(qū)分顯示和隱藏,當(dāng)調(diào)用時(shí)會(huì)根據(jù)當(dāng)前的狀態(tài)決定下一個(gè)狀態(tài),即隱藏時(shí)調(diào)用會(huì)顯示,顯示時(shí)調(diào)用會(huì)隱藏,所以就需要我們自己判斷鍵盤狀態(tài)
- 判斷鍵盤狀態(tài),Spy++抓觸摸鍵盤窗口,自己分析一些特性
- 需要注意觸摸鍵盤這個(gè)設(shè)置項(xiàng)的作用,在代碼中需要做處理(這個(gè)設(shè)置開(kāi)啟后系統(tǒng)會(huì)檢測(cè)到有輸入框聚焦時(shí)自動(dòng)調(diào)起觸摸鍵盤,如果你在代碼中去調(diào)用的話,可能會(huì)存在一些沖突)
 bool ScreenKeyBoard::IsNewTabTipKeyboardVisable() { //win10下父窗口是ApplicationFrameWindow子窗口是Windows.UI.Core.CoreWindow HWND parent = FindWindowExW(NULL, NULL, kWindowParentClass, NULL); if (!parent) { std::cerr << "no more windows, keyboard state is unknown. class:" << PublicUtils::CharsetUtils::UnicodeToUTF8(kWindowParentClass) << std::endl; return false; } HWND wnd = FindWindowExW(parent, NULL, kWindowClass, kWindowCaption); if (!wnd) { std::cerr << "it's a child of a WindowParentClass1709 window - the keyboard is open. class:" << PublicUtils::CharsetUtils::UnicodeToUTF8(kWindowClass) << " caption" << PublicUtils::CharsetUtils::UnicodeToUTF8(kWindowCaption) << std::endl; return false; } //觸摸鍵盤顯示和隱藏不能用IsWindowVisible判斷,判斷方式可參考 https://stackoverflow.com/questions/32149880/how-to-identify-windows-10-background-store-processes-that-have-non-displayed-wi int cloaked = 0; if (DwmGetWindowAttribute(wnd, DWMWA_CLOAKED, &cloaked, DWM_CLOAKED_INHERITED) != S_OK) { std::cerr << "DwmGetWindowAttribute err:" << GetLastError() << std::endl; return false; } std::cout << "DwmGetWindowAttribute cloaked=" << cloaked; return 0 == cloaked; } bool ScreenKeyBoard::IsOldTabTipKeyboardVisable() { HWND touchhWnd = FindWindowW(kKeyboardWindowClass, NULL); if (!touchhWnd) { std::cerr << "without window:" << PublicUtils::CharsetUtils::UnicodeToUTF8(kKeyboardWindowClass) << std::endl; return false; } unsigned long style = GetWindowLong(touchhWnd, GWL_STYLE); // 由于有的系統(tǒng)在鍵盤不顯示時(shí)候只是多返回一個(gè)WS_DISABLED這個(gè)字段。所以加一個(gè)它的判斷 std::cout << "WS_CLIPSIBLINGS:" << (style & WS_CLIPSIBLINGS) << " WS_VISIBLE:" << (style & WS_VISIBLE) << " WS_POPUP:" << (style & WS_POPUP) << " WS_DISABLED:" << !(style & WS_DISABLED) << std::endl; return (style & WS_CLIPSIBLINGS) && (style & WS_VISIBLE) && (style & WS_POPUP) && !(style & WS_DISABLED); }
到此這篇關(guān)于c++調(diào)用windows
鍵盤代碼詳情的文章就介紹到這了,更多相關(guān)c++調(diào)用windows
鍵盤內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)BMP圖像邊緣檢測(cè)處理
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)BMP圖像邊緣檢測(cè)處理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10C++實(shí)現(xiàn)并優(yōu)化異常系統(tǒng)
異常處理是C++的一項(xiàng)語(yǔ)言機(jī)制,用于在程序中處理異常事件,下面這篇文章主要給大家介紹了關(guān)于C++中異常的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08C語(yǔ)言實(shí)現(xiàn)JSON解析器的方法步驟
JSON是一種非常流行的數(shù)據(jù)格式,本文主要介紹了C語(yǔ)言實(shí)現(xiàn)JSON解析器的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-08-08C++中拷貝構(gòu)造函數(shù)的總結(jié)詳解
深拷貝和淺拷貝可以簡(jiǎn)單理解為:如果一個(gè)類擁有資源,當(dāng)這個(gè)類的對(duì)象發(fā)生復(fù)制過(guò)程的時(shí)候,資源重新分配,這個(gè)過(guò)程就是深拷貝,反之,沒(méi)有重新分配資源,就是淺拷貝2013-09-09C語(yǔ)言詳解數(shù)據(jù)結(jié)構(gòu)與算法中枚舉和模擬及排序
枚舉和模擬其實(shí)是沒(méi)什么算法可言的,大多數(shù)都是按照題目意思去寫,這里提供快排和歸并的兩個(gè)模板,感興趣的朋友來(lái)看看吧2022-04-04淺析C++模板類型中的原樣轉(zhuǎn)發(fā)和可變參數(shù)的實(shí)現(xiàn)
可變參數(shù)模板(variadic templates)是C++11新增的強(qiáng)大的特性之一,它對(duì)模板參數(shù)進(jìn)行了高度泛化,能表示0到任意個(gè)數(shù)、任意類型的參數(shù),這篇文章主要介紹了C++可變參數(shù)模板的展開(kāi)方式,需要的朋友可以參考下2022-08-08C語(yǔ)言課程設(shè)計(jì)之抽獎(jiǎng)系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言課程設(shè)計(jì)之抽獎(jiǎng)系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12