mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
IDEA-165950 [TEST] Added new regression test (National keyboard layouts support)
(cherry picked from commit 0900a705bc)
with fix for JBR-5300 Change source code and test files to use GPL license
This commit is contained in:
173
test/jdk/jb/sun/awt/macos/NationalLayoutTest/Key.java
Normal file
173
test/jdk/jb/sun/awt/macos/NationalLayoutTest/Key.java
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2000-2023 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.HashMap;
|
||||
|
||||
/*
|
||||
* Class containing common key functionality
|
||||
*/
|
||||
public class Key {
|
||||
|
||||
// KeyEvent.VK_ constant name corresponding to the key on US keyboard layout
|
||||
private final String vkName;
|
||||
// KeyChars mapped to the key on the current keyboard layout
|
||||
private final MappedKeyChars mappedKeyChars;
|
||||
|
||||
Key(String vkName, MappedKeyChars mappedKeyChars) {
|
||||
this.vkName = vkName;
|
||||
this.mappedKeyChars = mappedKeyChars;
|
||||
}
|
||||
|
||||
// Returns the virtual key code for US keyboard layout.
|
||||
// Robot only knows US keyboard layout.
|
||||
// So to press some key on the current layout, one needs to pass corresponding US layout key code to Robot.
|
||||
// So every key stores corresponding KeyEvent.VK_ constant name to provide mapping to US layout.
|
||||
int getKeyCode_US() {
|
||||
try {
|
||||
return KeyEvent.class.getField(vkName).getInt(null);
|
||||
} catch (IllegalAccessException | NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
|
||||
// Returns key code for the current layout.
|
||||
// Key that generates VK_ code when using a US keyboard layout also generates a unique code for other layout.
|
||||
// Test firstly determines char mapped to the key on the current layout
|
||||
// and then uses KeyEvent.getExtendedKeyCodeForChar(c) to get the key code.
|
||||
int getKeyCode() {
|
||||
KeyChar keyChar = mappedKeyChars.getKeyChar();
|
||||
char ch = keyChar.getChar();
|
||||
if (latinKeyCodesMap.containsKey(ch)) {
|
||||
// TODO Fix this in jbruntime
|
||||
// KeyEvent.getExtendedKeyCodeForChar(ch) does not return corresponding VK_ constant for non-English keys
|
||||
return latinKeyCodesMap.get(ch);
|
||||
} else if (keyChar.isDead() && deadKeyCodesMap.containsKey(ch)) {
|
||||
// KeyEvent.getExtendedKeyCodeForChar(ch) does not return corresponding VK_ constant for dead keys
|
||||
return deadKeyCodesMap.get(ch);
|
||||
} else {
|
||||
return KeyEvent.getExtendedKeyCodeForChar(ch);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns key char for the current layout
|
||||
public char getChar(Modifier modifier) {
|
||||
return mappedKeyChars.getKeyChar(modifier).getChar();
|
||||
}
|
||||
|
||||
// Checks if no char is mapped to the modifier + key
|
||||
public boolean isCharNull(Modifier modifier) {
|
||||
return (mappedKeyChars.getKeyChar(modifier).getChar() == Character.MIN_VALUE);
|
||||
}
|
||||
|
||||
// Checks if modifier + key is a shortcut
|
||||
public boolean isCharUndefined(Modifier modifier) {
|
||||
return (mappedKeyChars.getKeyChar(modifier).getChar() == Character.MAX_VALUE);
|
||||
}
|
||||
|
||||
// Checks if key is a dead key, no modifiers
|
||||
public boolean isDead() {
|
||||
return mappedKeyChars.getKeyChar().isDead();
|
||||
}
|
||||
|
||||
// Checks if modifier + key is a dead key, always false for shortcut
|
||||
public boolean isDead(Modifier modifier) {
|
||||
return mappedKeyChars.getKeyChar(modifier).isDead();
|
||||
}
|
||||
|
||||
// TODO Remove this map when KeyEvent.getExtendedKeyCodeForChar(ch) is fixed for latin keys in jbruntime
|
||||
// Map storing latin chars and corresponding VK_ codes
|
||||
private static final HashMap<Character, Integer> latinKeyCodesMap = new HashMap<Character, Integer>() {
|
||||
{
|
||||
// Please see:
|
||||
// jbruntime/src/java.desktop/share/classes/java/awt/event/KeyEvent.java
|
||||
|
||||
put((char) 0x00E0, KeyEvent.VK_A_WITH_GRAVE);
|
||||
put((char) 0x00E1, KeyEvent.VK_A_WITH_ACUTE);
|
||||
put((char) 0x00E2, KeyEvent.VK_A_WITH_CIRCUMFLEX);
|
||||
put((char) 0x00E3, KeyEvent.VK_A_WITH_TILDE);
|
||||
put((char) 0x00E4, KeyEvent.VK_A_WITH_DIAERESIS);
|
||||
put((char) 0x00E5, KeyEvent.VK_A_WITH_RING_ABOVE);
|
||||
put((char) 0x00E6, KeyEvent.VK_AE);
|
||||
put((char) 0x00E7, KeyEvent.VK_C_WITH_CEDILLA);
|
||||
put((char) 0x00E8, KeyEvent.VK_E_WITH_GRAVE);
|
||||
put((char) 0x00E9, KeyEvent.VK_E_WITH_ACUTE);
|
||||
put((char) 0x00EA, KeyEvent.VK_E_WITH_CIRCUMFLEX);
|
||||
put((char) 0x00EB, KeyEvent.VK_E_WITH_DIAERESIS);
|
||||
put((char) 0x00EC, KeyEvent.VK_I_WITH_GRAVE);
|
||||
put((char) 0x00ED, KeyEvent.VK_I_WITH_GRAVE);
|
||||
put((char) 0x00EE, KeyEvent.VK_I_WITH_CIRCUMFLEX);
|
||||
put((char) 0x00EF, KeyEvent.VK_I_WITH_DIAERESIS);
|
||||
put((char) 0x00F0, KeyEvent.VK_ETH);
|
||||
put((char) 0x00F1, KeyEvent.VK_N_WITH_TILDE);
|
||||
put((char) 0x00F2, KeyEvent.VK_O_WITH_GRAVE);
|
||||
put((char) 0x00F3, KeyEvent.VK_O_WITH_ACUTE);
|
||||
put((char) 0x00F4, KeyEvent.VK_O_WITH_CIRCUMFLEX);
|
||||
put((char) 0x00F5, KeyEvent.VK_O_WITH_TILDE);
|
||||
put((char) 0x00F6, KeyEvent.VK_O_WITH_DIAERESIS);
|
||||
put((char) 0x00F7, KeyEvent.VK_DIVISION_SIGN);
|
||||
put((char) 0x00F8, KeyEvent.VK_O_WITH_SLASH);
|
||||
put((char) 0x00F9, KeyEvent.VK_U_WITH_GRAVE);
|
||||
put((char) 0x00FA, KeyEvent.VK_U_WITH_ACUTE);
|
||||
put((char) 0x00FB, KeyEvent.VK_U_WITH_CIRCUMFLEX);
|
||||
put((char) 0x00FC, KeyEvent.VK_U_WITH_DIAERESIS);
|
||||
put((char) 0x00FD, KeyEvent.VK_Y_WITH_ACUTE);
|
||||
put((char) 0x00FE, KeyEvent.VK_THORN);
|
||||
put((char) 0x00FF, KeyEvent.VK_Y_WITH_DIAERESIS);
|
||||
}
|
||||
};
|
||||
|
||||
// Map storing possible dead key chars and corresponding VK_ codes
|
||||
private static final HashMap<Character, Integer> deadKeyCodesMap = new HashMap<Character, Integer>() {
|
||||
{
|
||||
// Please see:
|
||||
// jbruntime/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp
|
||||
// jbruntime/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTEvent.m
|
||||
|
||||
put((char) 0x02D9, KeyEvent.VK_DEAD_ABOVEDOT);
|
||||
put((char) 0x02DA, KeyEvent.VK_DEAD_ABOVERING);
|
||||
put((char) 0x00B4, KeyEvent.VK_DEAD_ACUTE); // ACUTE ACCENT
|
||||
put((char) 0x0384, KeyEvent.VK_DEAD_ACUTE); // GREEK TONOS
|
||||
// TODO Should test map ' to acute as sometimes it may add either acute or cedilla to the next key
|
||||
//put((char) 0x0027 /* ' */, KeyEvent.VK_DEAD_ACUTE); // APOSTROPHE
|
||||
put((char) 0x02D8, KeyEvent.VK_DEAD_BREVE);
|
||||
put((char) 0x02C7, KeyEvent.VK_DEAD_CARON);
|
||||
put((char) 0x00B8, KeyEvent.VK_DEAD_CEDILLA); // CEDILLA
|
||||
put((char) 0x002C /* , */, KeyEvent.VK_DEAD_CEDILLA); // COMMA
|
||||
put((char) 0x02C6, KeyEvent.VK_DEAD_CIRCUMFLEX); // MODIFIER LETTER CIRCUMFLEX ACCENT
|
||||
put((char) 0x005E, KeyEvent.VK_DEAD_CIRCUMFLEX); // CIRCUMFLEX ACCENT
|
||||
put((char) 0x00A8, KeyEvent.VK_DEAD_DIAERESIS); // DIAERESIS
|
||||
put((char) 0x0022 /* " */, KeyEvent.VK_DEAD_DIAERESIS); // QUOTATION MARK
|
||||
put((char) 0x02DD, KeyEvent.VK_DEAD_DOUBLEACUTE);
|
||||
put((char) 0x0060, KeyEvent.VK_DEAD_GRAVE);
|
||||
put((char) 0x037A, KeyEvent.VK_DEAD_IOTA);
|
||||
put((char) 0x02C9, KeyEvent.VK_DEAD_MACRON); // MODIFIER LETTER MACRON
|
||||
put((char) 0x00AF, KeyEvent.VK_DEAD_MACRON); // MACRON
|
||||
put((char) 0x02DB, KeyEvent.VK_DEAD_OGONEK);
|
||||
put((char) 0x02DC, KeyEvent.VK_DEAD_TILDE); // SMALL TILDE
|
||||
put((char) 0x007E, KeyEvent.VK_DEAD_TILDE); // TILDE
|
||||
put((char) 0x309B, KeyEvent.VK_DEAD_VOICED_SOUND);
|
||||
put((char) 0x309C, KeyEvent.VK_DEAD_SEMIVOICED_SOUND);
|
||||
}
|
||||
};
|
||||
}
|
||||
65
test/jdk/jb/sun/awt/macos/NationalLayoutTest/KeyChar.java
Normal file
65
test/jdk/jb/sun/awt/macos/NationalLayoutTest/KeyChar.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2000-2023 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Class describing a key char
|
||||
*/
|
||||
public class KeyChar {
|
||||
|
||||
// Char value
|
||||
private final char ch;
|
||||
// Dead or not
|
||||
private final boolean isDead;
|
||||
|
||||
// Private constructor for an ordinal key char
|
||||
private KeyChar(char ch) {
|
||||
this.ch = ch;
|
||||
this.isDead = false;
|
||||
}
|
||||
|
||||
// Private constructor for a dead key char
|
||||
private KeyChar(char ch, boolean isDead) {
|
||||
this.ch = ch;
|
||||
this.isDead = isDead;
|
||||
}
|
||||
|
||||
// Helper method for an ordinal key char creation
|
||||
static KeyChar ch(char ch) {
|
||||
return new KeyChar(ch);
|
||||
}
|
||||
|
||||
// Helper method for a dead key char creation
|
||||
static KeyChar dead(char ch) {
|
||||
return new KeyChar(ch, true);
|
||||
}
|
||||
|
||||
// Returns dead marker
|
||||
boolean isDead() {
|
||||
return isDead;
|
||||
}
|
||||
|
||||
// Returns char value
|
||||
char getChar() {
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
56
test/jdk/jb/sun/awt/macos/NationalLayoutTest/Layout.java
Normal file
56
test/jdk/jb/sun/awt/macos/NationalLayoutTest/Layout.java
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2000-2023 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Enumerates macOS keyboard layouts covered by this test
|
||||
*/
|
||||
public enum Layout {
|
||||
|
||||
ABC ("ABC", Layout_ABC.values()),
|
||||
US_INTERNATIONAL_PC ("USInternational-PC", Layout_US_INTERNATIONAL_PC.values()),
|
||||
SPANISH_ISO ("Spanish-ISO", Layout_SPANISH_ISO.values()),
|
||||
FRENCH_PC ("French-PC", Layout_FRENCH_PC.values()),
|
||||
GERMAN ("German", Layout_GERMAN.values()),
|
||||
|
||||
;
|
||||
|
||||
// Real macOS keyboard layout name without "com.apple.keylayout." prefix
|
||||
private String name;
|
||||
// Array of test keys for the layout
|
||||
private LayoutKey[] layoutKeys;
|
||||
|
||||
Layout(String name, LayoutKey[] layoutKeys) {
|
||||
this.name = name;
|
||||
this.layoutKeys = layoutKeys;
|
||||
}
|
||||
|
||||
// Return array of test keys for the layout
|
||||
LayoutKey[] getLayoutKeys() {
|
||||
return layoutKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "com.apple.keylayout." + name;
|
||||
}
|
||||
}
|
||||
33
test/jdk/jb/sun/awt/macos/NationalLayoutTest/LayoutKey.java
Normal file
33
test/jdk/jb/sun/awt/macos/NationalLayoutTest/LayoutKey.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2000-2023 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Common interface for all test layouts.
|
||||
* Keyboard layouts are declared as a separate enums to allow testing of different key sets for different layouts.
|
||||
* As layouts are declared as enums, they cannot extend any other class, but need to have some common functionality.
|
||||
*/
|
||||
public interface LayoutKey {
|
||||
|
||||
// Return Key object containing common key functionality
|
||||
Key getKey();
|
||||
}
|
||||
120
test/jdk/jb/sun/awt/macos/NationalLayoutTest/Layout_ABC.java
Normal file
120
test/jdk/jb/sun/awt/macos/NationalLayoutTest/Layout_ABC.java
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2000-2023 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Regression test for IDEA-165950: National keyboard layouts support
|
||||
* @requires (jdk.version.major >= 8 & os.family == "mac")
|
||||
* @modules java.desktop/sun.lwawt.macosx
|
||||
* @run main NationalLayoutTest ABC
|
||||
*/
|
||||
|
||||
/*
|
||||
* Enumerates keys under test for com.apple.keylayout.ABC (macOS 10.14.5)
|
||||
*/
|
||||
public enum Layout_ABC implements LayoutKey {
|
||||
|
||||
// Enum name must be the same as KeyEvent.VK_ constant name corresponding to the key on US keyboard layout
|
||||
// Note that '\u0000' may be used if no char is mapped to a key + modifier or if one wants to skip its testing
|
||||
|
||||
// Robot cannot press section sign key (16777383),
|
||||
// located on the left side of the key 1 on the Apple International English keyboard
|
||||
// SECTION ('§', '§', '±', '±'),
|
||||
|
||||
VK_MINUS ('-', '–', '_', '—'),
|
||||
VK_EQUALS ('=', '≠', '+', '±'),
|
||||
|
||||
VK_OPEN_BRACKET ('[', '“', '{', '”'),
|
||||
VK_CLOSE_BRACKET (']', '‘', '}', '’'),
|
||||
|
||||
VK_SEMICOLON (';', '…', ':', 'Ú'),
|
||||
VK_QUOTE ('\'', 'æ', '"', 'Æ'),
|
||||
VK_BACK_SLASH ('\\', '«', '|', '»'),
|
||||
|
||||
VK_BACK_QUOTE (KeyChar.ch('`'), KeyChar.dead('`'), KeyChar.ch('~'), KeyChar.ch('`')),
|
||||
VK_COMMA (',', '≤', '<', '¯'),
|
||||
VK_PERIOD ('.', '≥', '>', '˘'),
|
||||
VK_SLASH ('/', '÷', '?', '¿'),
|
||||
|
||||
//VK_1 ('1', '¡', '!', '⁄'),
|
||||
//VK_2 ('2', '™', '@', '€'),
|
||||
//VK_3 ('3', '£', '#', '‹'),
|
||||
//VK_4 ('4', '¢', '$', '›'),
|
||||
//VK_5 ('5', '∞', '%', 'fi'),
|
||||
//VK_6 ('6', '§', '^', 'fl'),
|
||||
//VK_7 ('7', '¶', '&', '‡'),
|
||||
//VK_8 ('8', '•', '*', '°'),
|
||||
//VK_9 ('9', 'ª', '(', '·'),
|
||||
//VK_0 ('0', 'º', ')', '‚'),
|
||||
|
||||
// macOS system shortcuts: Shift+Cmd+Q - Log Out, Ctrl+Cmd+Q - Lock Screen
|
||||
//VK_Q ('q', 'œ', 'Q', 'Œ'),
|
||||
//VK_W ('w', '∑', 'W', '„'),
|
||||
//VK_E (KeyChar.ch('e'), KeyChar.dead('´') ,KeyChar.ch('E'), KeyChar.ch('´')),
|
||||
//VK_R ('r', '®', 'R', '‰'),
|
||||
//VK_T ('t', '†', 'T', 'ˇ'),
|
||||
//VK_Y ('y', '¥', 'Y', 'Á'),
|
||||
//VK_U (KeyChar.ch('u'), KeyChar.dead('¨'), KeyChar.ch('U'), KeyChar.ch('¨')),
|
||||
//VK_I (KeyChar.ch('i'), KeyChar.dead('ˆ'), KeyChar.ch('I'), KeyChar.ch('ˆ')),
|
||||
//VK_O ('o', 'ø', 'O', 'Ø'),
|
||||
//VK_P ('p', 'π', 'P', '∏'),
|
||||
|
||||
//VK_A ('a', 'å', 'A', 'Å'),
|
||||
//VK_S ('s', 'ß', 'S', 'Í'),
|
||||
//VK_D ('d', '∂', 'D', 'Î'),
|
||||
//VK_F ('f', 'ƒ', 'F', 'Ï'),
|
||||
//VK_G ('g', '©', 'G', '˝'),
|
||||
// macOS system shortcuts: Cmd+H - Hide the windows of the front app
|
||||
//VK_H ('h', '˙', 'H', 'Ó'),
|
||||
//VK_J ('j', '∆', 'J', 'Ô'),
|
||||
//VK_K ('k', '˚', 'K', ''),
|
||||
//VK_L ('l', '¬', 'L', 'Ò'),
|
||||
|
||||
//VK_Z ('z', 'Ω', 'Z', '¸'),
|
||||
//VK_X ('x', '≈', 'X', '˛'),
|
||||
//VK_C ('c', 'ç', 'C', 'Ç'),
|
||||
// macOS system shortcuts: Cmd+V - Paste the contents of the Clipboard into the current document or app
|
||||
//VK_V ('v', '√', 'V', '◊'),
|
||||
//VK_B ('b', '∫', 'B', 'ı'),
|
||||
//VK_N (KeyChar.ch('n'), KeyChar.dead('˜'), KeyChar.ch('N'), KeyChar.ch('˜')),
|
||||
//VK_M ('m', 'µ', 'M', 'Â'),
|
||||
|
||||
;
|
||||
|
||||
// Common code for any LayoutKey enum
|
||||
|
||||
private final Key key;
|
||||
|
||||
Layout_ABC(char no, char alt, char shift, char alt_shift) {
|
||||
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
|
||||
}
|
||||
|
||||
Layout_ABC(KeyChar no, KeyChar alt, KeyChar shift, KeyChar alt_shift) {
|
||||
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
|
||||
}
|
||||
|
||||
public Key getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2000-2023 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Regression test for IDEA-165950: National keyboard layouts support
|
||||
* @requires (jdk.version.major >= 8 & os.family == "mac")
|
||||
* @modules java.desktop/sun.lwawt.macosx
|
||||
* @run main NationalLayoutTest FRENCH_PC
|
||||
*/
|
||||
|
||||
/*
|
||||
* Enumerates keys under test for com.apple.keylayout.French-PC (macOS 10.14.5)
|
||||
*/
|
||||
public enum Layout_FRENCH_PC implements LayoutKey {
|
||||
|
||||
// Enum name must be the same as KeyEvent.VK_ constant name corresponding to the key on US keyboard layout
|
||||
// Note that '\u0000' may be used if no char is mapped to a key + modifier or if one wants to skip its testing
|
||||
|
||||
VK_MINUS (')', ']', '°', ']'),
|
||||
VK_EQUALS ('=', '}', '+', '≠'),
|
||||
|
||||
VK_OPEN_BRACKET (KeyChar.dead('^'), KeyChar.ch('ô'), KeyChar.dead('¨'), KeyChar.ch('Ô')),
|
||||
VK_CLOSE_BRACKET ('$', '¤', '£', '¥'),
|
||||
|
||||
VK_SEMICOLON ('m', 'µ', 'M', 'Ó'),
|
||||
VK_QUOTE ('ù', 'Ù', '%', '‰'),
|
||||
VK_BACK_SLASH ('*', '@', 'μ', '#'),
|
||||
|
||||
VK_BACK_QUOTE ('<', '«', '>', '≥'),
|
||||
VK_COMMA (';', '…', '.', '•'),
|
||||
VK_PERIOD (':', '÷', '/', '\\'),
|
||||
VK_SLASH ('!', '¡', '§', '±'),
|
||||
|
||||
;
|
||||
|
||||
// Common code for any LayoutKey enum
|
||||
|
||||
private final Key key;
|
||||
|
||||
Layout_FRENCH_PC(char no, char alt, char shift, char alt_shift) {
|
||||
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
|
||||
}
|
||||
|
||||
Layout_FRENCH_PC(KeyChar no, KeyChar alt, KeyChar shift, KeyChar alt_shift) {
|
||||
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
|
||||
}
|
||||
|
||||
public Key getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2000-2023 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Regression test for IDEA-165950: National keyboard layouts support
|
||||
* @requires (jdk.version.major >= 8 & os.family == "mac")
|
||||
* @modules java.desktop/sun.lwawt.macosx
|
||||
* @run main NationalLayoutTest GERMAN
|
||||
*/
|
||||
|
||||
/*
|
||||
* Enumerates keys under test for com.apple.keylayout.German (macOS 10.14.5)
|
||||
*/
|
||||
public enum Layout_GERMAN implements LayoutKey {
|
||||
|
||||
// Enum name must be the same as KeyEvent.VK_ constant name corresponding to the key on US keyboard layout
|
||||
// Note that '\u0000' may be used if no char is mapped to a key + modifier or if one wants to skip its testing
|
||||
|
||||
// Eszett
|
||||
VK_MINUS ('ß', '¿', '?', '˙'),
|
||||
VK_EQUALS (KeyChar.dead('´'), KeyChar.ch('\''), KeyChar.dead('`'), KeyChar.ch('˚')),
|
||||
|
||||
VK_OPEN_BRACKET ('ü', '•', 'Ü', '°'),
|
||||
VK_CLOSE_BRACKET ('+', '±', '*', ''),
|
||||
|
||||
VK_SEMICOLON ('ö', 'œ', 'Ö', 'Œ'),
|
||||
VK_QUOTE ('ä', 'æ', 'Ä', 'Æ'),
|
||||
VK_BACK_SLASH ('#', '‘', '\'', '’'),
|
||||
|
||||
VK_BACK_QUOTE ('<', '≤', '>', '≥'),
|
||||
VK_COMMA (',', '∞', ';', '˛'),
|
||||
VK_PERIOD ('.', '…', ':', '÷'),
|
||||
VK_SLASH ('-', '–', '_', '—'),
|
||||
|
||||
;
|
||||
|
||||
// Common code for any LayoutKey enum
|
||||
|
||||
private final Key key;
|
||||
|
||||
Layout_GERMAN(char no, char alt, char shift, char alt_shift) {
|
||||
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
|
||||
}
|
||||
|
||||
Layout_GERMAN(KeyChar no, KeyChar alt, KeyChar shift, KeyChar alt_shift) {
|
||||
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
|
||||
}
|
||||
|
||||
public Key getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2000-2023 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Regression test for IDEA-165950: National keyboard layouts support
|
||||
* @requires (jdk.version.major >= 8 & os.family == "mac")
|
||||
* @modules java.desktop/sun.lwawt.macosx
|
||||
* @run main NationalLayoutTest SPANISH_ISO
|
||||
*/
|
||||
|
||||
/*
|
||||
* Enumerates keys under test for com.apple.keylayout.Spanish-ISO (macOS 10.14.5)
|
||||
*/
|
||||
public enum Layout_SPANISH_ISO implements LayoutKey {
|
||||
|
||||
// Enum name must be the same as KeyEvent.VK_ constant name corresponding to the key on US keyboard layout
|
||||
// Note that '\u0000' may be used if no char is mapped to a key + modifier or if one wants to skip its testing
|
||||
|
||||
VK_MINUS ('\'', '´', '?', '¸'),
|
||||
VK_EQUALS ('¡', '‚', '¿', '˛'),
|
||||
|
||||
VK_OPEN_BRACKET (KeyChar.dead('`'), KeyChar.ch('['), KeyChar.dead('^'), KeyChar.ch('ˆ')),
|
||||
VK_CLOSE_BRACKET ('+', ']', '*', '±'),
|
||||
|
||||
VK_SEMICOLON (KeyChar.ch('ñ'), KeyChar.dead('~'), KeyChar.ch('Ñ'), KeyChar.ch('˜')),
|
||||
VK_QUOTE (KeyChar.dead('´'), KeyChar.ch('{'), KeyChar.dead('¨'), KeyChar.ch('«')),
|
||||
VK_BACK_SLASH ('ç', '}', 'Ç', '»'),
|
||||
|
||||
VK_BACK_QUOTE ('<', '≤', '>', '≥'),
|
||||
VK_COMMA (',', '„', ';', '\u0000'),
|
||||
VK_PERIOD ('.', '…', ':', '…'),
|
||||
VK_SLASH ('-', '–', '_', '—'),
|
||||
|
||||
;
|
||||
|
||||
// Common code for any LayoutKey enum
|
||||
|
||||
private final Key key;
|
||||
|
||||
Layout_SPANISH_ISO(char no, char alt, char shift, char alt_shift) {
|
||||
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
|
||||
}
|
||||
|
||||
Layout_SPANISH_ISO(KeyChar no, KeyChar alt, KeyChar shift, KeyChar alt_shift) {
|
||||
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
|
||||
}
|
||||
|
||||
public Key getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2000-2023 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Regression test for IDEA-165950: National keyboard layouts support
|
||||
* @requires (jdk.version.major >= 8 & os.family == "mac")
|
||||
* @modules java.desktop/sun.lwawt.macosx
|
||||
* @run main NationalLayoutTest US_INTERNATIONAL_PC
|
||||
*/
|
||||
|
||||
/*
|
||||
* Enumerates keys under test for com.apple.keylayout.USInternational-PC (macOS 10.14.5)
|
||||
*/
|
||||
public enum Layout_US_INTERNATIONAL_PC implements LayoutKey {
|
||||
|
||||
// Enum name must be the same as KeyEvent.VK_ constant name corresponding to the key on US keyboard layout
|
||||
// Note that '\u0000' may be used if no char is mapped to a key + modifier or if one wants to skip its testing
|
||||
|
||||
VK_MINUS ('-', '–', '_', '—'),
|
||||
VK_EQUALS ('=', '≠', '+', '±'),
|
||||
|
||||
VK_OPEN_BRACKET ('[', '“', '{', '”'),
|
||||
VK_CLOSE_BRACKET (']', '‘', '}', '’'),
|
||||
|
||||
VK_SEMICOLON (';', '…', ':', 'Ú'),
|
||||
// ' is a special dead symbol, which may add either acute or cedilla to the next key
|
||||
VK_QUOTE (KeyChar.dead('\''), KeyChar.ch('æ'), KeyChar.dead('\"'), KeyChar.ch('Æ')),
|
||||
VK_BACK_SLASH ('\\', '«', '|', '»'),
|
||||
|
||||
VK_BACK_QUOTE (KeyChar.dead('`'), KeyChar.dead('`'), KeyChar.dead('~'), KeyChar.ch('`')),
|
||||
VK_COMMA (',', '≤', '<', '¯'),
|
||||
VK_PERIOD ('.', '≥', '>', '˘'),
|
||||
VK_SLASH ('/', '÷', '?', '¿'),
|
||||
|
||||
;
|
||||
|
||||
// Common code for any LayoutKey enum
|
||||
|
||||
private final Key key;
|
||||
|
||||
Layout_US_INTERNATIONAL_PC(char no, char alt, char shift, char alt_shift) {
|
||||
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
|
||||
}
|
||||
|
||||
Layout_US_INTERNATIONAL_PC(KeyChar no, KeyChar alt, KeyChar shift, KeyChar alt_shift) {
|
||||
key = new Key(name(), new MappedKeyChars(no, alt, shift, alt_shift));
|
||||
}
|
||||
|
||||
public Key getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2000-2023 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Defines chars mapped to the key on the current keyboard layout
|
||||
*/
|
||||
public class MappedKeyChars {
|
||||
|
||||
private final KeyChar no_modifier;
|
||||
private final KeyChar alt;
|
||||
private final KeyChar shift;
|
||||
private final KeyChar alt_shift;
|
||||
|
||||
MappedKeyChars(char no_modifier, char alt, char shift, char alt_shift) {
|
||||
this.no_modifier = KeyChar.ch(no_modifier);
|
||||
this.alt = KeyChar.ch(alt);
|
||||
this.shift = KeyChar.ch(shift);
|
||||
this.alt_shift = KeyChar.ch(alt_shift);
|
||||
}
|
||||
|
||||
MappedKeyChars(KeyChar no_modifier, KeyChar alt, KeyChar shift, KeyChar alt_shift) {
|
||||
this.no_modifier = no_modifier;
|
||||
this.alt = alt;
|
||||
this.shift = shift;
|
||||
this.alt_shift = alt_shift;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Return char mapped to key + modifier on the current layout.
|
||||
* Return "undefined" char '\uffff', if modifier is a shortcut, i.e. other than Alt, Shift or Alt+Shift or empty.
|
||||
* Return "null" char '\u0000', if there is no char mapped to the key + modifier or its testing is skipped.
|
||||
*/
|
||||
KeyChar getKeyChar(Modifier modifier) {
|
||||
if(modifier.isEmpty()) {
|
||||
return no_modifier;
|
||||
}
|
||||
if(modifier.isAlt()) {
|
||||
return alt;
|
||||
}
|
||||
if(modifier.isShift()) {
|
||||
return shift;
|
||||
}
|
||||
if(modifier.isAltShift()) {
|
||||
return alt_shift;
|
||||
}
|
||||
return KeyChar.ch(Character.MAX_VALUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return char mapped to the low registry key on the current layout, i.e. with no modifier.
|
||||
*/
|
||||
KeyChar getKeyChar() {
|
||||
return no_modifier;
|
||||
}
|
||||
}
|
||||
111
test/jdk/jb/sun/awt/macos/NationalLayoutTest/Modifier.java
Normal file
111
test/jdk/jb/sun/awt/macos/NationalLayoutTest/Modifier.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2000-2023 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
* Enumerates modifier combinations covered by this test
|
||||
*/
|
||||
public enum Modifier {
|
||||
|
||||
E(),
|
||||
//A(KeyEvent.VK_ALT),
|
||||
//S(KeyEvent.VK_SHIFT),
|
||||
//SA(KeyEvent.VK_SHIFT, KeyEvent.VK_ALT),
|
||||
|
||||
// Shortcuts
|
||||
|
||||
M(KeyEvent.VK_META),
|
||||
C(KeyEvent.VK_CONTROL),
|
||||
|
||||
//CS(KeyEvent.VK_CONTROL, KeyEvent.VK_SHIFT),
|
||||
//CA(KeyEvent.VK_CONTROL, KeyEvent.VK_ALT),
|
||||
//CM(KeyEvent.VK_CONTROL, KeyEvent.VK_META),
|
||||
//MS(KeyEvent.VK_META, KeyEvent.VK_SHIFT),
|
||||
//MA(KeyEvent.VK_META, KeyEvent.VK_ALT),
|
||||
|
||||
//CMS(KeyEvent.VK_CONTROL, KeyEvent.VK_META, KeyEvent.VK_SHIFT),
|
||||
//CMA(KeyEvent.VK_CONTROL, KeyEvent.VK_META, KeyEvent.VK_ALT),
|
||||
//CSA(KeyEvent.VK_CONTROL, KeyEvent.VK_SHIFT, KeyEvent.VK_ALT),
|
||||
//MSA(KeyEvent.VK_META, KeyEvent.VK_SHIFT, KeyEvent.VK_ALT),
|
||||
|
||||
//CMSA(KeyEvent.VK_CONTROL, KeyEvent.VK_META, KeyEvent.VK_SHIFT, KeyEvent.VK_ALT),
|
||||
|
||||
;
|
||||
|
||||
// Holds array of int modifier values, where every int value corresponds to modifier KeyEvent.VK_ code
|
||||
private int[] modifiers;
|
||||
|
||||
// Creates empty Modifier
|
||||
Modifier() {
|
||||
this(new int[0]);
|
||||
}
|
||||
|
||||
// Creates Modifier using given KeyEvent.VK_ codes
|
||||
Modifier(int... modifiers) {
|
||||
for(int key : modifiers) {
|
||||
if ((key != KeyEvent.VK_CONTROL) && (key != KeyEvent.VK_META)
|
||||
&& (key != KeyEvent.VK_SHIFT) && (key != KeyEvent.VK_ALT)) {
|
||||
throw new IllegalArgumentException("Bad modifier: " + key);
|
||||
}
|
||||
}
|
||||
this.modifiers = modifiers;
|
||||
}
|
||||
|
||||
// Returns array of int modifier values, where every int value corresponds to modifier KeyEvent.VK_ code
|
||||
int[] getModifiers() {
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
// Checks if no modifier is set
|
||||
boolean isEmpty() {
|
||||
return (modifiers.length == 0);
|
||||
}
|
||||
|
||||
// Checks if modifier is Alt
|
||||
boolean isAlt() {
|
||||
return ((modifiers.length == 1) && (modifiers[0] == KeyEvent.VK_ALT));
|
||||
}
|
||||
|
||||
// Checks if modifier is Shift
|
||||
boolean isShift() {
|
||||
return ((modifiers.length == 1) && (modifiers[0] == KeyEvent.VK_SHIFT));
|
||||
}
|
||||
|
||||
// Checks if modifier is Alt+Shift
|
||||
boolean isAltShift() {
|
||||
List<Integer> list = Arrays.stream(modifiers).boxed().collect(Collectors.toList());
|
||||
return ((modifiers.length == 2) && list.contains(KeyEvent.VK_ALT) && list.contains(KeyEvent.VK_SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (modifiers.length == 0) {
|
||||
return "no";
|
||||
}
|
||||
return Arrays.stream(modifiers).boxed().map(i -> KeyEvent.getKeyText(i)).collect(Collectors.joining(" "));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,538 @@
|
||||
/*
|
||||
* Copyright 2000-2023 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import sun.lwawt.macosx.LWCToolkit;
|
||||
|
||||
import java.awt.AWTException;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Label;
|
||||
import java.awt.Panel;
|
||||
import java.awt.Robot;
|
||||
import java.awt.TextArea;
|
||||
import java.awt.event.FocusAdapter;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.InputMethodEvent;
|
||||
import java.awt.event.InputMethodListener;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.text.CharacterIterator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
* Description: Tests national keyboard layouts on macOS.
|
||||
*
|
||||
* Test goes over existing Layout and Modifier enums.
|
||||
* Each layout key will be tested with all possible modifier combinations.
|
||||
* Test switches to the requested layout (or user changes it by hands).
|
||||
* Then Robot keeps pressing modifier + key, while test keeps tracking of keyPressed, charsTyped and inputMethod events.
|
||||
* Finally, test compares the resulting key presses and typed chars with the expected ones using the assumptions below.
|
||||
*
|
||||
* Test based on the following assumptions:
|
||||
* TODO check if these assumptions are correct
|
||||
* - Pressing "modifier + key" always generates "modifier key code + low registry key code" for any key and modifier.
|
||||
* - No keyTyped event is expected as the result of pressing dead key + key.
|
||||
* - Pressing "dead key + space" generates corresponding diacritic character,
|
||||
* which may be obtained using inputMethodTextChanged event.
|
||||
* - Cmd, Ctrl and its combinations with other modifiers are considered as a "shortcut",
|
||||
* no keyTyped event is expected as the result of pressing a shortcut,
|
||||
* no attempts are made to check inputMethodTextChanged event result for a "shortcut".
|
||||
*
|
||||
* WARNING: Test sends many key presses which may match system and IDE shortcuts.
|
||||
*
|
||||
* !!! DISABLE MACOS SYSTEM SHORTCUTS BEFORE RUNNING THIS TEST !!!
|
||||
* !!! DO NOT RUN THIS TEST FROM IDE !!!
|
||||
*
|
||||
* MacOS accessibility permission should be granted on macOS >= 10.14 for the application launching this test, so
|
||||
* Java Robot is able to access keyboard (use System Preferences -> Security&Privacy -> Privacy tab -> Accessibility).
|
||||
*
|
||||
* Test can only be compiled by JBRSDK as it uses private LWCToolkit API for switching system keyboard layout.
|
||||
* Test may be run by any JRE, but in case of non-JBR, one needs to manually switch the keyboard layout during testing.
|
||||
*
|
||||
* Compilation:
|
||||
* <javac-1.8.*> -bootclasspath <jbrsdk8>/Contents/Home/jre/lib/rt.jar:. NationalLayoutTest.java
|
||||
* <javac-11.*> --add-exports java.desktop/sun.lwawt.macosx=ALL-UNNAMED NationalLayoutTest.java
|
||||
*
|
||||
* Usage:
|
||||
* <java> NationalLayoutTest [manual] [layout1] [layout2] ... , where layoutN is one of the existing Layout enum values
|
||||
*
|
||||
* Examples:
|
||||
* > java NationalLayoutTest
|
||||
* > java NationalLayoutTest ABC SPANISH_ISO
|
||||
* > java NationalLayoutTest manual US_INTERNATIONAL_PC
|
||||
*
|
||||
*/
|
||||
|
||||
public class NationalLayoutTest {
|
||||
|
||||
private static final String MANUAL= "manual";
|
||||
|
||||
private static final int PAUSE = 2000;
|
||||
|
||||
// Test control keys
|
||||
private static final int NEXT_KEY = KeyEvent.VK_ENTER;
|
||||
private static final int NEXT_MODIFIER = KeyEvent.VK_ESCAPE;
|
||||
private static final int TERMINATE_KEY = KeyEvent.VK_SPACE;
|
||||
|
||||
private static CountDownLatch nextKey;
|
||||
private static CountDownLatch nextModifierSet;
|
||||
|
||||
private static boolean jbr = true;
|
||||
private static boolean autoTest = true;
|
||||
private static boolean showKeyCodeHex = false;
|
||||
|
||||
private static Frame mainFrame;
|
||||
|
||||
private static TextArea inputArea;
|
||||
private static TextArea pressArea;
|
||||
private static TextArea typeArea;
|
||||
|
||||
private static Robot robot;
|
||||
|
||||
// Synchronized lists for storing results of different key events
|
||||
private static CopyOnWriteArrayList<Integer> keysPressed = new CopyOnWriteArrayList();
|
||||
private static CopyOnWriteArrayList<Character> charsTyped = new CopyOnWriteArrayList();
|
||||
private static CopyOnWriteArrayList<Character> inputMethodChars = new CopyOnWriteArrayList();
|
||||
|
||||
/*
|
||||
* Test entry point
|
||||
*/
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
|
||||
// Check if the testing could be performed using Java Robot
|
||||
try {
|
||||
robot = new Robot();
|
||||
robot.setAutoDelay(50);
|
||||
} catch (AWTException e) {
|
||||
throw new RuntimeException("TEST ERROR: Cannot create Java Robot " + e);
|
||||
}
|
||||
|
||||
// Check if program arguments contain known layouts to test
|
||||
List<Layout> layoutList = new ArrayList();
|
||||
for (String arg : args) {
|
||||
if(!arg.equals(MANUAL)) {
|
||||
try {
|
||||
layoutList.add(Layout.valueOf(arg));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException("ERROR: Unexpected argument: " + arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// JBR internal API from LWCToolkit is used to switch system keyboard layout.
|
||||
// So running the test for other java implementations is only possible in manual mode.
|
||||
// During the test run one should switch to the requested keyboard layout by hands
|
||||
// and then proceed with testing by pressing NEXT_MODIFIER.
|
||||
if (!System.getProperty("java.vm.vendor").toLowerCase().contains("jetbrains")) {
|
||||
System.out.println("WARNING - Not JBR mode: Cannot automatically switch keyboard layout");
|
||||
jbr = false;
|
||||
}
|
||||
|
||||
// One may want to use MANUAL mode to simply improve visibility.
|
||||
// Please proceed with layout testing by pressing NEXT_MODIFIER.
|
||||
if(Arrays.asList(args).contains(MANUAL) || !(jbr)) {
|
||||
System.out.println("WARNING - Manual mode: Press " + KeyEvent.getKeyText(NEXT_MODIFIER)
|
||||
+ " to start testing keyboard layout with the modifier set");
|
||||
autoTest = false;
|
||||
}
|
||||
|
||||
String initialLayoutName = null;
|
||||
try {
|
||||
// Create test GUI
|
||||
createGUI();
|
||||
|
||||
// Save initial keyboard layout
|
||||
if(jbr) {
|
||||
initialLayoutName = LWCToolkit.getKeyboardLayoutId();
|
||||
}
|
||||
|
||||
boolean failed = false;
|
||||
// Test layouts defined in the command line or all enumerated test layouts in case command line is empty
|
||||
for(Layout layout : (layoutList.isEmpty()
|
||||
? Layout.values() : layoutList.toArray(new Layout[layoutList.size()]))) {
|
||||
// Test layout with all enumerated modifier combinations
|
||||
for (Modifier modifier : Modifier.values()) {
|
||||
if(!testLayout(layout, modifier)) {
|
||||
failed = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
// Provide the test result
|
||||
if(failed) {
|
||||
throw new RuntimeException("TEST FAILED: Some keyboard layout tests failed, check the test output");
|
||||
} else {
|
||||
System.out.println("TEST PASSED");
|
||||
}
|
||||
|
||||
} finally {
|
||||
// Restore initial keyboard layout
|
||||
if(initialLayoutName != null && !initialLayoutName.isEmpty()) {
|
||||
LWCToolkit.switchKeyboardLayout(initialLayoutName);
|
||||
}
|
||||
// Destroy test GUI
|
||||
destroyGUI();
|
||||
// Wait for EDT auto-shutdown
|
||||
Thread.sleep(PAUSE);
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers for checking whether type area got focus
|
||||
private static final CountDownLatch typeAreaGainedFocus = new CountDownLatch(1);
|
||||
private static final FocusListener typeAreaFocusListener = new FocusAdapter() {
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
typeAreaGainedFocus.countDown();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Create the test GUI - main frame with three text areas:
|
||||
* 1) input area shows the current test key combination pressed by Java Robot
|
||||
* 2) press area shows what key pressed events was received as the result of 1
|
||||
* 3) type area (which is initially focused) shows symbols typed as the result of 1
|
||||
*/
|
||||
private static void createGUI() throws InterruptedException {
|
||||
|
||||
mainFrame = new Frame("Test Frame");
|
||||
inputArea = new TextArea("",50, 30);
|
||||
pressArea = new TextArea("", 50, 30);
|
||||
typeArea = new TextArea("",50, 30);
|
||||
|
||||
// Add listeners to track keyboard events
|
||||
typeArea.addFocusListener(typeAreaFocusListener);
|
||||
typeArea.addKeyListener(keyListener);
|
||||
typeArea.addInputMethodListener(inputMethodListener);
|
||||
|
||||
Panel labelPanel = new Panel();
|
||||
labelPanel.add(new Label("Input Keys ---> Pressed Keys ---> Typed Chars"));
|
||||
|
||||
Panel textPanel = new Panel();
|
||||
textPanel.setLayout(new FlowLayout());
|
||||
textPanel.add(inputArea);
|
||||
textPanel.add(pressArea);
|
||||
textPanel.add(typeArea);
|
||||
|
||||
mainFrame.setLocation(200, 200);
|
||||
mainFrame.add(labelPanel, BorderLayout.NORTH);
|
||||
mainFrame.add(textPanel, BorderLayout.SOUTH);
|
||||
mainFrame.pack();
|
||||
mainFrame.setVisible(true);
|
||||
|
||||
typeArea.requestFocusInWindow();
|
||||
// Check if type area got focus.
|
||||
// Corresponding latch is released in the typeAreaFocusListener.
|
||||
if(!typeAreaGainedFocus.await(PAUSE, TimeUnit.MILLISECONDS)) {
|
||||
throw new RuntimeException("TEST ERROR: Failed to request focus in the text area for typing");
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the test GUI
|
||||
*/
|
||||
private static void destroyGUI() {
|
||||
if(typeArea != null) {
|
||||
typeArea.removeFocusListener(typeAreaFocusListener);
|
||||
typeArea.removeKeyListener(keyListener);
|
||||
typeArea.removeInputMethodListener(inputMethodListener);
|
||||
}
|
||||
if(mainFrame != null) {
|
||||
mainFrame.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Listener for keyPressed and keyTyped events
|
||||
*/
|
||||
private static final KeyListener keyListener = new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
// Obtain pressed key code
|
||||
int keyCode = e.getKeyCode();
|
||||
if (keyCode == KeyEvent.VK_UNDEFINED) {
|
||||
keyCode = e.getExtendedKeyCode();
|
||||
}
|
||||
if (keyCode == NEXT_MODIFIER) {
|
||||
// Support for manual mode: notify main thread that testing may be continued
|
||||
nextModifierSet.countDown();
|
||||
} else if (keyCode == NEXT_KEY) {
|
||||
// Update press area with the next line
|
||||
pressArea.append("\n");
|
||||
// Notify main thread that all events related to the key testing should already have been received
|
||||
nextKey.countDown();
|
||||
} else if (keyCode == TERMINATE_KEY) {
|
||||
// Do nothing, press TERMINATE_KEY_SEQUENCE to support dead key testing
|
||||
} else {
|
||||
String keyText = KeyEvent.getKeyText(keyCode);
|
||||
// Update press area with the pressed key text
|
||||
pressArea.append(keysPressed.isEmpty() ? keyText : " " + keyText);
|
||||
// Store pressed key code to the corresponding list
|
||||
keysPressed.add(keyCode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) {
|
||||
// Obtain typed char
|
||||
char keyChar = e.getKeyChar();
|
||||
int keyCode = KeyEvent.getExtendedKeyCodeForChar(keyChar);
|
||||
if ((keyCode != NEXT_MODIFIER) && (keyCode != NEXT_KEY) && (keyCode != TERMINATE_KEY)) {
|
||||
// Store typed char to the corresponding list
|
||||
charsTyped.add(keyChar);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Test listener for InputMethod events.
|
||||
* Such events may occur for a special case when a character is generated by pressing more than one key,
|
||||
* for example, when attaching specific diacritic to a base letter, by pressing dead key + base key.
|
||||
*/
|
||||
static final InputMethodListener inputMethodListener = new InputMethodListener() {
|
||||
@Override
|
||||
public void inputMethodTextChanged(InputMethodEvent e) {
|
||||
// Store generated chars to the corresponding list
|
||||
if(e.getCommittedCharacterCount() > 0) {
|
||||
CharacterIterator text = e.getText();
|
||||
for (char ch = text.first(); ch != CharacterIterator.DONE; ch = text.next()) {
|
||||
inputMethodChars.add(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void caretPositionChanged(InputMethodEvent event) {
|
||||
// Do nothing
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Main method for testing defined layout keys with the specific modifier set
|
||||
*/
|
||||
private static boolean testLayout(Layout layout, Modifier modifier) throws InterruptedException {
|
||||
boolean result = true;
|
||||
System.out.println("\nStart testing " + layout + " layout with " + modifier + " modifier(s):");
|
||||
|
||||
// Switch current keyboard layout to the test one
|
||||
if(jbr) {
|
||||
LWCToolkit.switchKeyboardLayout(layout.toString());
|
||||
}
|
||||
|
||||
// Support for manual mode: wait while user switches the keyboard layout (if needed)
|
||||
// and proceed with layout + modifier testing by pressing NEXT_MODIFIER.
|
||||
// Corresponding latch is released in the keyListener when NEXT_MODIFIER key event is received.
|
||||
nextModifierSet = new CountDownLatch(1);
|
||||
if(autoTest) {
|
||||
pressKey(NEXT_MODIFIER);
|
||||
}
|
||||
if(!nextModifierSet.await(PAUSE*10, TimeUnit.MILLISECONDS)) {
|
||||
throw new RuntimeException("TEST ERROR: User has not proceeded with manual testing");
|
||||
};
|
||||
|
||||
// Clean up the test text areas
|
||||
inputArea.setText("");
|
||||
pressArea.setText("");
|
||||
// Workaround jdk8 setText() issue
|
||||
typeArea.setText(" ");
|
||||
|
||||
// Store modifier keys to array
|
||||
int[] modifiers = modifier.getModifiers();
|
||||
|
||||
// Go over all keys defined for the layout
|
||||
for(LayoutKey layoutKey : layout.getLayoutKeys()) {
|
||||
|
||||
// Clean up synchronized lists which store pressed key codes and typed chars
|
||||
keysPressed = new CopyOnWriteArrayList();
|
||||
charsTyped = new CopyOnWriteArrayList();
|
||||
inputMethodChars = new CopyOnWriteArrayList();
|
||||
|
||||
// Get Key object from LayoutKey enum
|
||||
Key key = layoutKey.getKey();
|
||||
|
||||
// Obtain the key code for the current layout
|
||||
int keyCode = key.getKeyCode();
|
||||
|
||||
// Append input area with the modifiers + key under test
|
||||
if(!modifier.isEmpty()) {
|
||||
inputArea.append(modifier + " ");
|
||||
}
|
||||
inputArea.append(KeyEvent.getKeyText(keyCode) + "\n");
|
||||
|
||||
// Robot only knows US keyboard layout.
|
||||
// So, to press modifier + key under test on the current layout,
|
||||
// one need to pass corresponding US layout key code to Robot.
|
||||
pressKey(key.getKeyCode_US(), modifiers);
|
||||
|
||||
// The key under test may be a dead key which does not generate a character by itself.
|
||||
// But it modifies the character generated by the key pressed immediately after.
|
||||
// So need to press some TERMINATE_KEY key to avoid dead key influence on the next key under test.
|
||||
// Corresponding diacritic character by itself can be generated by pressing dead key followed by space.
|
||||
// That is why pressing TERMINATE_KEY=space after a dead key resets the dead key modifier
|
||||
// and allows testing the generated character which may be useful for some layouts.
|
||||
// Test does two checks: if modifier + key is a dead key and if key with no modifier is a dead key.
|
||||
// Second check is needed for shortcuts as key.isDead(modifier) is always false for a shortcut.
|
||||
if(key.isDead(modifier) || key.isDead()) {
|
||||
pressKey(TERMINATE_KEY);
|
||||
}
|
||||
|
||||
// Wait while NEXT_KEY is pressed, which identifies that modifier + key testing is finished.
|
||||
// Corresponding latch is released in the keyListener when NEXT_KEY key event is received.
|
||||
nextKey = new CountDownLatch(1);
|
||||
pressKey(NEXT_KEY);
|
||||
if(!nextKey.await(PAUSE, TimeUnit.MILLISECONDS)) {
|
||||
throw new RuntimeException("TEST ERROR: "
|
||||
+ KeyEvent.getKeyText(NEXT_KEY) + " key pressed event was not received");
|
||||
};
|
||||
|
||||
// Define array of key codes expected to be pressed as the result of modifiers + key
|
||||
int[] keysPattern = Arrays.copyOf(modifiers, modifiers.length + 1);
|
||||
keysPattern[modifiers.length] = keyCode;
|
||||
|
||||
// Define array of key codes which were really pressed as the result of modifiers + key
|
||||
int[] keysResult = listToInts(keysPressed);
|
||||
|
||||
// Do not check the resulting character in case it is null,
|
||||
// i.e. no char is mapped to the modifier or there is no need to test it.
|
||||
if (key.isCharNull(modifier)) {
|
||||
// Check if the pressed key codes are equal to the expected ones
|
||||
if(!checkResult(keysPattern, keysResult, null,null)) {
|
||||
result = false;
|
||||
};
|
||||
} else {
|
||||
// Define array of chars expected to be typed as the result of modifiers + key
|
||||
// Do not expect any char typed as the result of shortcut (char is undefined in this case)
|
||||
char[] charsPattern = key.isCharUndefined(modifier)
|
||||
? new char[0] : new char[] { key.getChar(modifier) };
|
||||
// Define array of chars which were really typed as the result of modifiers + key
|
||||
// No keyTyped events may be generated as the result of pressing a dead key + space,
|
||||
// so check if input method text was updated in this case.
|
||||
char[] charsResult = (key.isDead(modifier) && charsTyped.isEmpty())
|
||||
? listToChars(inputMethodChars) : listToChars(charsTyped);
|
||||
// Check if pressed key codes and typed chars are equal to the expected ones
|
||||
if(!checkResult(keysPattern, keysResult, charsPattern, charsResult)) {
|
||||
result = false;
|
||||
};
|
||||
}
|
||||
}
|
||||
// Provide layout + modifier testing result
|
||||
System.out.println("Finish testing " + layout + " layout with " + modifier + " modifier(s): "
|
||||
+ (result ? "PASSED" : "FAILED"));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use Java Robot to press the key with specific modifiers
|
||||
*/
|
||||
private static void pressKey(int keyCode, int... modifiers) {
|
||||
robot.waitForIdle();
|
||||
for (int modifier : modifiers) {
|
||||
robot.keyPress(modifier);
|
||||
}
|
||||
robot.keyPress(keyCode);
|
||||
robot.keyRelease(keyCode);
|
||||
for (int modifier : modifiers) {
|
||||
robot.keyRelease(modifier);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if keys pressed and char typed are equal to the expected ones
|
||||
*/
|
||||
private static boolean checkResult(int[] patternKeys, int[] resultKeys, char[] patternChars, char[] resultChars) {
|
||||
|
||||
boolean checkKeys = Arrays.equals(patternKeys, resultKeys);
|
||||
boolean checkChars = Arrays.equals(patternChars, resultChars);
|
||||
|
||||
boolean result = (checkKeys & checkChars);
|
||||
|
||||
if(!result) {
|
||||
String[] patternStr = (patternKeys != null) ? intsToStrings(patternKeys) : null;
|
||||
String[] resultStr = (resultKeys != null) ? intsToStrings(resultKeys) : null;
|
||||
String eqKeys = checkKeys ? " == " : " != ";
|
||||
System.err.println("keyText : " + Arrays.toString(patternStr) + eqKeys + Arrays.toString(resultStr));
|
||||
System.err.println("keyCode : " + Arrays.toString(patternKeys) + eqKeys + Arrays.toString(resultKeys));
|
||||
if(showKeyCodeHex) {
|
||||
String[] patternHex = intsToHexStrings(patternKeys);
|
||||
String[] resultHex = intsToHexStrings(resultKeys);
|
||||
System.err.println("keyCodeHex: " + Arrays.toString(patternHex) + eqKeys + Arrays.toString(resultHex));
|
||||
}
|
||||
}
|
||||
if(!checkChars) {
|
||||
String[] patternHex = (patternChars != null) ? charsToHexStrings(patternChars) : null;
|
||||
String[] resultHex = (resultChars != null) ? charsToHexStrings(resultChars) : null;
|
||||
String eqChars = checkChars ? " == " : " != ";
|
||||
System.err.println("keyChar : " + Arrays.toString(patternChars) + eqChars + Arrays.toString(resultChars));
|
||||
System.err.println("keyCharHex: " + Arrays.toString(patternHex) + eqChars + Arrays.toString(resultHex));
|
||||
}
|
||||
if(!result) {
|
||||
System.err.println();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform list of Integers to int array
|
||||
*/
|
||||
private static int[] listToInts(List<Integer> list) {
|
||||
return list.stream().mapToInt(i->i).toArray();
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform list of Characters to char array
|
||||
*/
|
||||
private static char[] listToChars(List<Character> list) {
|
||||
return list.stream().map(c -> c.toString()).collect(Collectors.joining()).toCharArray();
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform array of int keys to array of Strings, mapping an int key to its text representation
|
||||
*/
|
||||
private static String[] intsToStrings(int[] ints) {
|
||||
return Arrays.stream(ints).boxed().map(i -> KeyEvent.getKeyText(i)).toArray(String[]::new);
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform array of int keys to array of Strings, mapping an int key to its hex representation
|
||||
*/
|
||||
private static String[] intsToHexStrings(int[] ints) {
|
||||
return Arrays.stream(ints).boxed().map(i -> String.format("0x%1$04X", i)).toArray(String[]::new);
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform array of char to array of Strings, mapping a char to its hex representation
|
||||
*/
|
||||
private static String[] charsToHexStrings(char[] chars) {
|
||||
int[] result = new int[chars.length];
|
||||
Arrays.setAll(result, i -> (int) chars[i]);
|
||||
return intsToHexStrings(result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user