とにかく書く

日々の雑感や知り得たことを、とにかく書いています

キーの入力を検知するには onKeyTyped を使う

画像ビューアーの制御をショートカットキーで実現しようと、Scene のインスタンスに onKeyPressed を使っていた。
順調に進んでいたけど、"+" で拡大処理を実装したところ、"+" だけ何も表示が変わらない。"-" は正しく縮小処理がされるのに…。
原因は、日本語キーボードでは "+" は "Shift + ; " で、onKeyPressed では "Shift" キーでイベント処理、 ";" キーで次のイベント処理になっていた。
KeyEvent (JavaFX 8) によると、onKeyTyped を使う必要がある。

以下のコードで、キーを押したときにそれぞれ何が呼び出されるかを調べることができる。
onKeyTyped を使うときは、getCharacter メソッドで入力された文字を文字列として解釈する必要がある。
逆に、shift や insert キーなど文字列にならないキーは onKeyPressed でしか検知できない。

package application;
	
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;

public class Main extends Application {
	@Override
	public void start(Stage primaryStage) {
		try {
			BorderPane root = new BorderPane();
			Scene scene = new Scene(root,400,400);
			scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
			primaryStage.setScene(scene);
			primaryStage.show();
			// キーイベントを登録する
			scene.setOnKeyPressed(this::keyPressed);
			scene.setOnKeyTyped(this::keyTyped);
			scene.setOnKeyReleased(this::keyReleased);
			
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	private void keyPressed(KeyEvent e) {
		System.out.println("Pressed:" + e.getCode().getName());
	}
	private void keyTyped(KeyEvent e) {
		// KEY_TYPED イベントでは code フィールドと text フィールドは使用されない
		System.out.println("Typed (code): " + e.getCode().getName());
		// KEY_TYPED イベントでは character フィールドが使用される
		System.out.println("Typed (char): " + e.getCharacter());
	}
	private void keyReleased(KeyEvent e) {
		System.out.println("Released: " + e.getCode().getName());
	}
	
	public static void main(String[] args) {
		launch(args);
	}
}

以下は実行結果。

"a" キーを押した時。

Pressed:A
Typed (code): Undefined
Typed (char): a
Released: A

"shift" + "a" つまり "A" を押した時。

Pressed:Shift
Pressed:A
Typed (code): Undefined
Typed (char): A
Released: A
Released: Shift

"shift" + ";" つまり "+" を押した時(日本語キーボードの場合)。

Pressed:Shift
Pressed:Semicolon
Typed (code): Undefined
Typed (char): +
Released: Semicolon
Released: Shift

"Delete" を押した時。onKeyTyped で検知できているけど、文字列はバイナリ値が表示された。(以下の結果は大文字の□で書き直している。)

Pressed:Delete
Typed (code): Undefined
Typed (char): □
Released: Delete

"Insert" を押した時。"shift" などと同様、onKeyTyped はイベントが発生していない。

Pressed:Insert
Released: Insert