マルチスレッドでグローバルフックするときの注意
今日のキーワード:
SetWindowsHookEx
、WH_KEYBOARD_LL
(WH_MOUSE_LL
)- マルチスレッド
- グローバルフック
やりたいこと
メインの UI スレッドとは別スレッドでグローバルフックしたい。
例えば、描画の処理が重い場合、UI スレッドがそちらの処理で手間取り、キーボードやマウスの入力を処理できなくなる可能性があります。そういった場合、別スレッドでキーボード等での入力処理を取り扱いたくなります。
結論から
UI スレッド以外で、SetWindowsHookEx
を呼び出すときは注意が必要ですよ、というお話。
Why? なぜなのか
This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.
LowLevelKeyboardProc callback function (Windows) より
低レベルキーボードフック (WH_KEYBOARD_LL
) を使用する場合、SetWindowsHookEx
を呼びだすスレッドは、メッセージループを持っていなきゃ駄目という記載が MSDN にあります。
これを忘れていて僕はドハマりしました……。SetWindowsHookEx
が失敗する?エラー?なんでだ?で数時間悩みました。
How? どうやって対処するのか
別スレッドにメッセージループを持たせて、別 UI スレッドにしちゃいましょう。C# (というか .NET系)の場合、以下のページが参考になります。
メッセージループをアプリケーション内で複数作ってみる - 亀岡的プログラマ日記
メッセージループを持つスレッドが複数ある状態になりますが、場合によっては効果的だと思います。先程の例であれば、描画に専念する UI スレッドと、入力に対する処理に専念する UI スレッドのように専業化し、そのメリット、デメリットを考えて、有効なら取り入れるという形ですかね。UIAssistant には取り入れて入力のレスポンスをよくする予定です。