mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
JBR-6704: Fix extra IME events when a ctrl shortcut causes window focus switch [macOS]
This commit is contained in:
@@ -45,6 +45,9 @@
|
||||
// keyboard layout
|
||||
static NSString *kbdLayout;
|
||||
|
||||
// workaround for JBR-6704
|
||||
static unichar lastCtrlCombo;
|
||||
|
||||
@interface AWTView()
|
||||
@property (retain) CDropTarget *_dropTarget;
|
||||
@property (retain) CDragSource *_dragSource;
|
||||
@@ -87,6 +90,7 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, i
|
||||
fInputMethodLOCKABLE = NULL;
|
||||
fKeyEventsNeeded = NO;
|
||||
fProcessingKeystroke = NO;
|
||||
lastCtrlCombo = 0;
|
||||
|
||||
fEnablePressAndHold = shouldUsePressAndHold();
|
||||
fInPressAndHold = NO;
|
||||
@@ -365,6 +369,12 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
|
||||
|
||||
NSString *eventCharacters = [event characters];
|
||||
|
||||
if (([event modifierFlags] & NSControlKeyMask) && [eventCharacters length] == 1) {
|
||||
lastCtrlCombo = [eventCharacters characterAtIndex:0];
|
||||
} else {
|
||||
lastCtrlCombo = 0;
|
||||
}
|
||||
|
||||
// Allow TSM to look at the event and potentially send back NSTextInputClient messages.
|
||||
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
|
||||
|
||||
@@ -1140,6 +1150,14 @@ static jclass jc_CInputMethod = NULL;
|
||||
fprintf(stderr, "AWTView InputMethod Selector Called : [insertText]: %s\n", [aString UTF8String]);
|
||||
#endif // IM_DEBUG
|
||||
|
||||
NSMutableString * useString = [self parseString:aString];
|
||||
|
||||
// See JBR-6704
|
||||
if (lastCtrlCombo && !fProcessingKeystroke && [useString length] == 1 && [useString characterAtIndex:0] == lastCtrlCombo) {
|
||||
lastCtrlCombo = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fInputMethodLOCKABLE == NULL) {
|
||||
return;
|
||||
}
|
||||
@@ -1152,8 +1170,6 @@ static jclass jc_CInputMethod = NULL;
|
||||
// text, or 'text in progress'. We also need to send the event if we get an insert text out of the blue!
|
||||
// (i.e., when the user uses the Character palette or Inkwell), or when the string to insert is a complex
|
||||
// Unicode value.
|
||||
|
||||
NSMutableString * useString = [self parseString:aString];
|
||||
BOOL usingComplexIM = [self hasMarkedText] || !fProcessingKeystroke;
|
||||
|
||||
#ifdef IM_DEBUG
|
||||
@@ -1163,6 +1179,7 @@ static jclass jc_CInputMethod = NULL;
|
||||
NSLog(@"insertText kbdlayout %@ ",(NSString *)kbdLayout);
|
||||
|
||||
NSLog(@"utf8Length %lu utf16Length %lu", (unsigned long)utf8Length, (unsigned long)utf16Length);
|
||||
NSLog(@"hasMarkedText: %s, fProcessingKeyStroke: %s", [self hasMarkedText] ? "YES" : "NO", fProcessingKeystroke ? "YES" : "NO");
|
||||
#endif // IM_DEBUG
|
||||
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
@@ -1178,7 +1195,7 @@ static jclass jc_CInputMethod = NULL;
|
||||
|
||||
if (usingComplexIM) {
|
||||
DECLARE_METHOD(jm_insertText, jc_CInputMethod, "insertText", "(Ljava/lang/String;)V");
|
||||
jstring insertedText = NSStringToJavaString(env, useString);
|
||||
jstring insertedText = NSStringToJavaString(env, useString);
|
||||
(*env)->CallVoidMethod(env, fInputMethodLOCKABLE, jm_insertText, insertedText);
|
||||
CHECK_EXCEPTION();
|
||||
(*env)->DeleteLocalRef(env, insertedText);
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2024 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-6704 Extra IME event fired when pressing a keystroke containing Ctrl and focus moving to a different window
|
||||
* @modules java.desktop/sun.lwawt.macosx
|
||||
* @run main InputMethodTest CtrlShortcutNewWindowTest
|
||||
* @requires (jdk.version.major >= 8 & os.family == "mac")
|
||||
*/
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
import static java.awt.event.KeyEvent.*;
|
||||
|
||||
public class CtrlShortcutNewWindowTest implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
var frame = new JFrame();
|
||||
frame.setSize(300, 300);
|
||||
frame.setLocation(100, 100);
|
||||
JTextField textField = new JTextField();
|
||||
frame.add(textField);
|
||||
textField.requestFocusInWindow();
|
||||
|
||||
final boolean[] keyPressed = {false};
|
||||
|
||||
InputMethodTest.textArea.addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == VK_BACK_QUOTE && (e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0) {
|
||||
keyPressed[0] = true;
|
||||
frame.setVisible(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
InputMethodTest.section("Ctrl+Backtick");
|
||||
InputMethodTest.layout("com.apple.keylayout.ABC");
|
||||
InputMethodTest.type(VK_BACK_QUOTE, CTRL_DOWN_MASK);
|
||||
InputMethodTest.delay(500);
|
||||
|
||||
if (!keyPressed[0]) {
|
||||
InputMethodTest.fail("Ctrl+Backtick key combination not detected");
|
||||
}
|
||||
|
||||
if (!textField.getText().isEmpty()) {
|
||||
InputMethodTest.fail("Extra characters in the text field");
|
||||
}
|
||||
|
||||
frame.setVisible(false);
|
||||
frame.dispose();
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ public class InputMethodTest {
|
||||
private static final List<KeyEvent> triggeredEvents = new ArrayList<>();
|
||||
|
||||
private enum TestCases {
|
||||
CtrlShortcutNewWindowTest (new CtrlShortcutNewWindowTest()),
|
||||
DeadKeysTest (new DeadKeysTest()),
|
||||
FocusMoveUncommitedCharactersTest (new FocusMoveUncommitedCharactersTest()),
|
||||
KeyCodesTest (new KeyCodesTest()),
|
||||
@@ -332,4 +333,8 @@ public class InputMethodTest {
|
||||
public static void fail(String comment) {
|
||||
expectTrue(false, comment);
|
||||
}
|
||||
|
||||
public static void delay(int millis) {
|
||||
robot.delay(millis);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user