Запуск цикла сообщений в потоке - PullRequest
0 голосов
/ 15 января 2019

Я хочу запустить низкоуровневый хук клавиатуры, используя JNA. Я адаптировал пример, найденный в папке JNA contrib

private static HHOOK keyHook;
private static LowLevelKeyboardProc keyCallback;

public static void main(String[] args) {
   final User32 U32 = User32.INSTANCE;
   final Kernel32 K32 = Kernel32.INSTANCE;

   HMODULE module = K32.GetModuleHandle(null); 
   keyCallback = (int code, WPARAM wParam, KBDLLHOOKSTRUCT info) -> {
      if (code >= 0) {
         System.err.println("Key=" + info.vkCode);
         if (info.vkCode == 81) {
           U32.PostQuitMessage(0);
         }
      }
      long peer = Pointer.nativeValue(info.getPointer());
      return U32.CallNextHookEx(keyHook, code, wParam, new LPARAM(peer));
   };
   keyHook = U32.SetWindowsHookEx(WH_KEYBOARD_LL, keyCallback, module, 0);
   System.out.println("Hook installed, type anywhere, 'q' to quit");

   MSG msg = new MSG();
   while (U32.GetMessage(msg, null, 0, 0) > 0) {         
      U32.TranslateMessage(msg);
      U32.DispatchMessage(msg);               
   }
   U32.UnhookWindowsHookEx(keyHook);
}

Это работает, как ожидалось. Однако теперь я хочу запустить цикл сообщений в потоке, чтобы избежать блокировки моего приложения. Наивный подход будет

Executor thread = Executors.newSingleThreadExecutor();
thread.execute(() -> {
   int result;
   MSG msg = new MSG();
   while ((result = U32.GetMessage(msg, null, 0, 0)) > 0) {         
      U32.TranslateMessage(msg);
      U32.DispatchMessage(msg);               
   }
   U32.UnhookWindowsHookEx(keyHook);
});

К сожалению, это не работает. Обратный вызов больше не вызывается, и клавиатурные входы в системе начинают сильно отставать. Как я могу правильно заправить цикл сообщений? Я полагаю, мне нужно найти идентификатор потока и передать его в SetWindowsHookEx вместо 0, но как получить этот идентификатор?

Edit: я попробовал другой подход, заключив в единое целое весь процесс регистрации хуков и цикл обработки сообщений. Обратный вызов теперь работает правильно, но PostQuitMessage, похоже, не отправляет сообщение в правильную очередь, и поток не может быть остановлен. PostThreadMessage(0, User32.WM_QUIT, null, null) также не работает в этом случае.

1 Ответ

0 голосов
/ 17 января 2019

Я обнаружил, что решение на самом деле уже предоставляется платформой JNA в User32Util.MessageLoopThread

...