JavaFX 如何区分 keyPressed X 和 Keys X + Y 的组合

JavaFX How can I distinguish between a keyPressed X and a combination of Keys X + Y

我希望我的应用程序 (JavaFx 14) 在按下键 "a" 时执行某些操作,并且我还希望应用程序在具有相同键 "a" 和 "b" 被按下。目标是只调用一种方法。按 a 的方法或按 a + b 的方法。我试着用一个带有键码的可观察列表来做,但是所有的方法都被调用了。

    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();
                }           

            } 
        }
    });
}

当用户"presses two keys"时,两个按键不可能同时发生,因此其中一个按键必然会先于另一个被检测到。可能这里最好的方法是确保其中一个键(比如 B)没有它自己的功能。这样用户将学会始终先按下 B,然后按下 A,同时按住 B(这是我们键入的方式,使用修饰键,例如 SHIFTCTRL).

如果您确实希望两个键都有自己的功能,但同时按下两个键时功能不同"at the same time",那么您唯一的选择是实现延迟处理单个键的按下,等待查看在延迟到期之前是否按下了另一个键。当然,这是以响应速度为代价的。

这是一个实现,使用短(25 毫秒)PauseTransition 作为延迟。 (我也改为使用 ObservableSet,它清理了一些逻辑。)

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");
    }
}