Search code examples
javawinapijna

JNA KeyboardUtils.isPressed not working with arrow keys


I'm trying to create a sample that calls JNA's KeyboardUtils class to check key states on Windows (similar to Win32's GetAsyncKeyState()).

Here's my code:

package com.foo;

import com.sun.jna.platform.KeyboardUtils;
import java.awt.event.KeyEvent;

public class Main {
    public static void main(String[] args) {
        new Thread() {
            @Override
            public void run() {
                System.out.println("Watching for Left/Right/Up/Down or WASD.  Press Shift+Q to quit");
                while (true) {
                    try
                    {
                        Thread.sleep(10);
                        if (KeyboardUtils.isPressed(KeyEvent.VK_DOWN) || KeyboardUtils.isPressed(KeyEvent.VK_S) )
                        {
                            System.out.println("Down");
                        }
                        if (KeyboardUtils.isPressed(KeyEvent.VK_UP) || KeyboardUtils.isPressed(KeyEvent.VK_W) )
                        {
                            System.out.println("Up");
                        }
                        if (KeyboardUtils.isPressed(KeyEvent.VK_LEFT) || KeyboardUtils.isPressed(KeyEvent.VK_A) )
                        {
                            System.out.println("Left");
                        }
                        if (KeyboardUtils.isPressed(KeyEvent.VK_RIGHT) || KeyboardUtils.isPressed(KeyEvent.VK_D) )
                        {
                            System.out.println("Right");
                        }
                        if (KeyboardUtils.isPressed(KeyEvent.VK_Q) && KeyboardUtils.isPressed(KeyEvent.VK_SHIFT) )
                        {
                            break;
                        }
                    }
                    catch(Exception e)
                    { }
                }
                System.exit(0);
            }
        }.start();
    }
}

This works fine and detects WASD keys, as well as Shift+Q. However, the arrow keys Left/Right/Up/Down are never detected.

Converting the code to C++ and calling Win32 GetAsyncKeyState() does work with the arrow keys.

According to the web, the value of KeyEvent.VK_DOWN matches the Win32 definition (40).

Any idea why JNA isn't correctly detecting the arrow keys?


Solution

  • According to the KeyboardUtils source code, KeyboardUtils does not support arrow keys at all, on any platform.

    KeyboardUtils is implemented for only 3 keyboard platforms - Windows, Mac, and Linux.

    On Mac, isPressed() is not implemented at all and returns false for all key codes, and an UnsupportedOperationException is thrown when KeyboardUtils is initialized.

    On Windows and Linux, KeyboardUtils supports the following keys:

    • VK_A - VK_Z
    • VK_0 - VK_9
    • VK_SHIFT
    • VK_CONTROL
    • VK_ALT
    • VK_META (Linux only)

    On Windows, KeyboardUtils.isPressed() translates KeyEvent key codes into Win32 virtual key codes (in W32KeyboardUtils.toNative()) and passes them to GetAsyncKeyState() (in W32KeyboardUtils.isPressed()). But arrow keys are not handled and get translated to virtual key code 0, which is not a valid key code.

    Similar with Linux key codes.

    So, to detect arrow keys on Windows, you will have to call GetAsyncKeyState() yourself, as you have already discovered.