1616import javafx .scene .control .ContextMenu ;
1717import javafx .scene .control .IndexRange ;
1818import javafx .scene .input .ContextMenuEvent ;
19+ import javafx .scene .input .KeyCharacterCombination ;
1920import javafx .scene .input .KeyEvent ;
2021import javafx .scene .input .MouseButton ;
2122import javafx .scene .input .MouseEvent ;
@@ -49,6 +50,22 @@ class GenericStyledAreaBehavior {
4950 ? SelectionPolicy .EXTEND
5051 : SelectionPolicy .ADJUST ;
5152
53+ /*
54+ * KeyCodes are misinterpreted when using a different keyboard layout, for example:
55+ * on Dvorak: C results in KeyCode I, X -> B, and V -> .
56+ * and on German layouts: Z and Y are reportedly switched
57+ * so then editing commands such as Ctrl+C, or CMD+Z are incorrectly processed.
58+ * KeyCharacterCombination however does keyboard translation before matching.
59+ * This resolves issue #799
60+ */
61+ KeyCharacterCombination SHORTCUT_A = new KeyCharacterCombination ( "a" , SHORTCUT_DOWN );
62+ KeyCharacterCombination SHORTCUT_C = new KeyCharacterCombination ( "c" , SHORTCUT_DOWN );
63+ KeyCharacterCombination SHORTCUT_V = new KeyCharacterCombination ( "v" , SHORTCUT_DOWN );
64+ KeyCharacterCombination SHORTCUT_X = new KeyCharacterCombination ( "x" , SHORTCUT_DOWN );
65+ KeyCharacterCombination SHORTCUT_Y = new KeyCharacterCombination ( "y" , SHORTCUT_DOWN );
66+ KeyCharacterCombination SHORTCUT_Z = new KeyCharacterCombination ( "z" , SHORTCUT_DOWN );
67+ KeyCharacterCombination SHORTCUT_SHIFT_Z = new KeyCharacterCombination ( "z" , SHORTCUT_DOWN , SHIFT_DOWN );
68+
5269 InputMapTemplate <GenericStyledAreaBehavior , KeyEvent > editsBase = sequence (
5370 // deletion
5471 consume (keyPressed (DELETE ), GenericStyledAreaBehavior ::deleteForward ),
@@ -57,19 +74,19 @@ class GenericStyledAreaBehavior {
5774 consume (keyPressed (BACK_SPACE , SHORTCUT_DOWN ), GenericStyledAreaBehavior ::deletePrevWord ),
5875 // cut
5976 consume (
60- anyOf (keyPressed (CUT ), keyPressed (X , SHORTCUT_DOWN ), keyPressed (DELETE , SHIFT_DOWN )),
77+ anyOf (keyPressed (CUT ), keyPressed (SHORTCUT_X ), keyPressed (DELETE , SHIFT_DOWN )),
6178 (b , e ) -> b .view .cut ()),
6279 // paste
6380 consume (
64- anyOf (keyPressed (PASTE ), keyPressed (V , SHORTCUT_DOWN ), keyPressed (INSERT , SHIFT_DOWN )),
81+ anyOf (keyPressed (PASTE ), keyPressed (SHORTCUT_V ), keyPressed (INSERT , SHIFT_DOWN )),
6582 (b , e ) -> b .view .paste ()),
6683 // tab & newline
6784 consume (keyPressed (ENTER ), (b , e ) -> b .view .replaceSelection ("\n " )),
6885 consume (keyPressed (TAB ), (b , e ) -> b .view .replaceSelection ("\t " )),
6986 // undo/redo
70- consume (keyPressed (Z , SHORTCUT_DOWN ), (b , e ) -> b .view .undo ()),
87+ consume (keyPressed (SHORTCUT_Z ), (b , e ) -> b .view .undo ()),
7188 consume (
72- anyOf (keyPressed (Y , SHORTCUT_DOWN ), keyPressed (Z , SHORTCUT_DOWN , SHIFT_DOWN )),
89+ anyOf (keyPressed (SHORTCUT_Y ), keyPressed (SHORTCUT_SHIFT_Z )),
7390 (b , e ) -> b .view .redo ())
7491 );
7592 InputMapTemplate <GenericStyledAreaBehavior , KeyEvent > edits = when (b -> b .view .isEditable (), editsBase );
@@ -138,13 +155,13 @@ class GenericStyledAreaBehavior {
138155 keyPressed (LEFT , SHIFT_DOWN , SHORTCUT_DOWN ),
139156 keyPressed (KP_LEFT , SHIFT_DOWN , SHORTCUT_DOWN )
140157 ), (b , e ) -> b .skipToPrevWord (selPolicy )),
141- consume (keyPressed (A , SHORTCUT_DOWN ), (b , e ) -> b .view .selectAll ())
158+ consume (keyPressed (SHORTCUT_A ), (b , e ) -> b .view .selectAll ())
142159 );
143160
144161 InputMapTemplate <GenericStyledAreaBehavior , KeyEvent > copyAction = consume (
145162 anyOf (
146163 keyPressed (COPY ),
147- keyPressed (C , SHORTCUT_DOWN ),
164+ keyPressed (SHORTCUT_C ),
148165 keyPressed (INSERT , SHORTCUT_DOWN )
149166 ), (b , e ) -> b .view .copy ()
150167 );
0 commit comments