時間のかかる処理を行っっているときに押されたキーイベントを破棄しているアプリケーションをよく見かけます。そうすることで「おかしいな、何も起きないぞ」と何度も押されたキー入力を無効にしているのです。
しかし、そのような処理を行っているアプリに対してkeybd_event
でキーボードイベントを発射して操作しようとすると、そのキーイベント中に時間のかかる処理が始まると思うように操作できなくなってしまいます。
そうならないようにするためには、キーイベントを受け付けてくれるようになるまで待つしかありません。それではどういう状態になればキーイベントを受け付けてくれるのでしょうか?
キーイベントはメッセージキューにつまれて処理されますから、PostMessage
等でキューにつまれたメッセージが処理されるようならばキーイベント等も処理するだけの余裕があると考えて良いでしょう。
また、他スレッドからのSendMessage
は一旦メッセージキューにつまれ、そのメッセージキューが処理されてから戻ってくる、というWindows95/98の仕様が有ります(情報源は忘れました^^;)。
という訳でこのTIPSは95/98用です。NT用のいい方法があれば教えてください。
上記二つの条件からSendMessage
をそのウィンドウに対して行い、戻ってくればキーイベントを処理できる状態であると考えられます。送るメッセージは何でもよいので、この場合何もしないメッセージであるWM_NULL
がいいでしょう。
- void WaitInputIdle(HWND hWnd)
- {
- // キーボードイベントに対して応答可能になるまで待つ
- ::SendMessage(hTarget, WM_NULL, 0, 0);
- }
ただし、これではアプリケーションがなかなか終らない、もしくはハングアップしてしまっている場合にこちらのアプリまでハングアップしてしまいます。そこでSendMessageCallback
を使うことにより、待ち時間にも他の処理を行えるようにしておいた方がいいでしょう。
- void CALLBACK SAP_WaitInputIdle(HWND hWnd, UINT uMsg, DWORD dwData, LRESULT lResult)
- {
- // フラグをリセットする
- *((LPBOOL)dwData) = FALSE;
- }
- void WaitInputIdle(HWND hWnd)
- {
- BOOL bContinue = TRUE;
- SendMessageCallback(hWnd, WM_NULL, 0, 0, SAP_WaitInputIdle, (DWORD) &bContinue);
- MSG msg;
- while (bContinue){
- // PeekMessageを呼ばないとSAP_WaitInputIdleも呼ばれない
- PostMessage(NULL, WM_USER, 0, 0);
- PeekMessage(&msg, (HWND) -1, WM_USER, WM_USER, PM_REMOVE);
- }
- }