1 /* 2 * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.awt.im; 27 28 import java.awt.AWTException; 29 import java.awt.CheckboxMenuItem; 30 import java.awt.Component; 31 import java.awt.Dialog; 32 import java.awt.EventQueue; 33 import java.awt.Frame; 34 import java.awt.PopupMenu; 35 import java.awt.Menu; 36 import java.awt.MenuItem; 37 import java.awt.Toolkit; 38 import sun.awt.AppContext; 39 import java.awt.event.ActionEvent; 40 import java.awt.event.ActionListener; 41 import java.awt.event.InvocationEvent; 42 import java.awt.im.spi.InputMethodDescriptor; 43 import java.lang.reflect.InvocationTargetException; 44 import java.security.AccessController; 45 import java.security.PrivilegedAction; 46 import java.security.PrivilegedActionException; 47 import java.security.PrivilegedExceptionAction; 48 import java.util.Hashtable; 49 import java.util.Iterator; 50 import java.util.Locale; 51 import java.util.ServiceLoader; 52 import java.util.Vector; 53 import java.util.Set; 54 import java.util.prefs.BackingStoreException; 55 import java.util.prefs.Preferences; 56 import sun.awt.InputMethodSupport; 57 import sun.awt.SunToolkit; 58 import sun.misc.ManagedLocalsThread; 59 60 /** 61 * {@code InputMethodManager} is an abstract class that manages the input 62 * method environment of JVM. There is only one {@code InputMethodManager} 63 * instance in JVM that is executed under a separate daemon thread. 64 * {@code InputMethodManager} performs the following: 65 * <UL> 66 * <LI> 67 * Keeps track of the current input context.</LI> 68 * 69 * <LI> 70 * Provides a user interface to switch input methods and notifies the current 71 * input context about changes made from the user interface.</LI> 72 * </UL> 73 * 74 * The mechanism for supporting input method switch is as follows. (Note that 75 * this may change in future releases.) 76 * 77 * <UL> 78 * <LI> 79 * One way is to use platform-dependent window manager's menu (known as the <I>Window 80 * menu </I>in Motif and the <I>System menu</I> or <I>Control menu</I> in 81 * Win32) on each window which is popped up by clicking the left top box of 82 * a window (known as <I>Window menu button</I> in Motif and <I>System menu 83 * button</I> in Win32). This happens to be common in both Motif and Win32.</LI> 84 * 85 * <LI> 86 * When more than one input method descriptor can be found or the only input 87 * method descriptor found supports multiple locales, a menu item 88 * is added to the window (manager) menu. This item label is obtained invoking 89 * {@code getTriggerMenuString()}. If null is returned by this method, it 90 * means that there is only input method or none in the environment. Frame and Dialog 91 * invoke this method.</LI> 92 * 93 * <LI> 94 * This menu item means a trigger switch to the user to pop up a selection 95 * menu.</LI> 96 * 97 * <LI> 98 * When the menu item of the window (manager) menu has been selected by the 99 * user, Frame/Dialog invokes {@code notifyChangeRequest()} to notify 100 * {@code InputMethodManager} that the user wants to switch input methods.</LI> 101 * 102 * <LI> 103 * {@code InputMethodManager} displays a pop-up menu to choose an input method.</LI> 104 * 105 * <LI> 106 * {@code InputMethodManager} notifies the current {@code InputContext} of 107 * the selected {@code InputMethod}.</LI> 108 * </UL> 109 * 110 * <UL> 111 * <LI> 112 * The other way is to use user-defined hot key combination to show the pop-up menu to 113 * choose an input method. This is useful for the platforms which do not provide a 114 * way to add a menu item in the window (manager) menu.</LI> 115 * 116 * <LI> 117 * When the hot key combination is typed by the user, the component which has the input 118 * focus invokes {@code notifyChangeRequestByHotKey()} to notify 119 * {@code InputMethodManager} that the user wants to switch input methods.</LI> 120 * 121 * <LI> 122 * This results in a popup menu and notification to the current input context, 123 * as above.</LI> 124 * </UL> 125 * 126 * @see java.awt.im.spi.InputMethod 127 * @see sun.awt.im.InputContext 128 * @see sun.awt.im.InputMethodAdapter 129 * @author JavaSoft International 130 */ 131 132 public abstract class InputMethodManager { 133 134 /** 135 * InputMethodManager thread name 136 */ 137 private static final String threadName = "AWT-InputMethodManager"; 138 139 /** 140 * Object for global locking 141 */ 142 private static final Object LOCK = new Object(); 143 144 /** 145 * The InputMethodManager instance 146 */ 147 private static InputMethodManager inputMethodManager; 148 149 /** 150 * Returns the instance of InputMethodManager. This method creates 151 * the instance that is unique in the Java VM if it has not been 152 * created yet. 153 * 154 * @return the InputMethodManager instance 155 */ 156 public static final InputMethodManager getInstance() { 157 if (inputMethodManager != null) { 158 return inputMethodManager; 159 } 160 synchronized(LOCK) { 161 if (inputMethodManager == null) { 162 ExecutableInputMethodManager imm = new ExecutableInputMethodManager(); 163 164 // Initialize the input method manager and start a 165 // daemon thread if the user has multiple input methods 166 // to choose from. Otherwise, just keep the instance. 167 if (imm.hasMultipleInputMethods()) { 168 imm.initialize(); 169 Thread immThread = new ManagedLocalsThread(imm, threadName); 170 immThread.setDaemon(true); 171 immThread.setPriority(Thread.NORM_PRIORITY + 1); 172 immThread.start(); 173 } 174 inputMethodManager = imm; 175 } 176 } 177 return inputMethodManager; 178 } 179 180 /** 181 * Gets a string for the trigger menu item that should be added to 182 * the window manager menu. If no need to display the trigger menu 183 * item, null is returned. 184 */ 185 public abstract String getTriggerMenuString(); 186 187 /** 188 * Notifies InputMethodManager that input method change has been 189 * requested by the user. This notification triggers a popup menu 190 * for user selection. 191 * 192 * @param comp Component that has accepted the change 193 * request. This component has to be a Frame or Dialog. 194 */ 195 public abstract void notifyChangeRequest(Component comp); 196 197 /** 198 * Notifies InputMethodManager that input method change has been 199 * requested by the user using the hot key combination. This 200 * notification triggers a popup menu for user selection. 201 * 202 * @param comp Component that has accepted the change 203 * request. This component has the input focus. 204 */ 205 public abstract void notifyChangeRequestByHotKey(Component comp); 206 207 /** 208 * Sets the current input context so that it will be notified 209 * of input method changes initiated from the user interface. 210 * Set to real input context when activating; to null when 211 * deactivating. 212 */ 213 abstract void setInputContext(InputContext inputContext); 214 215 /** 216 * Tries to find an input method locator for the given locale. 217 * Returns null if no available input method locator supports 218 * the locale. 219 */ 220 abstract InputMethodLocator findInputMethod(Locale forLocale); 221 222 /** 223 * Gets the default keyboard locale of the underlying operating system. 224 */ 225 abstract Locale getDefaultKeyboardLocale(); 226 227 /** 228 * Returns whether multiple input methods are available or not 229 */ 230 abstract boolean hasMultipleInputMethods(); 231 232 }