JBR-5173 macOS keyboard support rewrite

with fix for JBR-5300 Change source code and test files to use GPL license
This commit is contained in:
Nikita Tsarev
2023-01-31 17:32:58 +01:00
committed by jbrbot
parent 42647a5943
commit af0d7d3ef5
17 changed files with 880 additions and 43 deletions

View File

@@ -26,6 +26,7 @@
package sun.lwawt.macosx;
import sun.awt.SunToolkit;
import sun.awt.event.KeyEventProcessing;
import sun.lwawt.LWWindowPeer;
import sun.lwawt.PlatformEventNotifier;
@@ -183,7 +184,7 @@ final class CPlatformResponder {
boolean spaceKeyTyped = false;
char testChar = KeyEvent.CHAR_UNDEFINED;
boolean isDeadChar = (chars!= null && chars.length() == 0);
boolean isDeadChar = (chars != null && chars.length() == 0);
if (isFlagsChangedEvent) {
int[] in = new int[] {modifierFlags, keyCode};
@@ -196,7 +197,11 @@ final class CPlatformResponder {
jeventType = out[2];
} else {
if (chars != null && chars.length() > 0) {
testChar = chars.charAt(0);
// Find a suitable character to report as a keypress.
// `chars` might contain more than one character
// e.g. when Dead Grave + S were pressed, `chars` will contain "`s"
// Since we only really care about the last character, let's use it
testChar = chars.charAt(chars.length() - 1);
//Check if String chars contains SPACE character.
if (chars.trim().isEmpty()) {
@@ -207,7 +212,7 @@ final class CPlatformResponder {
char testCharIgnoringModifiers = charsIgnoringModifiers != null && charsIgnoringModifiers.length() > 0 ?
charsIgnoringModifiers.charAt(0) : KeyEvent.CHAR_UNDEFINED;
int[] in = new int[] {testCharIgnoringModifiers, isDeadChar ? 1 : 0, modifierFlags, keyCode};
int[] in = new int[] {testCharIgnoringModifiers, isDeadChar ? 1 : 0, modifierFlags, keyCode, KeyEventProcessing.useNationalLayouts ? 1 : 0};
int[] out = new int[3]; // [jkeyCode, jkeyLocation, deadChar]
postsTyped = NSEvent.nsToJavaKeyInfo(in, out);
@@ -215,10 +220,14 @@ final class CPlatformResponder {
testChar = KeyEvent.CHAR_UNDEFINED;
}
if(isDeadChar){
if (isDeadChar) {
testChar = (char) out[2];
if(testChar == 0){
return;
if (testChar == 0) {
// Not abandoning the input event here, since we want to catch dead key presses.
// Consider Option+E on the standard ABC layout. This key combination produces a dead accent.
// The key 'E' by itself is not dead, thus out[2] will be 0, even though isDeadChar is true.
// If we abandon the event there, this key press will never get delivered to the application.
testChar = KeyEvent.CHAR_UNDEFINED;
}
}
@@ -227,11 +236,12 @@ final class CPlatformResponder {
// It is necessary to use testCharIgnoringModifiers instead of testChar for event
// generation in such case to avoid uppercase letters in text components.
LWCToolkit lwcToolkit = (LWCToolkit)Toolkit.getDefaultToolkit();
if ((lwcToolkit.getLockingKeyState(KeyEvent.VK_CAPS_LOCK) &&
if (testChar != KeyEvent.CHAR_UNDEFINED &&
((lwcToolkit.getLockingKeyState(KeyEvent.VK_CAPS_LOCK) &&
Locale.SIMPLIFIED_CHINESE.equals(lwcToolkit.getDefaultKeyboardLocale())) ||
(LWCToolkit.isLocaleUSInternationalPC(lwcToolkit.getDefaultKeyboardLocale()) &&
LWCToolkit.isCharModifierKeyInUSInternationalPC(testChar) &&
(testChar != testCharIgnoringModifiers))) {
(testChar != testCharIgnoringModifiers)))) {
testChar = testCharIgnoringModifiers;
}
@@ -241,10 +251,16 @@ final class CPlatformResponder {
NSEvent.nsToJavaEventType(eventType);
}
char javaChar = NSEvent.nsToJavaChar(testChar, modifierFlags, spaceKeyTyped);
// Some keys may generate a KEY_TYPED, but we can't determine
// what that character is. That's likely a bug, but for now we
// just check for CHAR_UNDEFINED.
char javaChar = (testChar == KeyEvent.CHAR_UNDEFINED) ? KeyEvent.CHAR_UNDEFINED :
NSEvent.nsToJavaChar(testChar, modifierFlags, spaceKeyTyped);
// Some keys may generate a KEY_TYPED, but we can't determine what that character is.
// This may happen during the key combinations that produce dead keys (like Option+E described before),
// since we don't care about the dead key for the purposes of keyPressed event, nor do the dead keys
// produce input by themselves. In this case we set postsTyped to false, so that the application
// doesn't receive unnecessary KEY_TYPED events.
//
// In cases not involving dead keys combos, having javaChar == CHAR_UNDEFINED is most likely a bug.
// Since we can't determine which character is supposed to be typed let's just ignore it.
if (javaChar == KeyEvent.CHAR_UNDEFINED) {
postsTyped = false;
}

View File

@@ -137,6 +137,21 @@ public final class LWCToolkit extends LWToolkit {
private static native void initAppkit(ThreadGroup appKitThreadGroup, boolean headless);
private static CInputMethodDescriptor sInputMethodDescriptor;
private static native void switchKeyboardLayoutNative(String layoutName);
static private native String getKeyboardLayoutNativeId();
public static void switchKeyboardLayout (String layoutName) {
if (layoutName == null || layoutName.isEmpty()) {
throw new RuntimeException("A valid layout ID is expected. Found: " + layoutName);
}
switchKeyboardLayoutNative(layoutName);
}
public static String getKeyboardLayoutId () {
return getKeyboardLayoutNativeId();
}
// Listens to EDT state in invokeAndWait() and disposes the invocation event
// when EDT becomes free but the invocation event is not yet dispatched (considered lost).
// This prevents a deadlock and makes the invocation return some default result.

View File

@@ -232,6 +232,58 @@ static const struct CharToVKEntry charToDeadVKTable[] = {
{0,0}
};
// This table is analogous to a similar one found in sun.awt.ExtendedKeyCodes.
// It governs translating the unicode codepoints into the proper VK_ values for keys that have one.
// It only deals with punctuation characters and certain exceptional letters from extended latin set.
// Also see test/jdk/jb/sun/awt/macos/InputMethodTest/KeyCodesTest.java
static const struct CharToVKEntry extraCharToVKTable[] = {
{0x0021, java_awt_event_KeyEvent_VK_EXCLAMATION_MARK},
{0x0022, java_awt_event_KeyEvent_VK_QUOTEDBL},
{0x0023, java_awt_event_KeyEvent_VK_NUMBER_SIGN},
{0x0024, java_awt_event_KeyEvent_VK_DOLLAR},
{0x0026, java_awt_event_KeyEvent_VK_AMPERSAND},
{0x0027, java_awt_event_KeyEvent_VK_QUOTE},
{0x0028, java_awt_event_KeyEvent_VK_LEFT_PARENTHESIS},
{0x0029, java_awt_event_KeyEvent_VK_RIGHT_PARENTHESIS},
{0x002A, java_awt_event_KeyEvent_VK_ASTERISK},
{0x002B, java_awt_event_KeyEvent_VK_PLUS},
{0x002C, java_awt_event_KeyEvent_VK_COMMA},
{0x002D, java_awt_event_KeyEvent_VK_MINUS},
{0x002E, java_awt_event_KeyEvent_VK_PERIOD},
{0x002F, java_awt_event_KeyEvent_VK_SLASH},
{0x003A, java_awt_event_KeyEvent_VK_COLON},
{0x003B, java_awt_event_KeyEvent_VK_SEMICOLON},
{0x003C, java_awt_event_KeyEvent_VK_LESS},
{0x003D, java_awt_event_KeyEvent_VK_EQUALS},
{0x003E, java_awt_event_KeyEvent_VK_GREATER},
{0x0040, java_awt_event_KeyEvent_VK_AT},
{0x005B, java_awt_event_KeyEvent_VK_OPEN_BRACKET},
{0x005C, java_awt_event_KeyEvent_VK_BACK_SLASH},
{0x005D, java_awt_event_KeyEvent_VK_CLOSE_BRACKET},
{0x005E, java_awt_event_KeyEvent_VK_CIRCUMFLEX},
{0x005F, java_awt_event_KeyEvent_VK_UNDERSCORE},
{0x0060, java_awt_event_KeyEvent_VK_BACK_QUOTE},
{0x007B, java_awt_event_KeyEvent_VK_BRACELEFT},
{0x007D, java_awt_event_KeyEvent_VK_BRACERIGHT},
{0x00A1, java_awt_event_KeyEvent_VK_INVERTED_EXCLAMATION_MARK},
// These are the extended latin characters which have a non-obvious key code.
// Their key codes are derived from the upper case instead of the lower case.
// It probably has to do with how these key codes are reported on Windows.
// Translating these characters to the key codes corresponding to their uppercase versions
// makes getExtendedKeyCodeForChar consistent with how these events are reported on macOS.
{0x00E4, 0x01000000+0x00C4},
{0x00E5, 0x01000000+0x00C5},
{0x00E6, 0x01000000+0x00C6},
{0x00E7, 0x01000000+0x00C7},
{0x00F1, 0x01000000+0x00D1},
{0x00F6, 0x01000000+0x00D6},
{0x00F8, 0x01000000+0x00D8},
{0x20AC, java_awt_event_KeyEvent_VK_EURO_SIGN},
{0, 0}
};
// TODO: some constants below are part of CGS (private interfaces)...
// for now we will look at the raw key code to determine left/right status
// but not sure this is foolproof...
@@ -381,14 +433,18 @@ unichar NsCharToJavaChar(unichar nsChar, NSUInteger modifiers, BOOL spaceKeyType
return nsChar;
}
static unichar NsGetDeadKeyChar(unsigned short keyCode)
static unichar NsGetDeadKeyChar(unsigned short keyCode, BOOL useModifiers)
{
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
if (uchr == nil) { return 0; }
const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr);
// Carbon modifiers should be used instead of NSEvent modifiers
UInt32 modifierKeyState = (GetCurrentEventKeyModifiers() >> 8) & 0xFF;
UInt32 modifierKeyState = 0;
if (useModifiers) {
// Carbon modifiers should be used instead of NSEvent modifiers
modifierKeyState = (GetCurrentEventKeyModifiers() >> 8) & 0xFF;
}
if (keyboardLayout) {
UInt32 deadKeyState = 0;
@@ -427,41 +483,77 @@ static unichar NsGetDeadKeyChar(unsigned short keyCode)
*/
static void
NsCharToJavaVirtualKeyCode(unichar ch, BOOL isDeadChar,
NSUInteger flags, unsigned short key,
NSUInteger flags, unsigned short key, const BOOL useNationalLayouts,
jint *keyCode, jint *keyLocation, BOOL *postsTyped,
unichar *deadChar)
{
static size_t size = sizeof(keyTable) / sizeof(struct _key);
static const size_t keyTableSize = sizeof(keyTable) / sizeof(struct _key);
NSInteger offset;
if (isDeadChar) {
unichar testDeadChar = NsGetDeadKeyChar(key);
// If the key without modifiers generates a dead char, then this is the character
// that is produced when pressing the key followed by a space
// Otherwise, it's the null character
unichar testDeadCharWithoutModifiers = NsGetDeadKeyChar(key, NO);
if (testDeadCharWithoutModifiers != 0) {
// Same as testDeadCharWithoutModifiers above, only this time we take modifiers into account.
unichar testDeadChar = NsGetDeadKeyChar(key, YES);
const struct CharToVKEntry *map;
for (map = charToDeadVKTable; map->c != 0; ++map) {
if (testDeadChar == map->c) {
if (testDeadCharWithoutModifiers == map->c) {
// The base key is a dead key in the current layout.
// The key with modifiers might or might not be dead.
// We report it here so as not to cause any confusion,
// since non-dead keys can reuse the same characters as dead keys
*keyCode = map->javaKey;
*postsTyped = NO;
*postsTyped = (BOOL)(testDeadChar == 0);
// TODO: use UNKNOWN here?
*keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;
*deadChar = testDeadChar;
return;
}
}
// If we got here, we keep looking for a normal key.
}
if ([[NSCharacterSet letterCharacterSet] characterIsMember:ch]) {
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
// Whether this is a latin-based keyboard layout (English, German, French, etc)
BOOL asciiCapable = (BOOL)((Boolean)CFBooleanGetValue(
(CFBooleanRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyInputSourceIsASCIICapable)));
unichar testLowercaseChar = tolower(ch);
if (useNationalLayouts && asciiCapable) {
// If national layouts are enabled and the current keyboard is latin-based then
// we try to look up a character in a table first, before falling back to looking up
// the virtual key code from macOS's hardware key code, since hardware key codes
// don't respect the specific keyboard layout the user uses.
for (const struct CharToVKEntry *map = extraCharToVKTable; map->c != 0; ++map) {
if (map->c == testLowercaseChar) {
*keyCode = map->javaKey;
*postsTyped = !isDeadChar;
*keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_STANDARD;
return;
}
}
}
if ((!useNationalLayouts || asciiCapable) && [[NSCharacterSet letterCharacterSet] characterIsMember:ch]) {
// Let's convert the received letter to a key code.
// If national layouts are enabled, then the letter must be (extended) latin.
// Otherwise, we will look up the key code from the key location further down below.
// key is an alphabetic character
unichar lower;
lower = tolower(ch);
offset = lower - 'a';
offset = testLowercaseChar - 'a';
if (offset >= 0 && offset <= 25) {
// checking for A-Z characters
*postsTyped = YES;
// do quick conversion
*keyCode = java_awt_event_KeyEvent_VK_A + offset;
*keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_STANDARD;
return;
} else {
// checking for non-english characters
// this value comes from ExtendedKeyCodes.java
@@ -471,8 +563,9 @@ NsCharToJavaVirtualKeyCode(unichar ch, BOOL isDeadChar,
// the keyCode is off by 32, so adding it here
*keyCode = java_awt_event_KeyEvent_VK_A + offset + 32;
*keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_STANDARD;
return;
}
return;
}
if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:ch]) {
@@ -494,7 +587,7 @@ return;
}
}
if (key < size) {
if (key < keyTableSize) {
*postsTyped = keyTable[key].postsTyped;
*keyCode = keyTable[key].javaKeyCode;
*keyLocation = keyTable[key].javaKeyLocation;
@@ -688,11 +781,12 @@ JNI_COCOA_ENTER(env);
jint *data = (*env)->GetIntArrayElements(env, inData, &copy);
CHECK_NULL_RETURN(data, postsTyped);
// in = [testChar, testDeadChar, modifierFlags, keyCode]
// in = [testChar, testDeadChar, modifierFlags, keyCode, useNationalLayouts]
jchar testChar = (jchar)data[0];
BOOL isDeadChar = (data[1] != 0);
jint modifierFlags = data[2];
jshort keyCode = (jshort)data[3];
BOOL useNationalLayouts = (data[4] != 0);
jint jkeyCode = java_awt_event_KeyEvent_VK_UNDEFINED;
jint jkeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;
@@ -700,6 +794,7 @@ JNI_COCOA_ENTER(env);
NsCharToJavaVirtualKeyCode((unichar)testChar, isDeadChar,
(NSUInteger)modifierFlags, (unsigned short)keyCode,
useNationalLayouts,
&jkeyCode, &jkeyLocation, &postsTyped,
(unichar *) &testDeadChar);

View File

@@ -45,6 +45,7 @@
jobject fInputMethodLOCKABLE;
BOOL fKeyEventsNeeded;
BOOL fProcessingKeystroke;
BOOL fComplexInputNeeded;
BOOL fEnablePressAndHold;
BOOL fInPressAndHold;

View File

@@ -85,6 +85,7 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, N
fInputMethodLOCKABLE = NULL;
fKeyEventsNeeded = NO;
fProcessingKeystroke = NO;
fComplexInputNeeded = NO;
fEnablePressAndHold = shouldUsePressAndHold();
fInPressAndHold = NO;
@@ -305,6 +306,19 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, N
- (void) keyDown: (NSEvent *)event {
fProcessingKeystroke = YES;
fKeyEventsNeeded = YES;
fComplexInputNeeded = NO;
NSString *eventCharacters = [event characters];
if ([eventCharacters length] > 0) {
unichar codePoint = [eventCharacters characterAtIndex:0];
if ((codePoint >= 0x3000 && codePoint <= 0x303F) || (codePoint >= 0xff00 && codePoint <= 0xffef)) {
// "CJK Symbols and Punctuation" or "Halfwidth and Fullwidth Forms"
// Force the complex input method because macOS doesn't properly send us
// the half-width characters when the user has them enabled.
fComplexInputNeeded = YES;
}
}
// Allow TSM to look at the event and potentially send back NSTextInputClient messages.
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
@@ -344,7 +358,6 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, N
}
}
NSString *eventCharacters = [event characters];
BOOL isDeadKey = (eventCharacters != nil && [eventCharacters length] == 0);
if ((![self hasMarkedText] && fKeyEventsNeeded) || isDeadKey) {
@@ -523,6 +536,41 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, N
[self resetTrackingArea];
}
- (NSString *) extractCharactersIgnoringAllModifiers: (NSEvent *) event {
// event.charactersIgnoringModifiers is actually not what we want, since it doesn't ignore Shift.
// What we really want is event.charactersByApplyingModifiers:0, but that's only available on macOS 10.15+
// The code below simulates what that function does by looking up the current keyboard and emulating
// a corresponding key press on it.
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
if (uchr == nil) {
return [event charactersIgnoringModifiers];
}
UInt32 deadKeyState = 0;
UniCharCount maxStringLength = 8;
UniCharCount actualStringLength = 0;
unichar unicodeString[maxStringLength];
const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *) CFDataGetBytePtr(uchr);
OSStatus status = UCKeyTranslate(
keyboardLayout,
[event keyCode],
kUCKeyActionDown,
0,
LMGetKbdType(),
kUCKeyTranslateNoDeadKeysMask,
&deadKeyState,
maxStringLength,
&actualStringLength,
unicodeString
);
return [NSString stringWithCharacters:unicodeString length:actualStringLength];
}
-(void) deliverJavaKeyEventHelper: (NSEvent *) event {
static NSEvent* sLastKeyEvent = nil;
if (event == sLastKeyEvent) {
@@ -539,7 +587,7 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, N
jstring charactersIgnoringModifiers = NULL;
if ([event type] != NSEventTypeFlagsChanged) {
characters = NSStringToJavaString(env, [event characters]);
charactersIgnoringModifiers = NSStringToJavaString(env, [event charactersIgnoringModifiers]);
charactersIgnoringModifiers = NSStringToJavaString(env, [self extractCharactersIgnoringAllModifiers:event]);
}
DECLARE_CLASS(jc_NSEvent, "sun/lwawt/macosx/NSEvent");
@@ -622,7 +670,18 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, N
}
}
-(BOOL) isChineseInputMethod {
return ([kbdLayout containsString:@"com.apple.inputmethod.SCIM"] ||
[kbdLayout containsString:@"com.apple.inputmethod.TCIM"] ||
[kbdLayout containsString:@"com.apple.inputmethod.TYIM"]);
}
-(BOOL) isCodePointInUnicodeBlockNeedingIMEvent: (unichar) codePoint {
if ((codePoint == 0x2018 || codePoint == 0x2019 || codePoint == 0x201C || codePoint == 0x201D) && [self isChineseInputMethod]) {
// left/right single/double quotation mark
return YES;
}
if (((codePoint >= 0x900) && (codePoint <= 0x97F)) ||
((codePoint >= 0x20A3) && (codePoint <= 0x20BF)) ||
((codePoint >= 0x3000) && (codePoint <= 0x303F)) ||
@@ -1067,7 +1126,7 @@ static jclass jc_CInputMethod = NULL;
aStringIsComplex = YES;
}
if ([self hasMarkedText] || !fProcessingKeystroke || aStringIsComplex) {
if ([self hasMarkedText] || !fProcessingKeystroke || aStringIsComplex || fComplexInputNeeded) {
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CIM_CLASS();
@@ -1088,6 +1147,7 @@ static jclass jc_CInputMethod = NULL;
// The input method event will create psuedo-key events for each character in the committed string.
// We also don't want to send the character that triggered the insertText, usually a return. [3337563]
fKeyEventsNeeded = NO;
fComplexInputNeeded = NO;
}
else {
// Need to set back the fKeyEventsNeeded flag so that the string following the

View File

@@ -43,6 +43,7 @@
#import "AWTWindow.h"
#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
#import <Carbon/Carbon.h>
// SCROLL PHASE STATE
#define SCROLL_PHASE_UNSUPPORTED 1
@@ -926,3 +927,43 @@ Java_sun_lwawt_macosx_LWCToolkit_getMultiClickTime(JNIEnv *env, jclass klass) {
JNI_COCOA_EXIT(env);
return multiClickTime;
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: getKeyboardLayoutNativeId
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL
JNICALL Java_sun_lwawt_macosx_LWCToolkit_getKeyboardLayoutNativeId(JNIEnv *env, jclass cls)
{
__block NSString * layoutId = NULL;
JNI_COCOA_ENTER(env);
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
TISInputSourceRef source = TISCopyCurrentKeyboardInputSource();
layoutId = TISGetInputSourceProperty(source, kTISPropertyInputSourceID);
}];
JNI_COCOA_EXIT(env);
return NSStringToJavaString(env, layoutId);
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: switchKeyboardLayoutNative
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL
JNICALL Java_sun_lwawt_macosx_LWCToolkit_switchKeyboardLayoutNative(JNIEnv *env, jclass cls, jstring jLayoutId)
{
JNI_COCOA_ENTER(env);
__block NSString* layoutId = [JavaStringToNSString(env, jLayoutId) retain];
[ThreadUtilities performOnMainThreadWaiting:NO block:^(){
NSArray* sources = CFBridgingRelease(TISCreateInputSourceList((__bridge CFDictionaryRef)@{ (__bridge NSString*)kTISPropertyInputSourceID : layoutId }, FALSE));
TISInputSourceRef source = (__bridge TISInputSourceRef)sources[0];
OSStatus status = TISSelectInputSource(source);
if (status != noErr) {
NSLog(@"error during keyboard layout switch");
}
[layoutId release];
}];
JNI_COCOA_EXIT(env);
}

View File

@@ -0,0 +1,22 @@
package sun.awt.event;
import sun.font.FontUtilities;
import java.lang.annotation.Native;
public class KeyEventProcessing {
// This property is used to emulate old behavior
// when user should turn off national keycodes processing
// "com.jetbrains.use.old.keyevent.processing"
public final static String useNationalLayoutsOption = "com.sun.awt.use.national.layouts";
@Native
public final static boolean useNationalLayouts = "true".equals(
System.getProperty(useNationalLayoutsOption,
FontUtilities.isMacOSX ? "true" : "false"));
// Used on windows to emulate latin OEM keys on cyrillic keyboards
public final static String useLatinNonAlphaNumKeycodesOption = "com.sun.awt.useLatinNonAlphaNumKeycodes";
@Native
public final static boolean useLatinNonAlphaNumKeycodes = "true".equals(
System.getProperty(useLatinNonAlphaNumKeycodesOption, "false"));
}

View File

@@ -23,5 +23,5 @@ public class TouchEvent {
@Native
public final static boolean defaultTouchHandling = "true".equalsIgnoreCase(
Util.getProperty(defaultTouchHandlingOption, "false"));
System.getProperty(defaultTouchHandlingOption, "false"));
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 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 JBR-5006 Dead keys exhibit invalid behavior on macOS
* @run shell Runner.sh DeadKeysTest
* @requires (jdk.version.major >= 8 & os.family == "mac")
*/
import static java.awt.event.KeyEvent.*;
public class DeadKeysTest implements Runnable {
@Override
public void run() {
InputMethodTest.layout("com.apple.keylayout.ABC");
InputMethodTest.section("Acute accent + vowel");
InputMethodTest.type(VK_E, ALT_DOWN_MASK);
InputMethodTest.type(VK_A, 0);
InputMethodTest.expect("\u00e1");
InputMethodTest.section("Acute accent + consonant");
InputMethodTest.type(VK_E, ALT_DOWN_MASK);
InputMethodTest.type(VK_S, 0);
InputMethodTest.expect("\u00b4s");
InputMethodTest.section("Acute accent + space");
InputMethodTest.type(VK_E, ALT_DOWN_MASK);
InputMethodTest.type(VK_SPACE, 0);
InputMethodTest.expect("\u00b4");
}
}

View File

@@ -0,0 +1,185 @@
/*
* 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 javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
public class InputMethodTest {
private static JFrame frame;
private static JTextArea textArea;
private static Robot robot;
private static String currentTest = "";
private static String currentSection = "";
private static String initialLayout;
private static boolean success = true;
private static int lastKeyCode = -1;
private enum TestCases {
DeadKeysTest (new DeadKeysTest()),
KeyCodesTest (new KeyCodesTest()),
PinyinQuotesTest (new PinyinQuotesTest()),
PinyinFullWidthPunctuationTest (new PinyinFullWidthPunctuationTest()),
PinyinHalfWidthPunctuationTest (new PinyinHalfWidthPunctuationTest())
;
private Runnable test;
TestCases(Runnable runnable) {
test = runnable;
}
public void run() {
test.run();
}
}
public static void main(String[] args) {
init();
for (String arg : args) {
runTest(arg);
}
LWCToolkit.switchKeyboardLayout(initialLayout);
System.exit(success ? 0 : 1);
}
private static void init() {
try {
robot = new Robot();
robot.setAutoDelay(100);
} catch (AWTException e) {
e.printStackTrace();
System.exit(1);
}
initialLayout = LWCToolkit.getKeyboardLayoutId();
frame = new JFrame("InputMethodTest");
frame.setVisible(true);
frame.setSize(300, 300);
frame.setLocationRelativeTo(null);
textArea = new JTextArea();
textArea.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent keyEvent) {}
@Override
public void keyPressed(KeyEvent keyEvent) {
lastKeyCode = keyEvent.getKeyCode();
}
@Override
public void keyReleased(KeyEvent keyEvent) {}
});
frame.setLayout(new BorderLayout());
frame.getContentPane().add(textArea, BorderLayout.CENTER);
textArea.grabFocus();
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {}
}
private static void runTest(String name) {
currentTest = name;
TestCases.valueOf(name).run();
}
public static void section(String description) {
currentSection = description;
textArea.setText("");
frame.setTitle(currentTest + ": " + description);
}
public static void layout(String name) {
LWCToolkit.switchKeyboardLayout(name);
}
public static void type(int key, int modifiers) {
lastKeyCode = -1;
List<Integer> modKeys = new ArrayList<>();
if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0) {
modKeys.add(KeyEvent.VK_ALT);
}
if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0) {
modKeys.add(KeyEvent.VK_CONTROL);
}
if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0) {
modKeys.add(KeyEvent.VK_SHIFT);
}
if ((modifiers & InputEvent.META_DOWN_MASK) != 0) {
modKeys.add(KeyEvent.VK_META);
}
for (var modKey : modKeys) {
robot.keyPress(modKey);
}
robot.keyPress(key);
robot.keyRelease(key);
for (var modKey : modKeys) {
robot.keyRelease(modKey);
}
}
public static void expect(String expectedValue) {
var actualValue = textArea.getText();
if (actualValue.equals(expectedValue)) {
System.out.printf("Test %s (%s) passed, got '%s'\n", currentTest, currentSection, actualValue);
} else {
success = false;
System.out.printf("Test %s (%s) failed, expected '%s', got '%s'\n", currentTest, currentSection, expectedValue, actualValue);
}
}
public static void expectKeyCode(int keyCode) {
if (lastKeyCode == keyCode) {
System.out.printf("Test %s (%s) passed, got key code %d\n", currentTest, currentSection, keyCode);
} else {
success = false;
System.out.printf("Test %s (%s) failed, expected key code %d, got %d\n", currentTest, currentSection, keyCode, lastKeyCode);
}
}
public static void expectTrue(boolean value, String comment) {
if (value) {
System.out.printf("Test %s (%s) passed: %s\n", currentTest, currentSection, comment);
} else {
success = false;
System.out.printf("Test %s (%s) failed: %s\n", currentTest, currentSection, comment);
}
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 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 JBR-5173 macOS keyboard support rewrite
* @run shell Runner.sh KeyCodesTest
* @requires (jdk.version.major >= 8 & os.family == "mac")
*/
import static java.awt.event.KeyEvent.*;
public class KeyCodesTest implements Runnable {
@Override
public void run() {
verify('!', VK_EXCLAMATION_MARK, "com.apple.keylayout.French-PC", VK_SLASH);
verify('"', VK_QUOTEDBL, "com.apple.keylayout.French-PC", VK_3);
verify('#', VK_NUMBER_SIGN, "com.apple.keylayout.British-PC", VK_BACK_SLASH);
verify('$', VK_DOLLAR, "com.apple.keylayout.French-PC", VK_CLOSE_BRACKET);
verify('&', VK_AMPERSAND, "com.apple.keylayout.French-PC", VK_1);
verify('\'', VK_QUOTE, "com.apple.keylayout.French-PC", VK_4);
verify('(', VK_LEFT_PARENTHESIS, "com.apple.keylayout.French-PC", VK_5);
verify(')', VK_RIGHT_PARENTHESIS, "com.apple.keylayout.French-PC", VK_MINUS);
verify('*', VK_ASTERISK, "com.apple.keylayout.French-PC", VK_BACK_SLASH);
verify('+', VK_PLUS, "com.apple.keylayout.German", VK_CLOSE_BRACKET);
verify(',', VK_COMMA, "com.apple.keylayout.ABC", VK_COMMA);
verify('-', VK_MINUS, "com.apple.keylayout.ABC", VK_MINUS);
verify('.', VK_PERIOD, "com.apple.keylayout.ABC", VK_PERIOD);
verify('/', VK_SLASH, "com.apple.keylayout.ABC", VK_SLASH);
verify(':', VK_COLON, "com.apple.keylayout.French-PC", VK_PERIOD);
verify(';', VK_SEMICOLON, "com.apple.keylayout.ABC", VK_SEMICOLON);
verify('<', VK_LESS, "com.apple.keylayout.French-PC", VK_BACK_QUOTE);
verify('=', VK_EQUALS, "com.apple.keylayout.ABC", VK_EQUALS);
// TODO: figure out which keyboard layout has VK_GREATER as a key on the primary layer
verify('@', VK_AT, "com.apple.keylayout.Norwegian", VK_BACK_SLASH);
verify('[', VK_OPEN_BRACKET, "com.apple.keylayout.ABC", VK_OPEN_BRACKET);
verify('\\', VK_BACK_SLASH, "com.apple.keylayout.ABC", VK_BACK_SLASH);
verify(']', VK_CLOSE_BRACKET, "com.apple.keylayout.ABC", VK_CLOSE_BRACKET);
// TODO: figure out which keyboard layout has VK_CIRCUMFLEX as a key on the primary layer
verify('_', VK_UNDERSCORE, "com.apple.keylayout.French-PC", VK_8);
verify('`', VK_BACK_QUOTE, "com.apple.keylayout.ABC", VK_BACK_QUOTE);
verify('{', VK_BRACELEFT, "com.apple.keylayout.LatinAmerican", VK_QUOTE);
verify('}', VK_BRACERIGHT, "com.apple.keylayout.LatinAmerican", VK_BACK_SLASH);
verify('\u00a1', VK_INVERTED_EXCLAMATION_MARK, "com.apple.keylayout.Spanish-ISO", VK_EQUALS);
// TODO: figure out which keyboard layout has VK_EURO_SIGN as a key on the primary layer
verify('\u00e4', 0x01000000+0x00C4, "com.apple.keylayout.German", VK_QUOTE);
verify('\u00e5', 0x01000000+0x00C5, "com.apple.keylayout.Norwegian", VK_OPEN_BRACKET);
verify('\u00e6', 0x01000000+0x00C6, "com.apple.keylayout.Norwegian", VK_QUOTE);
verify('\u00e7', 0x01000000+0x00C7, "com.apple.keylayout.French-PC", VK_9);
verify('\u00f1', 0x01000000+0x00D1, "com.apple.keylayout.Spanish-ISO", VK_SEMICOLON);
verify('\u00f6', 0x01000000+0x00D6, "com.apple.keylayout.German", VK_SEMICOLON);
verify('\u00f8', 0x01000000+0x00D8, "com.apple.keylayout.Norwegian", VK_SEMICOLON);
}
private void verify(char ch, int vk, String layout, int key) {
InputMethodTest.section("Key code test: " + vk + ", char: " + ch);
InputMethodTest.layout(layout);
InputMethodTest.type(key, 0);
InputMethodTest.expect(String.valueOf(ch));
InputMethodTest.expectKeyCode(vk);
InputMethodTest.expectTrue(getExtendedKeyCodeForChar(ch) == vk, "getExtendedKeyCodeForChar(ch) == vk");
}
}

View File

@@ -0,0 +1,66 @@
/*
* 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-221385: Cannot input with half-width punctuation.
* @run shell Runner.sh --fullwidth PinyinFullWidthPunctuationTest
* @requires (jdk.version.major >= 8 & os.family == "mac")
*/
import static java.awt.event.KeyEvent.*;
public class PinyinFullWidthPunctuationTest implements Runnable {
@Override
public void run() {
InputMethodTest.layout("com.apple.inputmethod.SCIM.ITABC");
InputMethodTest.section("comma");
InputMethodTest.type(VK_COMMA, 0);
InputMethodTest.expect("\uff0c");
InputMethodTest.section("period");
InputMethodTest.type(VK_PERIOD, 0);
InputMethodTest.expect("\u3002");
InputMethodTest.section("question mark");
InputMethodTest.type(VK_SLASH, SHIFT_DOWN_MASK);
InputMethodTest.expect("\uff1f");
InputMethodTest.section("semicolon");
InputMethodTest.type(VK_SEMICOLON, 0);
InputMethodTest.expect("\uff1b");
InputMethodTest.section("colon");
InputMethodTest.type(VK_SEMICOLON, SHIFT_DOWN_MASK);
InputMethodTest.expect("\uff1a");
InputMethodTest.section("left square bracket");
InputMethodTest.type(VK_OPEN_BRACKET, 0);
InputMethodTest.expect("\u3010");
InputMethodTest.section("right square bracket");
InputMethodTest.type(VK_CLOSE_BRACKET, 0);
InputMethodTest.expect("\u3011");
}
}

View File

@@ -0,0 +1,66 @@
/*
* 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-221385: Cannot input with half-width punctuation.
* @run shell Runner.sh --halfwidth PinyinHalfWidthPunctuationTest
* @requires (jdk.version.major >= 8 & os.family == "mac")
*/
import static java.awt.event.KeyEvent.*;
public class PinyinHalfWidthPunctuationTest implements Runnable {
@Override
public void run() {
InputMethodTest.layout("com.apple.inputmethod.SCIM.ITABC");
InputMethodTest.section("comma");
InputMethodTest.type(VK_COMMA, 0);
InputMethodTest.expect(",");
InputMethodTest.section("period");
InputMethodTest.type(VK_PERIOD, 0);
InputMethodTest.expect(".");
InputMethodTest.section("question mark");
InputMethodTest.type(VK_SLASH, SHIFT_DOWN_MASK);
InputMethodTest.expect("?");
InputMethodTest.section("semicolon");
InputMethodTest.type(VK_SEMICOLON, 0);
InputMethodTest.expect(";");
InputMethodTest.section("colon");
InputMethodTest.type(VK_SEMICOLON, SHIFT_DOWN_MASK);
InputMethodTest.expect(":");
InputMethodTest.section("left square bracket");
InputMethodTest.type(VK_OPEN_BRACKET, 0);
InputMethodTest.expect("[");
InputMethodTest.section("right square bracket");
InputMethodTest.type(VK_CLOSE_BRACKET, 0);
InputMethodTest.expect("]");
}
}

View File

@@ -0,0 +1,63 @@
/*
* 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-271898: Cannot enter Chinese full-corner single and double quotes (IDEA: macOS Intel version)
* @requires (jdk.version.major >= 8 & os.family == "mac")
* @run shell Runner.sh PinyinQuotesTest
*/
import static java.awt.event.KeyEvent.*;
public class PinyinQuotesTest implements Runnable {
@Override
public void run() {
InputMethodTest.layout("com.apple.inputmethod.SCIM.ITABC");
singleQuotes();
doubleQuotes();
}
private void singleQuotes() {
InputMethodTest.section("Single quotes");
// type the following: ' '
InputMethodTest.type(VK_QUOTE, 0);
InputMethodTest.type(VK_SPACE, 0);
InputMethodTest.type(VK_QUOTE, 0);
InputMethodTest.expect("\u2018 \u2019");
}
private void doubleQuotes() {
InputMethodTest.section("Double quotes");
// type the following: " "
InputMethodTest.type(VK_QUOTE, SHIFT_DOWN_MASK);
InputMethodTest.type(VK_SPACE, 0);
InputMethodTest.type(VK_QUOTE, SHIFT_DOWN_MASK);
InputMethodTest.expect("\u201c \u201d");
}
}

View File

@@ -0,0 +1,75 @@
#!/bin/sh
# 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.
#
[ -z "${TESTSRC}" ] && echo "TESTSRC not set" && exit 1
[ -z "${TESTCLASSES}" ] && echo "TESTCLASSES not set" && exit 1
[ -z "${TESTJAVA}" ] && echo "TESTJAVA not set" && exit 1
cd "${TESTSRC}" || exit 1
"${TESTJAVA}/bin/javac" -d "${TESTCLASSES}" --add-modules java.desktop --add-exports java.desktop/sun.lwawt.macosx=ALL-UNNAMED InputMethodTest.java
half_width_override=
while :; do
case $1 in
--halfwidth)
half_width_override=1
;;
--fullwidth)
half_width_override=0
;;
--)
shift
break
;;
*)
break
;;
esac
shift
done
if [ -n "$half_width_override" ]; then
half_width_old_value=$(defaults read com.apple.inputmethod.CoreChineseEngineFramework usesHalfwidthPunctuation)
defaults write com.apple.inputmethod.CoreChineseEngineFramework usesHalfwidthPunctuation "$half_width_override"
fi
"${TESTJAVA}/bin/java" -cp "${TESTCLASSES}" --add-modules java.desktop --add-exports java.desktop/sun.lwawt.macosx=ALL-UNNAMED InputMethodTest "$1"
exit_code=$?
if [ -n "$half_width_override" ]; then
defaults write com.apple.inputmethod.CoreChineseEngineFramework usesHalfwidthPunctuation "$half_width_old_value"
fi
case $exit_code in
0) echo "PASSED"
;;
*) echo "FAILED"
exit 1
;;
esac
exit 0

View File

@@ -70,13 +70,13 @@ public enum Layout_ABC implements LayoutKey {
// 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_W ('w', '∑', 'W', '„', '\u0017'),
VK_E (KeyChar.ch('e'), KeyChar.dead('´') ,KeyChar.ch('E'), KeyChar.ch('´'), KeyChar.ch('\u0005')),
//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_U (KeyChar.ch('u'), KeyChar.dead('¨'), KeyChar.ch('U'), KeyChar.ch('¨'), KeyChar.ch('\u0015')),
VK_I (KeyChar.ch('i'), KeyChar.dead('ˆ'), KeyChar.ch('I'), KeyChar.ch('ˆ'), KeyChar.ch('\u0009')),
//VK_O ('o', 'ø', 'O', 'Ø'),
//VK_P ('p', 'π', 'P', '∏'),

View File

@@ -400,11 +400,6 @@ public class NationalLayoutTest {
// Get Key object from LayoutKey enum
Key key = layoutKey.getKey();
if (key.isDead() || key.isDead(modifier)) {
// TODO: Disable skipping testing dead keys once they work properly on macOS
continue;
}
// Obtain the key code for the current layout
int keyCode = key.getKeyCode();