(Edited for clarity)
I want to detect when a user presses and releases a key in Java Swing, ignoring the keyboard auto repeat feature. I also would like a pure Java
Save the timestamp of the event (arg0.when()
) in keyReleased
. If the next keyPressed
event is for the same key and has the same timestamp, it is an autorepeat.
If you hold down multiple keys, X11 only autorepeats the last key pressed. So, if you hold down 'a' and 'd' you'll see something like:
a down
a up
a down
d down
d up
d down
d up
a up
This approach stores key presses in a HashMap, resetting them when the key is released. Most of the code is courtesy of Elist in this post.
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
public class KeyboardInput2 {
private static HashMap<Integer, Boolean> pressed = new HashMap<Integer, Boolean>();
public static boolean isPressed(int key) {
synchronized (KeyboardInput2.class) {
return pressed.get(key);
}
}
public static void allPressed() {
final Set<Integer> templist = pressed.keySet();
if (templist.size() > 0) {
System.out.println("Key(s) logged: ");
}
for (int key : templist) {
System.out.println(KeyEvent.getKeyText(key));
}
}
public static void main(String[] args) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
@Override
public boolean dispatchKeyEvent(KeyEvent ke) {
synchronized (KeyboardInput2.class) {
switch (ke.getID()) {
case KeyEvent.KEY_PRESSED:
pressed.put(ke.getKeyCode(), true);
break;
case KeyEvent.KEY_RELEASED:
pressed.remove(ke.getKeyCode());
break;
}
return false;
}
}
});
}
}
You can use the HashMap to check if a certain key is pressed, or call KeyboardInput2.allPressed()
to print every pressed key.
Well, you said that it is possible that the time between key events in case of key repeat be non-negative. Even so, it is likely very short. You could then threshold this time to some very small value, and everything equal or lower than it be considered a key repeat.
I've found a solution that does without waiting in case you have something like a game loop going. The idea is storing the release events. Then you can check against them both inside the game loop and inside the key pressed handler. By "(un)register a key" I mean the extracted true press/release events that should be processed by the application. Take care of synchronization when doing the following!