From d517dc81fac9ceef096e0a9a5d1366d6a763867c Mon Sep 17 00:00:00 2001 From: ssreedharan Date: Thu, 12 Oct 2017 10:16:05 -0400 Subject: [PATCH] 8180370: Characters are skipped on input of Korean text on OS X Reviewed-by: serb --- src/macosx/native/sun/awt/AWTView.m | 9 +- .../MissingCharsKorean.java | 331 ++++++++++++++++++ 2 files changed, 339 insertions(+), 1 deletion(-) create mode 100644 test/javax/swing/JTextField/MissingCharsKorean/MissingCharsKorean.java diff --git a/src/macosx/native/sun/awt/AWTView.m b/src/macosx/native/sun/awt/AWTView.m index 26f62698a..b8220f264 100644 --- a/src/macosx/native/sun/awt/AWTView.m +++ b/src/macosx/native/sun/awt/AWTView.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -980,6 +980,13 @@ JNF_CLASS_CACHE(jc_CInputMethod, "sun/lwawt/macosx/CInputMethod"); // We also don't want to send the character that triggered the insertText, usually a return. [3337563] fKeyEventsNeeded = NO; } + else { + // Need to set back the fKeyEventsNeeded flag so that the string following the + // marked text is not ignored by keyDown + if (utf16Length > 0 || utf8Length > 0) { + fKeyEventsNeeded = YES; + } + } fPAHNeedsToSelect = NO; diff --git a/test/javax/swing/JTextField/MissingCharsKorean/MissingCharsKorean.java b/test/javax/swing/JTextField/MissingCharsKorean/MissingCharsKorean.java new file mode 100644 index 000000000..bffe07a96 --- /dev/null +++ b/test/javax/swing/JTextField/MissingCharsKorean/MissingCharsKorean.java @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 + * @bug 8180370 + * @summary Checks whether non-alpha chars are skipped while entering KoreanText + * @requires (os.family == "mac") + * @run main/manual MissingCharsKorean + */ + +/** + * This test requires a manual intervention as the keyboard layout has to be + * changed to 2-set Korean. Once the keyboard layout has been selected, click on + * Start Test to start the automated tests. Along with testing for non-alpha + * chars, this test also ensures that the MarkedText property is not broken by + * running cases where different glyphs are combined and also cases where + * combined glyphs are broken. + */ + +import java.awt.AWTException; +import java.awt.Font; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Robot; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; +import java.awt.event.KeyEvent; +import java.util.concurrent.CountDownLatch; +import javax.swing.JLabel; +import javax.swing.JTextField; + +public class MissingCharsKorean { + private static boolean testPassed = false; + private static boolean startTest = false; + private static int expectedResults[] = null; + private static int inKeyCodes[][] = null; + + private static JFrame frame = null; + private static JLabel lblTestStatus = null; + private static JTextField textFieldMain = null; + private static String testResult; + + private static final CountDownLatch testStartLatch = new CountDownLatch(1); + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> { + setupUI(); + }); + + testStartLatch.await(); + + if (startTest) { + glyphTest(); + + frame.dispose(); + + if (testPassed) { + System.out.println(testResult); + } else { + throw new RuntimeException("Korean text missing characters : " + + testResult); + } + } else { + throw new RuntimeException("User has not executed the test"); + } + } + + private static void setupUI() { + String description = " 1. Go to \"System Preferences -> Keyboard -> " + + "Input Sources\" and add \"2-Set Korean\"" + + " from Korean language group \n" + + " 2. Set current IM to \"2-Set Korean\" \n" + + " 3. Try typing in the text field to ensure" + + " that Korean keyboard has been successfully" + + " selected \n" + + " 4. Now click on \"Start Test\" button \n"; + String title = "Missing Characters Korean Test (Mac OS)"; + + frame = new JFrame(title); + + JPanel mainPanel = new JPanel(new BorderLayout()); + + JPanel textEditPanel = new JPanel(new FlowLayout()); + + textFieldMain = new JTextField(20); + Font font = new Font("Source Han Serif K", Font.BOLD,12); + textFieldMain.setFont(font); + + textEditPanel.add(textFieldMain); + + mainPanel.add(textEditPanel, BorderLayout.CENTER); + + JTextArea textArea = new JTextArea(description); + textArea.setEditable(false); + final JButton btnStartTest = new JButton("Start Test"); + final JButton btnCancelTest = new JButton("Cancel Test"); + + btnStartTest.addActionListener((e) -> { + btnStartTest.setEnabled(false); + btnCancelTest.setEnabled(false); + startTest = true; + testStartLatch.countDown(); + }); + + btnCancelTest.addActionListener((e) -> { + frame.dispose(); + testStartLatch.countDown(); + }); + mainPanel.add(textArea, BorderLayout.NORTH); + + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(btnStartTest); + buttonPanel.add(btnCancelTest); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + + lblTestStatus = new JLabel(""); + lblTestStatus.setMinimumSize(new Dimension(150, 20)); + lblTestStatus.setPreferredSize(new Dimension(150, 20)); + lblTestStatus.setVisible(true); + textEditPanel.add(lblTestStatus); + + frame.add(mainPanel); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frame.pack(); + frame.setLocationRelativeTo(null); + + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + testStartLatch.countDown(); + } + @Override + public void windowOpened( WindowEvent e ){ + textFieldMain.requestFocusInWindow(); + } + }); + + frame.setVisible(true); + } + + private static void glyphTest() { + try { + Robot robotKeySimulator = new Robot(); + performTasks(robotKeySimulator); + } catch (AWTException e) { + System.err.print("Creation Of Robot Failed : " + e.getMessage()); + testPassed = false; + } + } + + public static void performTasks(Robot robotForKeyInput) { + int taskCount = 0; + + lblTestStatus.setText("Running Tests.."); + robotForKeyInput.setAutoDelay(500); + + while (setKeyInput(taskCount)) { + textFieldMain.setText(""); + textFieldMain.requestFocusInWindow(); + enterInput(robotForKeyInput, inKeyCodes); + taskCount++; + + try { + SwingUtilities.invokeAndWait(() -> { + validateInput(); + }); + } catch (Exception e) { + System.err.print("validateInput Failed : " + e.getMessage()); + testPassed = false; + break; + } + + if (!testPassed) { + break; + } + setTaskStatus(false, taskCount); + } + setTaskStatus(true, taskCount); + } + + private static boolean setKeyInput(int iCount) { + boolean inputSet = true; + + switch(iCount) { + case 0: + // Input Korean q (#12610) /(#47) + expectedResults = new int[]{ 12610, 47 }; + inKeyCodes = new int[][] { {KeyEvent.VK_Q}, + {KeyEvent.VK_SLASH} + }; + break; + + case 1: + // Input Korean q (#12610) /(#47) gh (#54840) \(#92) + expectedResults = new int[]{ 12610, 47, 54840, 92 }; + inKeyCodes = new int[][] { {KeyEvent.VK_Q}, + {KeyEvent.VK_SLASH}, + {KeyEvent.VK_G}, + {KeyEvent.VK_H}, + {KeyEvent.VK_BACK_SLASH} + }; + break; + + case 2: + // Input Korean q (#12610) /(#47) ghq (#54857) \(#92) + expectedResults = new int[]{ 12610, 47, 54857, 92 }; + inKeyCodes = new int[][] { {KeyEvent.VK_Q}, + {KeyEvent.VK_SLASH}, + {KeyEvent.VK_G}, + {KeyEvent.VK_H}, + {KeyEvent.VK_Q}, + {KeyEvent.VK_BACK_SLASH} + }; + break; + + case 3: + // Input Korean q (#12610) /(#47) gh (#54840) \(#92) + expectedResults = new int[]{ 12610, 47, 54840, 92 }; + inKeyCodes = new int[][] { {KeyEvent.VK_Q}, + {KeyEvent.VK_SLASH}, + {KeyEvent.VK_G}, + {KeyEvent.VK_H}, + {KeyEvent.VK_Q}, + {KeyEvent.VK_BACK_SPACE}, + {KeyEvent.VK_BACK_SLASH} + }; + break; + + case 4: + // Input Korean q (#12610) /(#47) g (#12622) \(#92) + expectedResults = new int[]{ 12610, 47, 12622, 92 }; + inKeyCodes = new int[][] { {KeyEvent.VK_Q}, + {KeyEvent.VK_SLASH}, + {KeyEvent.VK_G}, + {KeyEvent.VK_H}, + {KeyEvent.VK_Q}, + {KeyEvent.VK_BACK_SPACE}, + {KeyEvent.VK_BACK_SPACE}, + {KeyEvent.VK_BACK_SLASH} + }; + break; + + default: + inputSet = false; + break; + } + + return inputSet; + } + + private static void enterInput(Robot robotKeyInput, int keyInputs[][]) { + for (int i = 0; i < keyInputs.length; i++) { + String strKeyInput = "KeyPress=>"; + final int noOfKeyInputs = keyInputs[i].length; + for (int j = 0; j < noOfKeyInputs; j++) { + robotKeyInput.keyPress(keyInputs[i][j]); + strKeyInput += (Integer.toHexString(keyInputs[i][j])) + ":"; + } + + strKeyInput += "KeyRelease=>"; + for (int j = noOfKeyInputs - 1; j >= 0; j--) { + robotKeyInput.keyRelease(keyInputs[i][j]); + strKeyInput += (Integer.toHexString(keyInputs[i][j])) + ":"; + } + System.out.println(strKeyInput); + } + } + + private static void validateInput() { + testPassed = false; + + if (expectedResults != null) { + String strCurr = textFieldMain.getText(); + if (expectedResults.length == strCurr.length()) { + testPassed = true; + + for (int i = 0; i < strCurr.length(); i++) { + final int charActual = strCurr.charAt(i); + if (charActual != expectedResults[i]) { + System.err.println("<" + i + "> Actual = " + charActual + + " Expected = " + expectedResults[i]); + testPassed = false; + break; + } + } + } + } + } + + public static void setTaskStatus(boolean allTasksPerformed, int taskCount) { + if (testPassed) { + if (allTasksPerformed) { + testResult = "All Tests Passed"; + } else { + testResult = "Test " + Integer.toString(taskCount) + + " Passed"; + } + } else { + testResult = "Test " + Integer.toString(taskCount) + + " Failed"; + } + lblTestStatus.setText(testResult); + } +} -- GitLab