Java Swing: Key pressed key stroke on an `InputMap` triggers its action several times while holding down the key
Asked Answered
S

3

5

I register

getInputMap().put(KeyStroke.getKeyStroke("pressed RIGHT"), "go right");

When testing the code I get: While I hold the right arrow key down, the action is triggered repeatedly and not only once as I would have expected this.

Interestingly

getInputMap().put(KeyStroke.getKeyStroke("released RIGHT"), "stop");

triggers stop only when the key is finally released.

Is there a way to register a key stroke on an input map, so that the associated action is only triggered once at the moment when the key is pressed?

Swiss answered 1/11, 2013 at 8:27 Comment(0)
S
6

Documentation of KeyStroke:

A KeyStroke represents a key action on the keyboard, or equivalent input device. KeyStrokes can correspond to only a press or release of a particular key, just as KEY_PRESSED and KEY_RELEASED KeyEvents do; alternately, they can correspond to typing a specific Java character, just as KEY_TYPED KeyEvents do. In all cases, KeyStrokes can specify modifiers (alt, shift, control, meta, altGraph, or a combination thereof) which must be present during the action for an exact match.

To trigger the event only once, at release time, I suggest to register

getInputMap().put(KeyStroke.getKeyStroke("typed RIGHT"), "go right");

The documentation of KeyStroke.getKeyStroke(String) is:

Parses a string and returns a KeyStroke. The string must have the following syntax:

  • modifiers* (typedID | pressedReleasedID)

  • modifiers := shift | control | ctrl | meta | alt | altGraph
  • typedID := typed <typedKey>
  • typedKey := string of length 1 giving Unicode character.
  • pressedReleasedID := (pressed | released) key
  • key := KeyEvent key code name, i.e. the name following "VK_".
  • To trigger the event only once, at press time, I suggest to register the press and release events to manage yourself a latch with a boolean.

    Sorce answered 1/11, 2013 at 8:31 Comment(1)
    This works for a focused component, but a KeyListener doesn't help when your scenario is WHEN_IN_FOCUSED_WINDOW...Gripe
    S
    3

    Is there a way to register a key stroke on an input map, so that the associated action is only triggered once at the moment when the key is pressed?

    Remove the keyPressed binding from the InputMap. Then for the keyReleased Action you add the keyPressed binding back to the InputMap.

    However, even this can cause problems because on a Windows OS the sequence of KeyEvents is:

    pressed, pressed, pressed.... released.
    

    This makes sense to me as generally when you hold the key down you want the character to repeat. However, on a Mac I believe the sequence is:

    pressed, released, pressed, released, pressed, released
    

    which doesn't make sense to me and makes it difficult to determine when a key has truly been released.

    Selfanalysis answered 1/11, 2013 at 14:56 Comment(0)
    A
    1

    The "key typed" event operates per platform behaviour -- which, as standard since before the 1980's, has always included auto-repeat. This would be driven by the low-level events from the OS.

    You could try not holding down the keys? You shouldn't be mashing the keyboard, it's a precision instrument.

    You can possibly change the key-stroke binding (to avoid receiving auto-repeat) or otherwise use a custom event-listener & handle only the low-level keydown/ keyup event once. Low-level events may however expose keycodes (as they are below the level of actually typing any one character) rather than characters.

    Aprilette answered 1/11, 2013 at 8:33 Comment(0)

    © 2022 - 2024 — McMap. All rights reserved.