javajavafxjnativehook

Read each key press only once with JNativeHook


In my program want to have a text field that will contain the current keys pressed by the user. I can do this with JNativeHook, but the problem currently is that JNativeHook is registering tons of key presses when it is held down. Is there a way to ignore key holds? I would like to simply append to the text field whatever keys are currently held without overpopulating it with duplicates

Here is the relevant part of my code: (This is in my main class that extends Application and implements NativeKeyListener)

@Override
public void nativeKeyPressed(NativeKeyEvent e) {
    System.out.print(NativeKeyEvent.getKeyText(e.getKeyCode()) + " + ");

    if (e.getKeyText(e.getKeyCode()) == "F6")
        System.out.println("F6");


}
@Override
public void nativeKeyReleased(NativeKeyEvent e) {
    try {
        GlobalScreen.unregisterNativeHook();
    } catch (NativeHookException ex) {}
}
@Override
public void nativeKeyTyped(NativeKeyEvent e) {

}

All of this works fine, but if I hold a key, it will spam that key code in the console. Can I stop this?


Solution

  • Just move your code over to nativeKeyTyped. It is only triggered once each time you press and release a key.

    Key pressed will trigger on the initial click then after the timeout between a normal click and a held key, it will give a key pressed update every update.

    If you want more control though you could just add a map. This example uses a hashmap to record if a key is being pressed and how many updates it should wait until it triggers again. I didn't exactly look at the api though, so I wouldn't be surprised if some of the function calls were typed wrong.

    private Map<Integer, Integer> keysHeld = new Hashmap();
    
    
    @Override
    public void nativeKeyPressed(NativeKeyEvent e) {
        //When the countdown gets to 0, do a key update
        if (keysHeld.getOrDefault(e.keyCode(), 0) <= 0) {
            //Do whatever you want to do.
    
            //Set the countdown again, so it can be activated again after a reasonable amount of time.
            keysHeld.put(e.keyCode(), 50);
        }
    
        //Decrease the countdown by 1 each update until it triggers or is released.
        keysHeld.put(e.keyCode(), e.getOrDefault(e.keyCode(), 50) - 1);
    }
    
     @Override
     public void nativeKeyReleased(NativeKeyEvent e) {
         //Reset countdown when key is released.
         keysHeld.put(e.keyCode(), 0);
    }