mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
JBR-5254: Fix Caps Lock not working properly on certain Chinese IMs
with fix for JBR-5300 Change source code and test files to use GPL license
(cherry picked from commit be64a4f3d0)
This commit is contained in:
@@ -410,6 +410,7 @@ ifeq ($(call isTargetOs, macosx), true)
|
||||
-framework AudioToolbox \
|
||||
-framework Carbon \
|
||||
-framework Cocoa \
|
||||
-framework IOKit \
|
||||
-framework ExceptionHandling \
|
||||
-framework JavaRuntimeSupport \
|
||||
-framework Metal \
|
||||
|
||||
@@ -36,6 +36,8 @@ import java.awt.event.InputEvent;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Translates NSEvents/NPCocoaEvents into AWT events.
|
||||
@@ -55,6 +57,7 @@ final class CPlatformResponder {
|
||||
private int lastDraggedAbsoluteY;
|
||||
private int lastDraggedRelativeX;
|
||||
private int lastDraggedRelativeY;
|
||||
private static final Pattern layoutsNeedingCapsLockFix = Pattern.compile("com\\.apple\\.inputmethod\\.(SCIM|TCIM)\\.(Shuangpin|Pinyin|ITABC)");
|
||||
|
||||
CPlatformResponder(final PlatformEventNotifier eventNotifier,
|
||||
final boolean isNpapiCallback) {
|
||||
@@ -235,14 +238,23 @@ final class CPlatformResponder {
|
||||
}
|
||||
}
|
||||
|
||||
// If Pinyin Simplified input method is selected, CAPS_LOCK key is supposed to switch
|
||||
// If a Chinese input method is selected, CAPS_LOCK key is supposed to switch
|
||||
// input to latin letters.
|
||||
// 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();
|
||||
// This is only necessary for the following Chinese input methods:
|
||||
// com.apple.inputmethod.SCIM.ITABC
|
||||
// com.apple.inputmethod.SCIM.Shuangpin
|
||||
// com.apple.inputmethod.TCIM.Pinyin
|
||||
// com.apple.inputmethod.TCIM.Shuangpin
|
||||
// All the other ones work properly without this fix. Zhuyin (Traditional) for example reports
|
||||
// Bopomofo characters in 'charactersIgnoringModifiers', and latin letters in 'characters'.
|
||||
// This means that applying this fix will actually produce invalid behavior in this IM.
|
||||
// Also see test/jdk/jb/sun/awt/macos/InputMethodTest/PinyinCapsLockTest.java
|
||||
|
||||
if (testChar != KeyEvent.CHAR_UNDEFINED &&
|
||||
lwcToolkit.getLockingKeyState(KeyEvent.VK_CAPS_LOCK) &&
|
||||
Locale.SIMPLIFIED_CHINESE.equals(lwcToolkit.getDefaultKeyboardLocale())) {
|
||||
Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_CAPS_LOCK) &&
|
||||
layoutsNeedingCapsLockFix.matcher(LWCToolkit.getKeyboardLayoutId()).matches()) {
|
||||
testChar = testCharIgnoringModifiers;
|
||||
}
|
||||
|
||||
|
||||
@@ -557,6 +557,8 @@ public final class LWCToolkit extends LWToolkit {
|
||||
|
||||
private native boolean isCapsLockOn();
|
||||
|
||||
private static native boolean setCapsLockState(boolean on);
|
||||
|
||||
/*
|
||||
* NOTE: Among the keys this method is supposed to check,
|
||||
* only Caps Lock works as a true locking key with OS X.
|
||||
@@ -583,6 +585,25 @@ public final class LWCToolkit extends LWToolkit {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLockingKeyState(int keyCode, boolean on) throws UnsupportedOperationException {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.VK_NUM_LOCK:
|
||||
case KeyEvent.VK_SCROLL_LOCK:
|
||||
case KeyEvent.VK_KANA_LOCK:
|
||||
throw new UnsupportedOperationException("Toolkit.setLockingKeyState");
|
||||
|
||||
case KeyEvent.VK_CAPS_LOCK:
|
||||
if (!setCapsLockState(on)) {
|
||||
throw new RuntimeException("failed to set caps lock state");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("invalid key for Toolkit.setLockingKeyState");
|
||||
}
|
||||
}
|
||||
|
||||
//Is it allowed to generate events assigned to extra mouse buttons.
|
||||
//Set to true by default.
|
||||
private static boolean areExtraMouseButtonsEnabled = true;
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
|
||||
#import <Carbon/Carbon.h>
|
||||
|
||||
#include <IOKit/hidsystem/IOHIDShared.h>
|
||||
#include <IOKit/hidsystem/IOHIDParameter.h>
|
||||
|
||||
// SCROLL PHASE STATE
|
||||
#define SCROLL_PHASE_UNSUPPORTED 1
|
||||
#define SCROLL_PHASE_BEGAN 2
|
||||
@@ -1034,4 +1037,34 @@ JNICALL Java_sun_lwawt_macosx_LWCToolkit_disableKeyboardLayoutNative(JNIEnv *env
|
||||
}];
|
||||
JNI_COCOA_EXIT(env);
|
||||
return status == noErr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_LWCToolkit
|
||||
* Method: setCapsLockState
|
||||
* Signature: (Z)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL
|
||||
JNICALL Java_sun_lwawt_macosx_LWCToolkit_setCapsLockState(JNIEnv *env, jclass cls, jboolean on) {
|
||||
__block kern_return_t err = KERN_SUCCESS;
|
||||
JNI_COCOA_ENTER(env);
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^() {
|
||||
io_service_t ioHIDService = IOServiceGetMatchingService(kIOMasterPortDefault,
|
||||
IOServiceMatching(kIOHIDSystemClass));
|
||||
if (!ioHIDService) {
|
||||
err = KERN_FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
io_connect_t ioHIDConnect;
|
||||
err = IOServiceOpen(ioHIDService, mach_task_self(), kIOHIDParamConnectType, &ioHIDConnect);
|
||||
if (err == KERN_SUCCESS) {
|
||||
err = IOHIDSetModifierLockState(ioHIDConnect, kIOHIDCapsLockState, on);
|
||||
IOServiceClose(ioHIDConnect);
|
||||
}
|
||||
|
||||
IOObjectRelease(ioHIDService);
|
||||
}];
|
||||
JNI_COCOA_EXIT(env);
|
||||
return err == KERN_SUCCESS;
|
||||
}
|
||||
@@ -47,9 +47,10 @@ public class InputMethodTest {
|
||||
private enum TestCases {
|
||||
DeadKeysTest (new DeadKeysTest()),
|
||||
KeyCodesTest (new KeyCodesTest()),
|
||||
PinyinQuotesTest (new PinyinQuotesTest()),
|
||||
PinyinCapsLockTest (new PinyinCapsLockTest()),
|
||||
PinyinFullWidthPunctuationTest (new PinyinFullWidthPunctuationTest()),
|
||||
PinyinHalfWidthPunctuationTest (new PinyinHalfWidthPunctuationTest())
|
||||
PinyinHalfWidthPunctuationTest (new PinyinHalfWidthPunctuationTest()),
|
||||
PinyinQuotesTest (new PinyinQuotesTest())
|
||||
;
|
||||
|
||||
private Runnable test;
|
||||
@@ -70,6 +71,7 @@ public class InputMethodTest {
|
||||
runTest(arg);
|
||||
}
|
||||
} finally {
|
||||
setCapsLockState(false);
|
||||
LWCToolkit.switchKeyboardLayout(initialLayout);
|
||||
for (String layoutId : addedLayouts) {
|
||||
try {
|
||||
@@ -121,6 +123,7 @@ public class InputMethodTest {
|
||||
|
||||
private static void runTest(String name) {
|
||||
currentTest = name;
|
||||
setCapsLockState(false);
|
||||
try {
|
||||
TestCases.valueOf(name).run();
|
||||
} catch (Exception e) {
|
||||
@@ -151,6 +154,7 @@ public class InputMethodTest {
|
||||
}
|
||||
|
||||
LWCToolkit.switchKeyboardLayout(name);
|
||||
robot.delay(250);
|
||||
}
|
||||
|
||||
public static void type(int key, int modifiers) {
|
||||
@@ -185,6 +189,11 @@ public class InputMethodTest {
|
||||
}
|
||||
}
|
||||
|
||||
public static void setCapsLockState(boolean desiredState) {
|
||||
LWCToolkit.getDefaultToolkit().setLockingKeyState(KeyEvent.VK_CAPS_LOCK, desiredState);
|
||||
robot.delay(250);
|
||||
}
|
||||
|
||||
public static void expect(String expectedValue) {
|
||||
var actualValue = textArea.getText();
|
||||
if (actualValue.equals(expectedValue)) {
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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-5254: CapsLock and Chinese IMs don't work properly
|
||||
* @run shell Runner.sh PinyinCapsLockTest
|
||||
* @requires (jdk.version.major >= 8 & os.family == "mac")
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static java.awt.event.KeyEvent.*;
|
||||
|
||||
public class PinyinCapsLockTest implements Runnable {
|
||||
private static final List<String> expectLowercase = new ArrayList<>(Arrays.asList(
|
||||
"com.apple.inputmethod.SCIM.ITABC",
|
||||
"com.apple.inputmethod.SCIM.Shuangpin",
|
||||
"com.apple.inputmethod.SCIM.WBH",
|
||||
"com.apple.inputmethod.TYIM.Cangjie",
|
||||
"com.apple.inputmethod.TYIM.Sucheng",
|
||||
"com.apple.inputmethod.TYIM.Stroke",
|
||||
"com.apple.inputmethod.TCIM.Zhuyin",
|
||||
"com.apple.inputmethod.TCIM.Cangjie",
|
||||
"com.apple.inputmethod.TCIM.ZhuyinEten",
|
||||
"com.apple.inputmethod.TCIM.Jianyi",
|
||||
"com.apple.inputmethod.TCIM.Pinyin",
|
||||
"com.apple.inputmethod.TCIM.Shuangpin",
|
||||
"com.apple.inputmethod.TCIM.WBH"
|
||||
));
|
||||
|
||||
// Wubi (Simplified) produces uppercase characters even in native apps.
|
||||
private static final List<String> expectUppercase = new ArrayList<>(Arrays.asList(
|
||||
"com.apple.inputmethod.SCIM.WBX"
|
||||
));
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (String layout : expectLowercase) {
|
||||
testLatinTyping(layout, false);
|
||||
}
|
||||
|
||||
for (String layout : expectUppercase) {
|
||||
testLatinTyping(layout, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void testLatinTyping(String layout, boolean expectUppercase) {
|
||||
InputMethodTest.section(layout);
|
||||
InputMethodTest.layout(layout);
|
||||
InputMethodTest.setCapsLockState(true);
|
||||
InputMethodTest.type(VK_A, 0);
|
||||
InputMethodTest.type(VK_B, 0);
|
||||
InputMethodTest.type(VK_C, 0);
|
||||
InputMethodTest.expect(expectUppercase ? "ABC" : "abc");
|
||||
InputMethodTest.type(VK_ESCAPE, 0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user