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?

mKorbel
  • 109,525
  • 20
  • 134
  • 319
ThomasR
  • 51
  • 2

3 Answers3

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.

    Evgeni Sergeev
    • 22,495
    • 17
    • 107
    • 124
    Aubin
    • 14,617
    • 9
    • 61
    • 84
    • This works for a focused component, but a `KeyListener` doesn't help when your scenario is `WHEN_IN_FOCUSED_WINDOW`... – 0__ Oct 07 '14 at 21:38
    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.

    camickr
    • 321,443
    • 19
    • 166
    • 288
    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.

    Thomas W
    • 13,940
    • 4
    • 58
    • 76