title: Key listener written in Java JNA. Cannot stop the thread
body: <p>I use the following code to listen to global key events:</p>
  
  <p>Win32HookManager.java</p>
  
  <pre><code>import com.sun.jna.platform.win32.Kernel32;
  import com.sun.jna.platform.win32.User32;
  import com.sun.jna.platform.win32.WinDef.HMODULE;
  import com.sun.jna.platform.win32.WinDef.LRESULT;
  import com.sun.jna.platform.win32.WinDef.WPARAM;
  import com.sun.jna.platform.win32.WinUser;
  import com.sun.jna.platform.win32.WinUser.HHOOK;
  import com.sun.jna.platform.win32.WinUser.KBDLLHOOKSTRUCT;
  import com.sun.jna.platform.win32.WinUser.LowLevelKeyboardProc;
  import com.sun.jna.platform.win32.WinUser.MSG;
  
  
  import java.awt.event.KeyEvent;
  
  public class Win32HookManager {
      private static HHOOK keyboardHook;
  
      public static boolean installKeyboardHook(final NativeKeyboardListener listener) {
          final User32  lib  = User32.INSTANCE;
          final HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null);
  
          final LowLevelKeyboardProc keyboardHookProc = new LowLevelKeyboardProc() {
              @Override
              public LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT info) {
                  NativeKeyboardEvent ev = null;
                  long                ti = System.currentTimeMillis();
                  boolean             nh = true;
  
                  if (nCode &gt;= 0) {
                      switch (wParam.intValue()) {
                          case WinUser.WM_KEYDOWN:
                          case WinUser.WM_SYSKEYDOWN:
                              ev = new NativeKeyboardEvent(KeyEvent.KEY_PRESSED, ti, 0, info.vkCode);
                              nh = listener.keyPressed(ev);
                              break;
  
                          case WinUser.WM_KEYUP:
                          case WinUser.WM_SYSKEYUP:
                              ev = new NativeKeyboardEvent(KeyEvent.KEY_RELEASED, ti, 0, info.vkCode);
                              nh = listener.keyReleased(ev);
                              break;
                      }
                  }
  
                  if(nh) {
                      return lib.CallNextHookEx(keyboardHook, nCode, wParam, info.getPointer());
                  }
                  return new LRESULT(1);
              }
          };
  
          new Thread() {
              @Override
              public void run() {
                  keyboardHook = lib.SetWindowsHookEx(WinUser.WH_KEYBOARD_LL, keyboardHookProc, hMod, 0);
                  msgLoop();
                  lib.UnhookWindowsHookEx(keyboardHook);
              }
          }.start();
  
          return keyboardHook != null;
      }
  
      public static boolean uninstallKeyboardHook() {
          if(keyboardHook != null) {
              return User32.INSTANCE.UnhookWindowsHookEx(keyboardHook);
          }
  
          return false;
      }
  
      private static void msgLoop()
      {
          final User32 lib = User32.INSTANCE;
  
          int result;
          MSG msg = new MSG();
          while ((result = lib.GetMessage(msg, null, 0, 0)) != 0) {
              if (result == -1) {
                  System.err.println("error in get message");
                  break;
              }
              else {
                  System.err.println("got message");
                  lib.TranslateMessage(msg);
                  lib.DispatchMessage(msg);
              }
          }
      }
  }
  </code></pre>
  
  <p>NativeKeyboardListener </p>
  
  <pre><code>public interface NativeKeyboardListener {
      public boolean keyPressed (NativeKeyboardEvent e);
      public boolean keyReleased(NativeKeyboardEvent e);
  }
  </code></pre>
  
  <p>NativeKeyboardEvent </p>
  
  <pre><code>public class NativeKeyboardEvent {
      private int  id;
      private int  keyCode;
  
      public NativeKeyboardEvent(int id, long when, int modifiers, int keyCode) {
          this.id        = id;
          this.keyCode   = keyCode;
      }
  
      public int getId() {
          return id;
      }
  
      public int getKeyCode() {
          return keyCode;
      }
  }
  </code></pre>
  
  <p>Unfortunately, it doesn't work as I expected, i.e. it detects when a key is pressed/released, but it cannot finish the thread started by installKeyboardHook() method because of GetMessage() in msgLoop method. Yes, I can stop listening to key events, but I cannot stop the thread. However, it seems that GetMessage() is needed in this code. Do you see any workaround for this problem?</p>
  
  <p>Thanks!   </p>