Search code examples
windowsjavafxuser-input

Multiple Key press event abuse in Windows


I'm trying to replicate the behavior of action game multiple key press using JavaFx onKeyPressed event and I've noticed some more general problem that seems to occur in every windows based keyboard input handler, i.e: the wanted behavior:

user press and holds "W" - W key is detected/printed user press and holds some other key "R" while still holding "W" - "W" detected, then "R" detected. when "R" released "W" should still be detected until he's released.

what really happens: open any editor and press those keys first hold W then R, it prints something like:

WWWWWWWWWWRRRRRRRRRRRR

while wanted behavior is :

WRWRWRWRWRWRWRWRWRWRWR

furthermore when R is released - W won't get printed at all! now i'm using JavaFx key event detection and I'm guessing its based on windows key event detection, I know i could do some workaround for this to detect all keys (using stack and pop key on release) but I'm wondering is it a matter of configuration or i'm missing something? you can see that in most computer games the issue is taken care of, i.e when you press run and type some irreverent key you keep running in the game.


Solution

  • There is only a guarantee that a key press causes a event once, not that it repeatedly triggers events as long as the key is down. Therefore you should take care of saving the pressed keys yourself and updates according to the states should be triggered from a AnimationTimer or some other code that repeatedly is executed on the applicaton thread after a appropriate delay.

    Example:

    final Set<KeyCode> activeKeys = EnumSet.noneOf(KeyCode.class);
    final AnimationTimer updater = new AnimationTimer() {
    
        @Override
        public void handle(long now) {
            // print all pressed keys
            for (KeyCode code : activeKeys) {
                System.out.println(code);
            }
        }
    };
    
    scene.setOnKeyPressed(evt -> {
        boolean wasEmpty = activeKeys.isEmpty();
        if (activeKeys.add(evt.getCode()) && wasEmpty) {
            updater.start();
        }
    });
    
    scene.setOnKeyReleased(evt -> {
        if (activeKeys.remove(evt.getCode()) && activeKeys.isEmpty()) {
            updater.stop();
        }
    });