我想做一件概念上很简单的事情:对于每个接受键盘输入的控件(CEdit,带有可编辑文本的CCombobox等),当控件被聚焦并启用时,使屏幕键盘出现。最好有可访问性支持(我已经读了一些关于微软用户界面自动化的文章),而不是直接调用osk.exe实用程序。
当用户把焦点放在一个可编辑的控件上时,就像触屏智能手机一样。
更新:如果有一个Windows选项可以使屏幕键盘的行为方式,我描述的,那就好了!
更新2:我想要的东西是类似于http://msdn.microsoft.com/en-us/library/windows/apps/hh465404.aspx,但在Windows 7。
我已经用IUIAutomation类做了实验,在聚焦可编辑控件时直接调用osk.exe,并在聚焦不可编辑控件时关闭该窗口。
但是,我仍然有三个问题:
1)当打开一个CFileDialog应用程序变得无响应。同样的情况只发生在应用程序的另一个模态对话框中(在所有其他模态对话框中一切正常)。我发现CFileDialog打开了一些后台线程和我唯一有问题的模态。我怀疑这与线程问题有关。
2)当一些其他控件集中,此后我直接单击CBS_DROPDOWN组合框的下拉按钮,而不是选择其编辑控件,我看到OSK的闪烁出现和消失。使用spy++和UIA Inspect,我怀疑在组合框进入掉落状态之前文本编辑被聚焦。
3)用SetWindowPos、MoveWindow做了一些实验后
::MoveWindow(osk_wnd->m_hWnd, LeftOsk, TopOsk, -1, -1, FALSE);
或
osk_wnd->SetWindowPos(NULL, LeftOsk, TopOsk, -1, -1, SWP_NOSIZE | SWP_NOACTIVATE);
和使用一些消息处理实验,如
//osk_wnd is a CWnd* variable that represents OSK main window
osk_wnd->PostMessage(WM_SYSCOMMAND, SC_MOVE + HTCAPTION, MAKELPARAM(point.x, point.y));
或
POINT point = {0};
GetCursorPos(&point);
SendMessage(osk_wnd->m_hWnd, WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x, point.y));
SendMessage(osk_wnd->m_hWnd, WM_NCMOUSEMOVE, HTCAPTION, MAKELPARAM(LeftOsk, TopOsk));
GetCursorPos(&point);
SendMessage(osk_wnd->m_hWnd, WM_NCLBUTTONUP, HTCAPTION, MAKELPARAM(LeftOsk + point.x, TopOsk + point.y));
无法移动OSK窗口。重要的是我可以移动它;否则,它将出现覆盖焦点控件,并且用户无法看到他给控件的输入!附注:以下代码用于取消最小化OSK窗口工作得很好:
if(osk_wnd->IsIconic())
osk_wnd->PostMessage(WM_SYSCOMMAND, SC_RESTORE, NULL);
即使尝试使用AutoIt脚本移动该窗口也没有任何效果:
If WinActivate("[CLASS:OSKMainClass]") Then
If WinWaitActive("[CLASS:OSKMainClass]") Then
ConsoleWrite("activ" & @CRLF)
Sleep(500)
If WinMove("[CLASS:OSKMainClass]", "", 30 ,320,360,123) Then
ConsoleWrite("move 1" & @CRLF)
EndIf
EndIf
EndIf
If WinMove("[CLASS:OSKMainClass]", "", 30 ,320,360,123) Then
ConsoleWrite("move 2" & @CRLF)
EndIf
我看到文本
活性
移动1
移动2
正在打印,但是OSK窗口没有移动到任何地方。也许它在主动拒绝定位指令。
我尝试了这个自动脚本来移动Tabtip.exe窗口,它也失败了。我尝试这个脚本移动Visual Studio命令提示符的窗口,它移动!了呃!
更新3:在我看来,这件事与用户访问控制和权限有关。如果我禁用用户访问控制或以管理员身份运行应用程序,MoveWindow指令工作完美!这同样适用于AutoIt试图移动OSKMainCLASS窗口!那么,Windows 7中是否有一些本地或组策略允许我对OSK应用程序进行例外处理?
4)为了让osk.exe在64位操作系统上运行,我尝试了所有不强制禁用SysWOW64重定向的方法,但我无法逃脱它。到目前为止,我还没有发现任何问题,但也许下面的代码会在未来造成问题。
const int sysDirNameSize= 1024;
TCHAR sysDir[sysDirNameSize];
if( !GetSystemDirectory( sysDir, sysDirNameSize) )
{
ASSERT(FALSE);
return;
}
CString osk_path = CString(sysDir) + _T("\osk.exe");
PVOID pOldValue = NULL;
BOOL bRes= Wow64DisableWow64FsRedirection(&pOldValue);
::ShellExecute(NULL, NULL, osk_path, _T("") , sysDir, SW_SHOW);
if(bRes)
Wow64RevertWow64FsRedirection(pOldValue);
更新5:似乎最后一次我试图执行osk.exe进程开始,但它的窗口没有出现!要将值属性为osk_wnd,我有一个函数遍历CWnd的所有GW_CHILD窗口::GetDesktopWindow()以搜索GetClassName(…)为"OSKMainClass"的窗口,并且没有找到!
我又一次自己解决了这个问题:)
1)阅读http://social.msdn.microsoft.com/Forums/br/windowsaccessibilityandautomation/thread/aee0be4d-2cf5-45e7-8406-2de3e5d0af03和http://www.c-plusplus.de/forum/285011-full(德语,但谷歌翻译可以帮助)后,我决定把代码相关的一个单独的线程。打开CFileDialog窗口时不再挂起:)
项目经理说这是个小问题:)
3)在对项目经理说在执行osk.exe时需要传递一个安全令牌后,他回答说这会给一个非常简单的事情带来很多复杂性,最好是应用程序可以在管理模式下运行:)
直到现在还没有引起问题,所以顺其自然吧:)
无论如何,谢谢你的帮助。
用于移动OSK窗口。最初通过命令提示符将低完整性设置为询问屏幕。然后使用移动窗口函数。会成功的