Reputation: 33
I want my application (JavaFx 14) to so something when the key "a" is pressed and I also want the application to do something when a key combination with the same key "a" and "b" is pressed. The goal is to only call one method. the method for pressing a or the method for pressing a +b. I tried doing it with a observable List with keycodes but all methods are called.
private ObservableList<KeyCode> keys = FXCollections.observableArrayList();
private void keyboardShortcuts(Button[] buttons){
// collect pressed key
scene.addEventFilter(KeyEvent.KEY_PRESSED, (e) -> {
if (!keys.contains(e.getCode())) {
keys.add(e.getCode());
}
e.consume();
});
// remove pressed key when it is released
scene.setOnKeyReleased((e) -> {
keys.remove(e.getCode());
e.consume();
});
keys.addListener(new InvalidationListener() {
@Override
public void invalidated(Observable observable) {
if(keys.size() == 1) {
if(keys.contains(KeyCode.A)) {
foo();
}
if(keys.contains(KeyCode.B)) {
foo2();
}
}
if(keys.size() == 2) {
if(keys.contains(KeyCode.A) && keys.contains(KeyCode.B)) {
foo3();
}
}
}
});
}
Upvotes: 2
Views: 251
Reputation: 209553
When the user "presses two keys", it's impossible for both key presses to happen simultaneously, so one of the key presses will necessarily be detected before the other. Probably the best approach here is to ensure one of the keys (say B) doesn't have it's own functionality. That way the user will learn to always press B first, then A while B is held down (this is the way we type, using modifier keys such as SHIFT and CTRL).
If you really want both keys to have their own functionality, but different functionality when both are pressed "at the same time", then your only option is to implement a delay in handling the press of a single key, waiting to see if the other key is pressed before that delay expires. This, of course, comes at the expense of responsiveness.
Here's an implementation of that, using a short (25ms) PauseTransition
for the delay. (I also changed to use an ObservableSet
, which cleans up some of the logic.)
private ObservableSet<KeyCode> keys = FXCollections.observableSet();
private PauseTransition keyDelay = new PauseTransition(Duration.millis(25));
private void keyboardShortcuts(Scene scene){
// collect pressed key
scene.addEventFilter(KeyEvent.KEY_PRESSED, (e) -> {
keys.add(e.getCode());
e.consume();
});
// remove pressed key when it is released
scene.setOnKeyReleased((e) -> {
keys.remove(e.getCode());
e.consume();
});
keys.addListener((Change<? extends KeyCode> c) -> {
if (keys.size() <= 1) {
keyDelay.playFromStart();
} else {
keyDelay.stop();
checkKeys();
}
});
keyDelay.setOnFinished(e -> checkKeys());
}
private void checkKeys() {
if(keys.contains(KeyCode.A) && keys.contains(KeyCode.B)) {
System.out.println("A and B");
} else if(keys.contains(KeyCode.A)) {
System.out.println("A only");
} else if(keys.contains(KeyCode.B)) {
System.out.println("B only");
}
}
Upvotes: 2