Search code examples
javaeventskeyboardjna

Java JNA Consume Keyhook Callback


I was looking for a keyhook library using JNA and found a demo on their github

public final class Test {

private static volatile boolean quit;
private static WinUser.HHOOK hhk;
private static WinUser.LowLevelKeyboardProc keyboardHook;

public static void main(String[] args) {
    final User32 lib = User32.INSTANCE;
    WinDef.HMODULE hMod = Kernel32Direct.GetModuleHandle(null);
    keyboardHook = new WinUser.LowLevelKeyboardProc() {
        @Override
        public WinDef.LRESULT callback(int nCode, WinDef.WPARAM wParam, WinUser.KBDLLHOOKSTRUCT info) {
            if (nCode >= 0) {
                switch (wParam.intValue()) {
                    case WinUser.WM_KEYUP:
                    case WinUser.WM_KEYDOWN:
                    case WinUser.WM_SYSKEYUP:
                    case WinUser.WM_SYSKEYDOWN:
                        System.err.println("in callback, key=" + info.vkCode);
                        if (info.vkCode == 81) {
                            quit = true;
                        }
                        break;
                }
            }

            Pointer ptr = info.getPointer();
            long peer = Pointer.nativeValue(ptr);
            return lib.CallNextHookEx(hhk, nCode, wParam, new WinDef.LPARAM(peer));
        }
    };
    hhk = lib.SetWindowsHookEx(WinUser.WH_KEYBOARD_LL, keyboardHook, hMod, 0);
    System.out.println("Keyboard hook installed, type anywhere, 'q' to quit");
    new Thread() {
        @Override
        public void run() {
            while (!quit) {
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                }
            }
            System.err.println("unhook and exit");
            lib.UnhookWindowsHookEx(hhk);
            System.exit(0);
        }
    }.start();

    // This bit never returns from GetMessage
    int result;
    WinUser.MSG msg = new WinUser.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);
        }
    }
    lib.UnhookWindowsHookEx(hhk);
}

}

I was wondering how could I consume a key press like you can using Swing/AWT events?

For example: If a user types the letter h, how do I make it so the keypress won't be processed further than my keyboard hook and consume it?

Thanks!


Solution

  • In order to consume a key you must return new WinDef.LRESULT(1).

    Example:

                   keyboardHook = (nCode, wParam, info) -> {
                        if (nCode >= 0) {
                            NativeKeyEvent event = new NativeKeyEvent(info.vkCode, info.time);
                            switch (wParam.intValue()) {
                                case WinUser.WM_KEYDOWN:
                                case WinUser.WM_SYSKEYDOWN:
                                    dispatch(EventType.KEY_DOWN, event);
                                    break;
                                case WinUser.WM_KEYUP:
                                case WinUser.WM_SYSKEYUP:
                                    dispatch(EventType.KEY_UP, event);
                                    break;
                            }
                            if (event.consumed()) {
                                return new WinDef.LRESULT(1);
                            }
                        }
                        return new WinDef.LRESULT(0);
                    };