|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.awt.im; |
|
|
|
import java.awt.AWTEvent; |
|
import java.awt.AWTKeyStroke; |
|
import java.awt.Component; |
|
import java.awt.EventQueue; |
|
import java.awt.Frame; |
|
import java.awt.Rectangle; |
|
import java.awt.Toolkit; |
|
import java.awt.Window; |
|
import java.awt.event.ComponentEvent; |
|
import java.awt.event.ComponentListener; |
|
import java.awt.event.FocusEvent; |
|
import java.awt.event.InputEvent; |
|
import java.awt.event.InputMethodEvent; |
|
import java.awt.event.KeyEvent; |
|
import java.awt.event.WindowEvent; |
|
import java.awt.event.WindowListener; |
|
import java.awt.im.InputMethodRequests; |
|
import java.awt.im.spi.InputMethod; |
|
import java.lang.Character.Subset; |
|
import java.security.AccessController; |
|
import java.security.PrivilegedAction; |
|
import java.text.MessageFormat; |
|
import java.util.HashMap; |
|
import java.util.Iterator; |
|
import java.util.Locale; |
|
import java.util.prefs.BackingStoreException; |
|
import java.util.prefs.Preferences; |
|
import sun.util.logging.PlatformLogger; |
|
import sun.awt.SunToolkit; |
|
|
|
/** |
|
* This InputContext class contains parts of the implementation of |
|
* java.text.im.InputContext. These parts have been moved |
|
* here to avoid exposing protected members that are needed by the |
|
* subclass InputMethodContext. |
|
* |
|
* @see java.awt.im.InputContext |
|
* @author JavaSoft Asia/Pacific |
|
*/ |
|
|
|
public class InputContext extends java.awt.im.InputContext |
|
implements ComponentListener, WindowListener { |
|
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.im.InputContext"); |
|
// The current input method is represented by two objects: |
|
// a locator is used to keep information about the selected |
|
// input method and locale until we actually need a real input |
|
// method; only then the input method itself is created. |
|
// Once there is an input method, the input method's locale |
|
|
|
private InputMethodLocator inputMethodLocator; |
|
private InputMethod inputMethod; |
|
private boolean inputMethodCreationFailed; |
|
|
|
|
|
private HashMap<InputMethodLocator, InputMethod> usedInputMethods; |
|
|
|
// the current client component is kept until the user focusses on a different |
|
// client component served by the same input context. When that happens, we call |
|
|
|
private Component currentClientComponent; |
|
private Component awtFocussedComponent; |
|
private boolean isInputMethodActive; |
|
private Subset[] characterSubsets = null; |
|
|
|
|
|
private boolean compositionAreaHidden = false; |
|
|
|
|
|
private static InputContext inputMethodWindowContext; |
|
|
|
// Previously active input method to decide whether we need to call |
|
|
|
private static InputMethod previousInputMethod = null; |
|
|
|
|
|
private boolean clientWindowNotificationEnabled = false; |
|
|
|
private Window clientWindowListened; |
|
|
|
private Rectangle clientWindowLocation = null; |
|
|
|
private HashMap<InputMethod, Boolean> perInputMethodState; |
|
|
|
|
|
private static AWTKeyStroke inputMethodSelectionKey; |
|
private static boolean inputMethodSelectionKeyInitialized = false; |
|
private static final String inputMethodSelectionKeyPath = "/java/awt/im/selectionKey"; |
|
private static final String inputMethodSelectionKeyCodeName = "keyCode"; |
|
private static final String inputMethodSelectionKeyModifiersName = "modifiers"; |
|
|
|
|
|
|
|
*/ |
|
protected InputContext() { |
|
InputMethodManager imm = InputMethodManager.getInstance(); |
|
synchronized (InputContext.class) { |
|
if (!inputMethodSelectionKeyInitialized) { |
|
inputMethodSelectionKeyInitialized = true; |
|
if (imm.hasMultipleInputMethods()) { |
|
initializeInputMethodSelectionKey(); |
|
} |
|
} |
|
} |
|
selectInputMethod(imm.getDefaultKeyboardLocale()); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public synchronized boolean selectInputMethod(Locale locale) { |
|
if (locale == null) { |
|
throw new NullPointerException(); |
|
} |
|
|
|
|
|
if (inputMethod != null) { |
|
if (inputMethod.setLocale(locale)) { |
|
return true; |
|
} |
|
} else if (inputMethodLocator != null) { |
|
// This is not 100% correct, since the input method |
|
// may support the locale without advertising it. |
|
// But before we try instantiations and setLocale, |
|
|
|
if (inputMethodLocator.isLocaleAvailable(locale)) { |
|
inputMethodLocator = inputMethodLocator.deriveLocator(locale); |
|
return true; |
|
} |
|
} |
|
|
|
|
|
InputMethodLocator newLocator = InputMethodManager.getInstance().findInputMethod(locale); |
|
if (newLocator != null) { |
|
changeInputMethod(newLocator); |
|
return true; |
|
} |
|
|
|
// make one last desperate effort with the current input method |
|
|
|
if (inputMethod == null && inputMethodLocator != null) { |
|
inputMethod = getInputMethod(); |
|
if (inputMethod != null) { |
|
return inputMethod.setLocale(locale); |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public Locale getLocale() { |
|
if (inputMethod != null) { |
|
return inputMethod.getLocale(); |
|
} else if (inputMethodLocator != null) { |
|
return inputMethodLocator.getLocale(); |
|
} else { |
|
return null; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void setCharacterSubsets(Subset[] subsets) { |
|
if (subsets == null) { |
|
characterSubsets = null; |
|
} else { |
|
characterSubsets = new Subset[subsets.length]; |
|
System.arraycopy(subsets, 0, |
|
characterSubsets, 0, characterSubsets.length); |
|
} |
|
if (inputMethod != null) { |
|
inputMethod.setCharacterSubsets(subsets); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public synchronized void reconvert() { |
|
InputMethod inputMethod = getInputMethod(); |
|
if (inputMethod == null) { |
|
throw new UnsupportedOperationException(); |
|
} |
|
inputMethod.reconvert(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@SuppressWarnings("fallthrough") |
|
public void dispatchEvent(AWTEvent event) { |
|
|
|
if (event instanceof InputMethodEvent) { |
|
return; |
|
} |
|
|
|
// Ignore focus events that relate to the InputMethodWindow of this context. |
|
|
|
if (event instanceof FocusEvent) { |
|
Component opposite = ((FocusEvent)event).getOppositeComponent(); |
|
if ((opposite != null) && |
|
(getComponentWindow(opposite) instanceof InputMethodWindow) && |
|
(opposite.getInputContext() == this)) { |
|
return; |
|
} |
|
} |
|
|
|
InputMethod inputMethod = getInputMethod(); |
|
int id = event.getID(); |
|
|
|
switch (id) { |
|
case FocusEvent.FOCUS_GAINED: |
|
focusGained((Component) event.getSource()); |
|
break; |
|
|
|
case FocusEvent.FOCUS_LOST: |
|
focusLost((Component) event.getSource(), ((FocusEvent) event).isTemporary()); |
|
break; |
|
|
|
case KeyEvent.KEY_PRESSED: |
|
if (checkInputMethodSelectionKey((KeyEvent)event)) { |
|
|
|
InputMethodManager.getInstance().notifyChangeRequestByHotKey((Component)event.getSource()); |
|
break; |
|
} |
|
|
|
// fall through |
|
|
|
default: |
|
if ((inputMethod != null) && (event instanceof InputEvent)) { |
|
inputMethod.dispatchEvent(event); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void focusGained(Component source) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
synchronized (source.getTreeLock()) { |
|
synchronized (this) { |
|
if ("sun.awt.im.CompositionArea".equals(source.getClass().getName())) { |
|
// no special handling for this one |
|
} else if (getComponentWindow(source) instanceof InputMethodWindow) { |
|
// no special handling for this one either |
|
} else { |
|
if (!source.isDisplayable()) { |
|
|
|
return; |
|
} |
|
|
|
// Focus went to a real client component. |
|
// Check whether we're switching between client components |
|
// that share an input context. We can't do that earlier |
|
// than here because we don't want to end composition |
|
|
|
if (inputMethod != null) { |
|
if (currentClientComponent != null && currentClientComponent != source) { |
|
if (!isInputMethodActive) { |
|
activateInputMethod(false); |
|
} |
|
endComposition(); |
|
deactivateInputMethod(false); |
|
} |
|
} |
|
|
|
currentClientComponent = source; |
|
} |
|
|
|
awtFocussedComponent = source; |
|
if (inputMethod instanceof InputMethodAdapter) { |
|
((InputMethodAdapter) inputMethod).setAWTFocussedComponent(source); |
|
} |
|
|
|
// it's possible that the input method is still active because |
|
// we suppressed a deactivate cause by an input method window |
|
|
|
if (!isInputMethodActive) { |
|
activateInputMethod(true); |
|
} |
|
|
|
|
|
// If the client component is an active client with the below-the-spot |
|
|
|
InputMethodContext inputContext = ((InputMethodContext)this); |
|
if (!inputContext.isCompositionAreaVisible()) { |
|
InputMethodRequests req = source.getInputMethodRequests(); |
|
if (req != null && inputContext.useBelowTheSpotInput()) { |
|
inputContext.setCompositionAreaUndecorated(true); |
|
} else { |
|
inputContext.setCompositionAreaUndecorated(false); |
|
} |
|
} |
|
// restores the composition area if it was set to invisible |
|
|
|
if (compositionAreaHidden == true) { |
|
((InputMethodContext)this).setCompositionAreaVisible(true); |
|
compositionAreaHidden = false; |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void activateInputMethod(boolean updateCompositionArea) { |
|
// call hideWindows() if this input context uses a different |
|
|
|
if (inputMethodWindowContext != null && inputMethodWindowContext != this && |
|
inputMethodWindowContext.inputMethodLocator != null && |
|
!inputMethodWindowContext.inputMethodLocator.sameInputMethod(inputMethodLocator) && |
|
inputMethodWindowContext.inputMethod != null) { |
|
inputMethodWindowContext.inputMethod.hideWindows(); |
|
} |
|
inputMethodWindowContext = this; |
|
|
|
if (inputMethod != null) { |
|
if (previousInputMethod != inputMethod && |
|
previousInputMethod instanceof InputMethodAdapter) { |
|
// let the host adapter pass through the input events for the |
|
|
|
((InputMethodAdapter) previousInputMethod).stopListening(); |
|
} |
|
previousInputMethod = null; |
|
|
|
if (log.isLoggable(PlatformLogger.Level.FINE)) { |
|
log.fine("Current client component " + currentClientComponent); |
|
} |
|
if (inputMethod instanceof InputMethodAdapter) { |
|
((InputMethodAdapter) inputMethod).setClientComponent(currentClientComponent); |
|
} |
|
inputMethod.activate(); |
|
isInputMethodActive = true; |
|
|
|
if (perInputMethodState != null) { |
|
Boolean state = perInputMethodState.remove(inputMethod); |
|
if (state != null) { |
|
clientWindowNotificationEnabled = state.booleanValue(); |
|
} |
|
} |
|
if (clientWindowNotificationEnabled) { |
|
if (!addedClientWindowListeners()) { |
|
addClientWindowListeners(); |
|
} |
|
synchronized(this) { |
|
if (clientWindowListened != null) { |
|
notifyClientWindowChange(clientWindowListened); |
|
} |
|
} |
|
} else { |
|
if (addedClientWindowListeners()) { |
|
removeClientWindowListeners(); |
|
} |
|
} |
|
} |
|
InputMethodManager.getInstance().setInputContext(this); |
|
|
|
((InputMethodContext) this).grabCompositionArea(updateCompositionArea); |
|
} |
|
|
|
static Window getComponentWindow(Component component) { |
|
while (true) { |
|
if (component == null) { |
|
return null; |
|
} else if (component instanceof Window) { |
|
return (Window) component; |
|
} else { |
|
component = component.getParent(); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void focusLost(Component source, boolean isTemporary) { |
|
|
|
|
|
synchronized (source.getTreeLock()) { |
|
synchronized (this) { |
|
|
|
// We need to suppress deactivation if removeNotify has been called earlier. |
|
|
|
if (isInputMethodActive) { |
|
deactivateInputMethod(isTemporary); |
|
} |
|
|
|
awtFocussedComponent = null; |
|
if (inputMethod instanceof InputMethodAdapter) { |
|
((InputMethodAdapter) inputMethod).setAWTFocussedComponent(null); |
|
} |
|
|
|
|
|
InputMethodContext inputContext = ((InputMethodContext)this); |
|
if (inputContext.isCompositionAreaVisible()) { |
|
inputContext.setCompositionAreaVisible(false); |
|
compositionAreaHidden = true; |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private boolean checkInputMethodSelectionKey(KeyEvent event) { |
|
if (inputMethodSelectionKey != null) { |
|
AWTKeyStroke aKeyStroke = AWTKeyStroke.getAWTKeyStrokeForEvent(event); |
|
return inputMethodSelectionKey.equals(aKeyStroke); |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
private void deactivateInputMethod(boolean isTemporary) { |
|
InputMethodManager.getInstance().setInputContext(null); |
|
if (inputMethod != null) { |
|
isInputMethodActive = false; |
|
inputMethod.deactivate(isTemporary); |
|
previousInputMethod = inputMethod; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
synchronized void changeInputMethod(InputMethodLocator newLocator) { |
|
// If we don't have a locator yet, this must be a new input context. |
|
// If we created a new input method here, we might get into an |
|
// infinite loop: create input method -> create some input method window -> |
|
// create new input context -> add input context to input method manager's context list -> |
|
// call changeInputMethod on it. |
|
|
|
if (inputMethodLocator == null) { |
|
inputMethodLocator = newLocator; |
|
inputMethodCreationFailed = false; |
|
return; |
|
} |
|
|
|
// If the same input method is specified, just keep it. |
|
|
|
if (inputMethodLocator.sameInputMethod(newLocator)) { |
|
Locale newLocale = newLocator.getLocale(); |
|
if (newLocale != null && inputMethodLocator.getLocale() != newLocale) { |
|
if (inputMethod != null) { |
|
inputMethod.setLocale(newLocale); |
|
} |
|
inputMethodLocator = newLocator; |
|
} |
|
return; |
|
} |
|
|
|
|
|
Locale savedLocale = inputMethodLocator.getLocale(); |
|
boolean wasInputMethodActive = isInputMethodActive; |
|
boolean wasCompositionEnabledSupported = false; |
|
boolean wasCompositionEnabled = false; |
|
if (inputMethod != null) { |
|
try { |
|
wasCompositionEnabled = inputMethod.isCompositionEnabled(); |
|
wasCompositionEnabledSupported = true; |
|
} catch (UnsupportedOperationException e) { } |
|
|
|
if (currentClientComponent != null) { |
|
if (!isInputMethodActive) { |
|
activateInputMethod(false); |
|
} |
|
endComposition(); |
|
deactivateInputMethod(false); |
|
if (inputMethod instanceof InputMethodAdapter) { |
|
((InputMethodAdapter) inputMethod).setClientComponent(null); |
|
} |
|
} |
|
savedLocale = inputMethod.getLocale(); |
|
|
|
|
|
if (usedInputMethods == null) { |
|
usedInputMethods = new HashMap<>(5); |
|
} |
|
if (perInputMethodState == null) { |
|
perInputMethodState = new HashMap<>(5); |
|
} |
|
usedInputMethods.put(inputMethodLocator.deriveLocator(null), inputMethod); |
|
perInputMethodState.put(inputMethod, |
|
Boolean.valueOf(clientWindowNotificationEnabled)); |
|
enableClientWindowNotification(inputMethod, false); |
|
if (this == inputMethodWindowContext) { |
|
inputMethod.hideWindows(); |
|
inputMethodWindowContext = null; |
|
} |
|
inputMethodLocator = null; |
|
inputMethod = null; |
|
inputMethodCreationFailed = false; |
|
} |
|
|
|
|
|
if (newLocator.getLocale() == null && savedLocale != null && |
|
newLocator.isLocaleAvailable(savedLocale)) { |
|
newLocator = newLocator.deriveLocator(savedLocale); |
|
} |
|
inputMethodLocator = newLocator; |
|
inputMethodCreationFailed = false; |
|
|
|
|
|
if (wasInputMethodActive) { |
|
inputMethod = getInputMethodInstance(); |
|
if (inputMethod instanceof InputMethodAdapter) { |
|
((InputMethodAdapter) inputMethod).setAWTFocussedComponent(awtFocussedComponent); |
|
} |
|
activateInputMethod(true); |
|
} |
|
|
|
|
|
if (wasCompositionEnabledSupported) { |
|
inputMethod = getInputMethod(); |
|
if (inputMethod != null) { |
|
try { |
|
inputMethod.setCompositionEnabled(wasCompositionEnabled); |
|
} catch (UnsupportedOperationException e) { } |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
Component getClientComponent() { |
|
return currentClientComponent; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public synchronized void removeNotify(Component component) { |
|
if (component == null) { |
|
throw new NullPointerException(); |
|
} |
|
|
|
if (inputMethod == null) { |
|
if (component == currentClientComponent) { |
|
currentClientComponent = null; |
|
} |
|
return; |
|
} |
|
|
|
// We may or may not get a FOCUS_LOST event for this component, |
|
|
|
if (component == awtFocussedComponent) { |
|
focusLost(component, false); |
|
} |
|
|
|
if (component == currentClientComponent) { |
|
if (isInputMethodActive) { |
|
|
|
deactivateInputMethod(false); |
|
} |
|
inputMethod.removeNotify(); |
|
if (clientWindowNotificationEnabled && addedClientWindowListeners()) { |
|
removeClientWindowListeners(); |
|
} |
|
currentClientComponent = null; |
|
if (inputMethod instanceof InputMethodAdapter) { |
|
((InputMethodAdapter) inputMethod).setClientComponent(null); |
|
} |
|
|
|
// removeNotify() can be issued from a thread other than the event dispatch |
|
// thread. In that case, avoid possible deadlock between Component.AWTTreeLock |
|
// and InputMethodContext.compositionAreaHandlerLock by releasing the composition |
|
|
|
if (EventQueue.isDispatchThread()) { |
|
((InputMethodContext)this).releaseCompositionArea(); |
|
} else { |
|
EventQueue.invokeLater(new Runnable() { |
|
public void run() { |
|
((InputMethodContext)InputContext.this).releaseCompositionArea(); |
|
} |
|
}); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public synchronized void dispose() { |
|
if (currentClientComponent != null) { |
|
throw new IllegalStateException("Can't dispose InputContext while it's active"); |
|
} |
|
if (inputMethod != null) { |
|
if (this == inputMethodWindowContext) { |
|
inputMethod.hideWindows(); |
|
inputMethodWindowContext = null; |
|
} |
|
if (inputMethod == previousInputMethod) { |
|
previousInputMethod = null; |
|
} |
|
if (clientWindowNotificationEnabled) { |
|
if (addedClientWindowListeners()) { |
|
removeClientWindowListeners(); |
|
} |
|
clientWindowNotificationEnabled = false; |
|
} |
|
inputMethod.dispose(); |
|
|
|
// in case the input method enabled the client window |
|
// notification in dispose(), which shouldn't happen, it |
|
|
|
if (clientWindowNotificationEnabled) { |
|
enableClientWindowNotification(inputMethod, false); |
|
} |
|
|
|
inputMethod = null; |
|
} |
|
inputMethodLocator = null; |
|
if (usedInputMethods != null && !usedInputMethods.isEmpty()) { |
|
Iterator<InputMethod> iterator = usedInputMethods.values().iterator(); |
|
usedInputMethods = null; |
|
while (iterator.hasNext()) { |
|
iterator.next().dispose(); |
|
} |
|
} |
|
|
|
|
|
clientWindowNotificationEnabled = false; |
|
clientWindowListened = null; |
|
perInputMethodState = null; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public synchronized Object getInputMethodControlObject() { |
|
InputMethod inputMethod = getInputMethod(); |
|
|
|
if (inputMethod != null) { |
|
return inputMethod.getControlObject(); |
|
} else { |
|
return null; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public void setCompositionEnabled(boolean enable) { |
|
InputMethod inputMethod = getInputMethod(); |
|
|
|
if (inputMethod == null) { |
|
throw new UnsupportedOperationException(); |
|
} |
|
inputMethod.setCompositionEnabled(enable); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean isCompositionEnabled() { |
|
InputMethod inputMethod = getInputMethod(); |
|
|
|
if (inputMethod == null) { |
|
throw new UnsupportedOperationException(); |
|
} |
|
return inputMethod.isCompositionEnabled(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public String getInputMethodInfo() { |
|
InputMethod inputMethod = getInputMethod(); |
|
|
|
if (inputMethod == null) { |
|
throw new UnsupportedOperationException("Null input method"); |
|
} |
|
|
|
String inputMethodInfo = null; |
|
if (inputMethod instanceof InputMethodAdapter) { |
|
|
|
inputMethodInfo = ((InputMethodAdapter)inputMethod). |
|
getNativeInputMethodInfo(); |
|
} |
|
|
|
// extracts the information from the InputMethodDescriptor |
|
|
|
if (inputMethodInfo == null && inputMethodLocator != null) { |
|
inputMethodInfo = inputMethodLocator.getDescriptor(). |
|
getInputMethodDisplayName(getLocale(), SunToolkit. |
|
getStartupLocale()); |
|
} |
|
|
|
if (inputMethodInfo != null && !inputMethodInfo.equals("")) { |
|
return inputMethodInfo; |
|
} |
|
|
|
|
|
return inputMethod.toString() + "-" + inputMethod.getLocale().toString(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void disableNativeIM() { |
|
InputMethod inputMethod = getInputMethod(); |
|
if (inputMethod != null && inputMethod instanceof InputMethodAdapter) { |
|
((InputMethodAdapter)inputMethod).stopListening(); |
|
} |
|
} |
|
|
|
|
|
private synchronized InputMethod getInputMethod() { |
|
if (inputMethod != null) { |
|
return inputMethod; |
|
} |
|
|
|
if (inputMethodCreationFailed) { |
|
return null; |
|
} |
|
|
|
inputMethod = getInputMethodInstance(); |
|
return inputMethod; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private InputMethod getInputMethodInstance() { |
|
InputMethodLocator locator = inputMethodLocator; |
|
if (locator == null) { |
|
inputMethodCreationFailed = true; |
|
return null; |
|
} |
|
|
|
Locale locale = locator.getLocale(); |
|
InputMethod inputMethodInstance = null; |
|
|
|
|
|
if (usedInputMethods != null) { |
|
inputMethodInstance = usedInputMethods.remove(locator.deriveLocator(null)); |
|
if (inputMethodInstance != null) { |
|
if (locale != null) { |
|
inputMethodInstance.setLocale(locale); |
|
} |
|
inputMethodInstance.setCharacterSubsets(characterSubsets); |
|
Boolean state = perInputMethodState.remove(inputMethodInstance); |
|
if (state != null) { |
|
enableClientWindowNotification(inputMethodInstance, state.booleanValue()); |
|
} |
|
((InputMethodContext) this).setInputMethodSupportsBelowTheSpot( |
|
(!(inputMethodInstance instanceof InputMethodAdapter)) || |
|
((InputMethodAdapter) inputMethodInstance).supportsBelowTheSpot()); |
|
return inputMethodInstance; |
|
} |
|
} |
|
|
|
|
|
try { |
|
inputMethodInstance = locator.getDescriptor().createInputMethod(); |
|
|
|
if (locale != null) { |
|
inputMethodInstance.setLocale(locale); |
|
} |
|
inputMethodInstance.setInputMethodContext((InputMethodContext) this); |
|
inputMethodInstance.setCharacterSubsets(characterSubsets); |
|
|
|
} catch (Exception e) { |
|
logCreationFailed(e); |
|
|
|
// there are a number of bad things that can happen while creating |
|
// the input method. In any case, we just continue without an |
|
|
|
inputMethodCreationFailed = true; |
|
|
|
// if the instance has been created, then it means either |
|
|
|
if (inputMethodInstance != null) { |
|
inputMethodInstance = null; |
|
} |
|
} catch (LinkageError e) { |
|
logCreationFailed(e); |
|
|
|
|
|
inputMethodCreationFailed = true; |
|
} |
|
((InputMethodContext) this).setInputMethodSupportsBelowTheSpot( |
|
(!(inputMethodInstance instanceof InputMethodAdapter)) || |
|
((InputMethodAdapter) inputMethodInstance).supportsBelowTheSpot()); |
|
return inputMethodInstance; |
|
} |
|
|
|
private void logCreationFailed(Throwable throwable) { |
|
PlatformLogger logger = PlatformLogger.getLogger("sun.awt.im"); |
|
if (logger.isLoggable(PlatformLogger.Level.CONFIG)) { |
|
String errorTextFormat = Toolkit.getProperty("AWT.InputMethodCreationFailed", |
|
"Could not create {0}. Reason: {1}"); |
|
Object[] args = |
|
{inputMethodLocator.getDescriptor().getInputMethodDisplayName(null, Locale.getDefault()), |
|
throwable.getLocalizedMessage()}; |
|
MessageFormat mf = new MessageFormat(errorTextFormat); |
|
logger.config(mf.format(args)); |
|
} |
|
} |
|
|
|
InputMethodLocator getInputMethodLocator() { |
|
if (inputMethod != null) { |
|
return inputMethodLocator.deriveLocator(inputMethod.getLocale()); |
|
} |
|
return inputMethodLocator; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public synchronized void endComposition() { |
|
if (inputMethod != null) { |
|
inputMethod.endComposition(); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
synchronized void enableClientWindowNotification(InputMethod requester, |
|
boolean enable) { |
|
// in case this request is not from the current input method, |
|
// store the request and handle it when this requesting input |
|
|
|
if (requester != inputMethod) { |
|
if (perInputMethodState == null) { |
|
perInputMethodState = new HashMap<>(5); |
|
} |
|
perInputMethodState.put(requester, Boolean.valueOf(enable)); |
|
return; |
|
} |
|
|
|
if (clientWindowNotificationEnabled != enable) { |
|
clientWindowLocation = null; |
|
clientWindowNotificationEnabled = enable; |
|
} |
|
if (clientWindowNotificationEnabled) { |
|
if (!addedClientWindowListeners()) { |
|
addClientWindowListeners(); |
|
} |
|
if (clientWindowListened != null) { |
|
clientWindowLocation = null; |
|
notifyClientWindowChange(clientWindowListened); |
|
} |
|
} else { |
|
if (addedClientWindowListeners()) { |
|
removeClientWindowListeners(); |
|
} |
|
} |
|
} |
|
|
|
private synchronized void notifyClientWindowChange(Window window) { |
|
if (inputMethod == null) { |
|
return; |
|
} |
|
|
|
|
|
if (!window.isVisible() || |
|
((window instanceof Frame) && ((Frame)window).getState() == Frame.ICONIFIED)) { |
|
clientWindowLocation = null; |
|
inputMethod.notifyClientWindowChange(null); |
|
return; |
|
} |
|
Rectangle location = window.getBounds(); |
|
if (clientWindowLocation == null || !clientWindowLocation.equals(location)) { |
|
clientWindowLocation = location; |
|
inputMethod.notifyClientWindowChange(clientWindowLocation); |
|
} |
|
} |
|
|
|
private synchronized void addClientWindowListeners() { |
|
Component client = getClientComponent(); |
|
if (client == null) { |
|
return; |
|
} |
|
Window window = getComponentWindow(client); |
|
if (window == null) { |
|
return; |
|
} |
|
window.addComponentListener(this); |
|
window.addWindowListener(this); |
|
clientWindowListened = window; |
|
} |
|
|
|
private synchronized void removeClientWindowListeners() { |
|
clientWindowListened.removeComponentListener(this); |
|
clientWindowListened.removeWindowListener(this); |
|
clientWindowListened = null; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private boolean addedClientWindowListeners() { |
|
return clientWindowListened != null; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void componentResized(ComponentEvent e) { |
|
notifyClientWindowChange((Window)e.getComponent()); |
|
} |
|
|
|
public void componentMoved(ComponentEvent e) { |
|
notifyClientWindowChange((Window)e.getComponent()); |
|
} |
|
|
|
public void componentShown(ComponentEvent e) { |
|
notifyClientWindowChange((Window)e.getComponent()); |
|
} |
|
|
|
public void componentHidden(ComponentEvent e) { |
|
notifyClientWindowChange((Window)e.getComponent()); |
|
} |
|
|
|
public void windowOpened(WindowEvent e) {} |
|
public void windowClosing(WindowEvent e) {} |
|
public void windowClosed(WindowEvent e) {} |
|
|
|
public void windowIconified(WindowEvent e) { |
|
notifyClientWindowChange(e.getWindow()); |
|
} |
|
|
|
public void windowDeiconified(WindowEvent e) { |
|
notifyClientWindowChange(e.getWindow()); |
|
} |
|
|
|
public void windowActivated(WindowEvent e) {} |
|
public void windowDeactivated(WindowEvent e) {} |
|
|
|
|
|
|
|
*/ |
|
private void initializeInputMethodSelectionKey() { |
|
AccessController.doPrivileged(new PrivilegedAction<Object>() { |
|
public Object run() { |
|
|
|
Preferences root = Preferences.userRoot(); |
|
inputMethodSelectionKey = getInputMethodSelectionKeyStroke(root); |
|
|
|
if (inputMethodSelectionKey == null) { |
|
|
|
root = Preferences.systemRoot(); |
|
inputMethodSelectionKey = getInputMethodSelectionKeyStroke(root); |
|
} |
|
return null; |
|
} |
|
}); |
|
} |
|
|
|
private AWTKeyStroke getInputMethodSelectionKeyStroke(Preferences root) { |
|
try { |
|
if (root.nodeExists(inputMethodSelectionKeyPath)) { |
|
Preferences node = root.node(inputMethodSelectionKeyPath); |
|
int keyCode = node.getInt(inputMethodSelectionKeyCodeName, KeyEvent.VK_UNDEFINED); |
|
if (keyCode != KeyEvent.VK_UNDEFINED) { |
|
int modifiers = node.getInt(inputMethodSelectionKeyModifiersName, 0); |
|
return AWTKeyStroke.getAWTKeyStroke(keyCode, modifiers); |
|
} |
|
} |
|
} catch (BackingStoreException bse) { |
|
} |
|
|
|
return null; |
|
} |
|
} |