概念的に単純なことをしたいのですが、キーボード入力を受け入れるすべてのコントロール(CEdit、編集可能なテキストを含むCComboboxなど)について、コントロールがフォーカスされて有効になっているときに、オンスクリーンキーボードを表示します。できれば、osk.exeユーティリティを直接呼び出すのではなく、アクセシビリティのサポート(Microsoftユーザーインターフェイスの自動化について読んだことがあります)を使用することをお勧めします。
ユーザーが編集可能なコントロールに焦点を合わせたときのタッチスクリーンスマートフォンに非常に似ています。
更新:オンスクリーンキーボードを私が説明したように動作させることができるWindowsオプションがある場合、それは問題ありません!
更新2:必要なものはhttp://msdn.microsoft.com/en-us/library/windows/apps/hh465404.aspxに似ていますが、Windows7にあります。
私はIUIAutomationクラスで実験を行い、編集可能なコントロールにフォーカスするときにosk.exeを直接呼び出し、編集不可能なコントロールにフォーカスするときにそのウィンドウを閉じました。
しかし、私にはまだ3つの問題があります。
1)CFileDialogアプリケーションを開くと応答しなくなります。同じことが、アプリケーションの別のモーダルダイアログでのみ発生します(他のすべてのモーダルダイアログでは、すべてが正常に機能します)。私は、CFileDialogがいくつかのバックグラウンドスレッドを開き、私の唯一の問題のあるモーダルも開くことを発見しました。これはスレッドの問題に関係していると思います。
2)他のコントロールにフォーカスがあり、その後、編集コントロールを選択せずに、CBS_DROPDOWNコンボボックスのドロップダウンボタンを直接クリックすると、OSKのフラッシュが表示されたり消えたりします。Spy++とUIAInspectを使用すると、コンボボックスがドロップ状態になる前に、テキスト編集がフォーカスされている疑いがありました。
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ウィンドウはどこにも移動されていません。多分それは積極的に位置指示を拒否しています。
このAutoItスクリプトを試してTabtip.exeウィンドウを移動しようとしましたが、失敗します。このスクリプトを試して、Visual Studioコマンドプロンプトのウィンドウを移動すると、移動します。GRRRRR!
更新3:私には、これはユーザーアクセス制御とアクセス許可に関係しているようです。ユーザーアクセス制御を無効にするか、管理者としてアプリケーションを実行すると、MoveWindow命令は完全に機能します。同じことがOSKMainCLASSウィンドウを動かそうとしているAutoItにも当てはまります!それで、OSKアプリケーションに例外を設けることを許可するWindows 7のローカルまたはグループポリシーはありますか?
4)64ビットオペレーティングシステムでosk.exeを実行するために、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 :: GetDesktopWindow()のすべてのGW_CHILDウィンドウをトラバースして、GetClassName(...)が「OSKMainClass」で何も見つからないウィンドウを検索する関数があります。