Загадочная обработка KeyEvent для строчных букв

Если я настрою KeyEvent обработчик, как показано ниже, ведет себя так, как я ожидал, и, как представляется, в документации Oracle, прописные буквы и символы Ascii не являются буквами или цифрами.

Однако для строчных букв, если при вводе буквы удерживать клавишу Ctrl, EventHandler кажется, не удается зарегистрировать нажатие клавиш вообще.

Это показано в выводе ниже, начиная с ввода Q, q, $, Ctrl+Q, Ctrl+q, Ctrl+$ в последовательности.

Кто-нибудь может пролить свет на это поведение? Я что-то пропустил? Я искал, но не нашел никаких других ссылок на этот вопрос.

import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.event.*;
import javafx.scene.input.KeyEvent;

// Test handling keypresses of upper and lower case letter, and non-alphameric ascii symbol,
// to see if any difference exists when Ctrl is held down
// between the handling for (ev.isShortcutDown()) and (ev.isMetaDown() || ev.isControlDown())
// and between the three character types

// Program to be tested by typing, in sequence,
//              Q  q  $  Ctrl+Q  Ctrl+q  Ctrl+$


public class TestHandlingKeyEvents extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    public void start(Stage stage) throws Exception {
        Scene scene = new Scene(new Group());
        stage.setScene(scene);

        EventHandler<KeyEvent> handleUserTyping = ev -> {

            String charTyped = ev.getCharacter();
            switch (charTyped) {
                case "Q":               // quit
                    System.out.println("\nQ typed ");
                    if (ev.isShortcutDown()) 
                        System.out.println("with Shortcut down ");
                    if (ev.isMetaDown() || ev.isControlDown())
                        System.out.println("with Meta or Ctrl down ");
                    break;                  
                case "q":               // complete reset
                    System.out.println("\nq typed ");
                    if (ev.isShortcutDown()) 
                        System.out.println("with Shortcut down ");
                    if (ev.isMetaDown() || ev.isControlDown())
                        System.out.println("with Meta or Ctrl down ");              
                    break;
                case "$":               // back to last view
                    System.out.println("\n$ typed ");
                    if (ev.isShortcutDown()) 
                        System.out.println("with Shortcut down ");
                    if (ev.isMetaDown() || ev.isControlDown())
                        System.out.println("with Meta or Ctrl down ");              
                    break;
            }
        };

        scene.setOnKeyTyped(handleUserTyping);
        stage.show();
    }
}

И вывод:

john@jlaptop2:/java$ java TestHandlingKeyEvents

Q typed 

q typed 

$ typed 

Q typed 
with Shortcut down 
with Meta or Ctrl down 

$ typed 
with Shortcut down 
with Meta or Ctrl down 
john@jlaptop2:/java$ 

1 ответ

Решение

Вы используете неправильный тип события, чтобы получить желаемое поведение.

Читайте о различных типах KeyEvents в javadoc KeyEvent.

В основном вы можете зарегистрировать обработчики событий для событий KEY_PRESSED, а не для событий KEY_TYPED. События, вводимые с клавиатуры, генерируются только тогда, когда базовая система регистрирует символ Unicode, сгенерированный посредством набора, что не относится к некоторым последовательностям ввода клавиш, которые вы пытаетесь захватить. Чтобы захватить больше последовательностей входных символов, которые не обязательно связаны с генерацией символов Юникода, следует использовать события KEY_PRESSED (или KEY_RELEASED) более низкого уровня.

Тем не менее, существует интерфейс более высокого уровня, чем тот, который вы можете использовать, и он может быть более подходящим для вашего варианта использования, который заключается в установке ускорителей на основе KeyCodeCombination.

Образец с использованием ускорителей

import javafx.application.Application;
import javafx.collections.ObservableMap;
import javafx.scene.*;
import javafx.scene.input.KeyCombination;
import javafx.stage.Stage;

// Test handling keypresses of upper and lower case letter, 
// and non-alphameric ascii symbol.    
// Program to be tested by typing, in sequence,
//              Ctrl+Q  Ctrl+q  Ctrl+$    
public class TestHandlingKeyAccelerators extends Application {    
    public void start(Stage stage) throws Exception {
        Scene scene = new Scene(new Group());
        stage.setScene(scene);

        ObservableMap<KeyCombination, Runnable> accelerators = 
                scene.getAccelerators();

        accelerators.put(
                KeyCombination.valueOf("Ctrl+Q"), 
                () -> System.out.println("Ctrl+q -> reset")
        );
        accelerators.put(
                KeyCombination.valueOf("Ctrl+Shift+Q"), 
                () -> System.out.println("Ctrl+Q -> quit")
        );
        accelerators.put(
                KeyCombination.valueOf("Ctrl+Shift+'4'"), 
                () -> System.out.println("Ctrl+$ -> back to last view")
        );

        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Обратите внимание, как метод KeyCombination.valueO f используется для создания комбинаций клавиш. Также обратите внимание, что (кроме "4", который идентифицирует символ) каждый ключ идентифицируется его кодом ключа. Так как на моей клавиатуре строчные q и прописные Q - это одна и та же клавиша, но для генерации клавиши верхнего регистра используется сдвиг, тогда Ctrl+q кодируется как Ctrl+Q, а Ctrl + Q кодируется как Ctrl+Shift+Q. Кроме того, на моей клавиатуре нет клавиши доллара, вместо этого доллар генерируется нажатием клавиши Shift и клавиши "четыре". Обычно четырехзначным кодом является DIGIT4, но по какой-то причине в этом случае это не работает. Таким образом, чтобы получить операцию Ctrl+$, я использую Ctrl+Shift+'4', чтобы обозначить модификаторы управления и сдвига, когда нажата клавиша, генерирующая символ '4'.

Прокомментируйте работу вашего оригинального образца

Кроме того, в качестве дополнительного примечания, которое по большей части является пустяком, при тестировании на Mac (MacBook Air OS X 10.11.4 2012 года, Java 8u60) ваша программа выдает другой вывод, вероятно, из-за другой системы клавиатуры или обработки клавишных событий в ОС. Вывод на Mac для предложенной вами последовательности клавиш:

Q typed 

q typed 

$ typed 

Следующая последовательность вывода, которую вы показываете в своем вопросе, не производится на Mac:

Q typed 
with Shortcut down 
with Meta or Ctrl down 

$ typed 
with Shortcut down 
with Meta or Ctrl down 
Другие вопросы по тегам