Загадочная обработка 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