JBR-6704: Fix extra IME events when a ctrl shortcut causes window focus switch [macOS]

This commit is contained in:
Nikita Tsarev
2024-02-14 13:35:21 +01:00
parent 2aa3828f59
commit 70d60692f0
3 changed files with 104 additions and 3 deletions

View File

@@ -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);

View File

@@ -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();
}
}

View File

@@ -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);
}
}