如何在 Windows Vista/7 中以编程方式控制文本输入面板 (TabTip.exe)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1770670/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I control the text input panel programmatically (TabTip.exe) in Windows Vista/7
提问by Yngve Hammersland
I'm adapting an application for touch screen interface and we want to use the tablet text input panel included in Windows Vista/7, specifically its keyboard. I want to show and hide it as appropriate for my app. Basically I want ShowKeyboard()
and HideKeyboard()
functions. What's the best way to control this?
我正在为触摸屏界面调整应用程序,我们想使用 Windows Vista/7 中包含的平板电脑文本输入面板,特别是它的键盘。我想根据我的应用程序显示和隐藏它。基本上我想要ShowKeyboard()
和HideKeyboard()
功能。控制这种情况的最佳方法是什么?
I looked at the ITextInputPanel API but I was unable to control the keyboard directly with it (maybe I missed something?). I have also unsuccessfully tried to send window messages to its window.
我查看了 ITextInputPanel API,但无法直接用它控制键盘(也许我错过了什么?)。我也尝试将窗口消息发送到它的窗口,但没有成功。
The application is written in C++/MFC.
该应用程序是用 C++/MFC 编写的。
Any pointers at all are greatly appreciated.
任何指针都非常感谢。
采纳答案by Yngve Hammersland
I solved the problem. It turns out that Spy++ really is a Windows programmers best friend.
我解决了这个问题。事实证明,Spy++ 确实是 Windows 程序员最好的朋友。
First, the window class of the input panel window turns out to be "IPTip_Main_Window". I use this to get the window handle like so:
首先,输入面板窗口的窗口类原来是“IPTip_Main_Window”。我用它来获取窗口句柄,如下所示:
HWND wKB = ::FindWindow(_TEXT("IPTip_Main_Window"), NULL);
It turns out that I can just post the same WM_COMMAND messages that its own menu is sending. Most of the operations are available from the menu: dock top, dock bottom and float. The code for sending those messages are:
事实证明,我可以只发布它自己的菜单发送的相同 WM_COMMAND 消息。大多数操作都可以从菜单中获得:停靠顶部、停靠底部和浮动。发送这些消息的代码是:
::PostMessage(wKB, WM_COMMAND, MAKEWPARAM(X,0) , 0);
where X is 10021 for dock bottom, 10023 for dock top and 10020 for floating. The 0 in the high word indicates that the message is sent from a menu.
其中 X 为 10021 为船坞底部,10023 为船坞顶部和 10020 为浮动。高位字中的 0 表示消息是从菜单发送的。
Finally, I wanted to be able to show and hide the input panel. I noticed that I could turn on a desk band which only includes a single button for toggling the visibility of the input panel. Spy++ing on the messages posted from this button revealed that it sends a global registered window message which is named "TabletInputPanelDeskBandClicked". Sending this message to the input panel causes it to toggle its visibility.
最后,我希望能够显示和隐藏输入面板。我注意到我可以打开一个只包含一个按钮的桌面乐队,用于切换输入面板的可见性。对从该按钮发布的消息进行间谍 ++ 发现它发送了一个名为“TabletInputPanelDeskBandClicked”的全局注册窗口消息。将此消息发送到输入面板会导致它切换其可见性。
The HideKeyboard() function now looks like this:
HideKeyboard() 函数现在看起来像这样:
DWORD WM_DESKBAND_CLICKED = ::RegisterWindowMessage(_TEXT("TabletInputPanelDeskBandClicked")); void HideKeyboard() { HWND wKB = ::FindWindow(_TEXT("IPTip_Main_Window"), NULL); if(wKB != NULL && ::IsWindowVisible(wKB)) { ::PostMessage(wKB, WM_DESKBAND_CLICKED, 0, 0); } }
The ShowWindow() function is implemented similarly, but it will also start the keyboard if it is not running.
ShowWindow() 函数的实现方式类似,但如果它没有运行,它也会启动键盘。
Update:
更新:
It seems that this inter-process messaging is disallowed in Windows Vista/7. When running this command in a non-elevated process it will fail with "access denied". My guess is that this is caused by User Interface Process Isolation (UIPI) protection found in Windows Vista/7. Since the Tablet PC Input Panel is running as a child process of a service it has higher integrity level than user programs, and thus cannot be sent any (or a very limited set of) messages to.
Windows Vista/7 中似乎不允许这种进程间消息传递。在非提升进程中运行此命令时,它将失败并显示“拒绝访问”。我的猜测是,这是由 Windows Vista/7 中的用户界面进程隔离 (UIPI) 保护引起的。由于 Tablet PC 输入面板作为服务的子进程运行,它具有比用户程序更高的完整性级别,因此无法向其发送任何(或非常有限的一组)消息。
Update:
更新:
It turns out that the Tablet PC Input Panel is indeed running in high integrity level, whereas processes started by a limited user account is medium integrity level.
事实证明,Tablet PC 输入面板确实以高完整性级别运行,而由受限用户帐户启动的进程是中等完整性级别。
回答by Ryand
For Windows 8:
对于 Windows 8:
Note: Just like the Windows 7 solution, this requires an elevated process.
注意:就像 Windows 7 解决方案一样,这需要一个提升的过程。
The input panel is not a descendant of HWND_DESKTOP. (It's probably some kind of Metro window.) In order to get the window handle, do a series of horizontal sweeps in a grid-like pattern testing with WindowFromPoint(). For each test, check the window class of the parent window to see if it is "IPTip_Main_Window".
输入面板不是 HWND_DESKTOP 的后代。(它可能是某种 Metro 窗口。)为了获得窗口句柄,使用 WindowFromPoint() 在类似网格的模式测试中进行一系列水平扫描。对于每个测试,检查父窗口的窗口类是否为“IPTip_Main_Window”。
To show the input panel, launch "C:\\Program Files\\Common Files\\microsoft shared\\ink\\tabtip.exe"
. To determine if it is already in docked mode, read registry key:
要显示输入面板,请启动"C:\\Program Files\\Common Files\\microsoft shared\\ink\\tabtip.exe"
。要确定它是否已经处于停靠模式,请阅读注册表项:
HKEY_CURRENT_USER\Software\Microsoft\TabletTip.7\EdgeTargetDockedState
A value of 0 indicates the input panel is in floating mode. If that was the case, post the following message to toggle the docked state:
值为 0 表示输入面板处于浮动模式。如果是这种情况,请发布以下消息以切换停靠状态:
DWORD WM_DOCK_BUTTON_PRESSED = ::RegisterWindowMessage(_TEXT("IPTipDockButtonPressed"));
PostMessage(hwndInputPanel, WM_DOCK_BUTTON_PRESSED, 0, 0);
To hide the keyboard, post the following:
要隐藏键盘,请发布以下内容:
PostMessage(hwndInputPanel, WM_SYSCOMMAND, SC_CLOSE, 0);