InputMap - register a keystroke that monitors key press, and no virtual repeats

139 Views Asked by At

Apparently this question has been asked before and before and before, but either the answers are not solving the problem or use a language not understandable by me.

I have to register a keyboard action using JComponent.WHEN_IN_FOCUSED_WINDOW, so a KeyListener is not an alternative. I have to track pressing down and releasing the key, say a cursor key. I cannot have multiple press/release firings due to some built-in key repeat. I really want to know when the key is physically pressed and depressed. E.g., start a timer when pressed, stop the timer when released (and do not start and stop the timer dozens of times because of the virtual key repeats).

I believe this worked correctly on OS X, but I am on Linux now (OpenJDK 7).

How?

1

There are 1 best solutions below

2
0__ On BEST ANSWER

As multiple people have noted, this is an oddity (or: bug) on Linux.

The work-around goes as follows. Let's say the press action class is called ActionPress, and the release action class is called ActionRelease.

  • both maintain a long lastWhen that is updated in actionPerformed with e.getWhen. They have a public method getLastWhen that can be called by their counterparts.
  • ActionRelease maintains a javax.swing.Timer with a few milliseconds. It's regular actionPerformed restarts the timer, nothing else.
  • ActionPress in its actionPerformed calls the corresponding ActionRelease's getLastWhen. If the result is identical to its own lastWhen, ignore the action and return, otherwise perform the action.
  • ActionRelease in the additional ActionListener for the Timer performs the actual action. In its getLastWhen implementation, it stops the timer before return lastWhen.