mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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, ©);
|
||||
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);
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
jobject fInputMethodLOCKABLE;
|
||||
BOOL fKeyEventsNeeded;
|
||||
BOOL fProcessingKeystroke;
|
||||
BOOL fComplexInputNeeded;
|
||||
|
||||
BOOL fEnablePressAndHold;
|
||||
BOOL fInPressAndHold;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
@@ -23,5 +23,5 @@ public class TouchEvent {
|
||||
|
||||
@Native
|
||||
public final static boolean defaultTouchHandling = "true".equalsIgnoreCase(
|
||||
Util.getProperty(defaultTouchHandlingOption, "false"));
|
||||
System.getProperty(defaultTouchHandlingOption, "false"));
|
||||
}
|
||||
|
||||
53
test/jdk/jb/sun/awt/macos/InputMethodTest/DeadKeysTest.java
Normal file
53
test/jdk/jb/sun/awt/macos/InputMethodTest/DeadKeysTest.java
Normal 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");
|
||||
}
|
||||
}
|
||||
185
test/jdk/jb/sun/awt/macos/InputMethodTest/InputMethodTest.java
Normal file
185
test/jdk/jb/sun/awt/macos/InputMethodTest/InputMethodTest.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
84
test/jdk/jb/sun/awt/macos/InputMethodTest/KeyCodesTest.java
Normal file
84
test/jdk/jb/sun/awt/macos/InputMethodTest/KeyCodesTest.java
Normal 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");
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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("]");
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
75
test/jdk/jb/sun/awt/macos/InputMethodTest/Runner.sh
Normal file
75
test/jdk/jb/sun/awt/macos/InputMethodTest/Runner.sh
Normal 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
|
||||
@@ -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', '∏'),
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user