/*
* Copyright (c) 1997, 2019, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
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.
Author: JavaSoft Asia/Pacific See Also: - InputContext
/**
* 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
// takes precedence over locale information in the locator.
private InputMethodLocator inputMethodLocator;
private InputMethod inputMethod;
private boolean inputMethodCreationFailed;
// holding bin for previously used input method instances, but not the current one
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
// endComposition so that text doesn't jump from one component to another.
private Component currentClientComponent;
private Component awtFocussedComponent;
private boolean isInputMethodActive;
private Subset[] characterSubsets = null;
// true if composition area has been set to invisible when focus was lost
private boolean compositionAreaHidden = false;
// The input context for whose input method we may have to call hideWindows
private static InputContext inputMethodWindowContext;
// Previously active input method to decide whether we need to call
// InputMethodAdapter.stopListening() on activateInputMethod()
private static InputMethod previousInputMethod = null;
// true if the current input method requires client window change notification
private boolean clientWindowNotificationEnabled = false;
// client window to which this input context is listening
private Window clientWindowListened;
// cache location notification
private Rectangle clientWindowLocation = null;
// holding the state of clientWindowNotificationEnabled of only non-current input methods
private HashMap<InputMethod, Boolean> perInputMethodState;
// Input Method selection hot key stuff
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";
Constructs an InputContext.
/**
* Constructs an InputContext.
*/
protected InputContext() {
InputMethodManager imm = InputMethodManager.getInstance();
synchronized (InputContext.class) {
if (!inputMethodSelectionKeyInitialized) {
inputMethodSelectionKeyInitialized = true;
if (imm.hasMultipleInputMethods()) {
initializeInputMethodSelectionKey();
}
}
}
selectInputMethod(imm.getDefaultKeyboardLocale());
}
Throws: - NullPointerException – when the locale is null.
See Also: - selectInputMethod.selectInputMethod
/**
* @see java.awt.im.InputContext#selectInputMethod
* @exception NullPointerException when the locale is null.
*/
public synchronized boolean selectInputMethod(Locale locale) {
if (locale == null) {
throw new NullPointerException();
}
// see whether the current input method supports the locale
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,
// we look for an input method that's more confident.
if (inputMethodLocator.isLocaleAvailable(locale)) {
inputMethodLocator = inputMethodLocator.deriveLocator(locale);
return true;
}
}
// see whether there's some other input method that supports the locale
InputMethodLocator newLocator = InputMethodManager.getInstance().findInputMethod(locale);
if (newLocator != null) {
changeInputMethod(newLocator);
return true;
}
// make one last desperate effort with the current input method
// ??? is this good? This is pretty high cost for something that's likely to fail.
if (inputMethod == null && inputMethodLocator != null) {
inputMethod = getInputMethod();
if (inputMethod != null) {
return inputMethod.setLocale(locale);
}
}
return false;
}
See Also: - getLocale.getLocale
/**
* @see java.awt.im.InputContext#getLocale
*/
public Locale getLocale() {
if (inputMethod != null) {
return inputMethod.getLocale();
} else if (inputMethodLocator != null) {
return inputMethodLocator.getLocale();
} else {
return null;
}
}
See Also: - setCharacterSubsets.setCharacterSubsets
/**
* @see java.awt.im.InputContext#setCharacterSubsets
*/
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);
}
}
Throws: - UnsupportedOperationException – when input method is null
See Also: - reconvert.reconvert
Since: 1.3
/**
* @see java.awt.im.InputContext#reconvert
* @since 1.3
* @exception UnsupportedOperationException when input method is null
*/
public synchronized void reconvert() {
InputMethod inputMethod = getInputMethod();
if (inputMethod == null) {
throw new UnsupportedOperationException();
}
inputMethod.reconvert();
}
See Also: - dispatchEvent.dispatchEvent
/**
* @see java.awt.im.InputContext#dispatchEvent
*/
@SuppressWarnings("fallthrough")
public void dispatchEvent(AWTEvent event) {
if (event instanceof InputMethodEvent) {
return;
}
// Ignore focus events that relate to the InputMethodWindow of this context.
// This is a workaround. Should be removed after 4452384 is fixed.
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)) {
// pop up the input method selection menu
InputMethodManager.getInstance().notifyChangeRequestByHotKey((Component)event.getSource());
break;
}
// fall through
default:
if ((inputMethod != null) && (event instanceof InputEvent)) {
inputMethod.dispatchEvent(event);
}
}
}
Handles focus gained events for any component that's using
this input context.
These events are generated by AWT when the keyboard focus
moves to a component.
Besides actual client components, the source components
may also be the composition area or any component in an
input method window.
When handling the focus event for a client component, this
method checks whether the input context was previously
active for a different client component, and if so, calls
endComposition for the previous client component.
Params: - source – the component gaining the focus
/**
* Handles focus gained events for any component that's using
* this input context.
* These events are generated by AWT when the keyboard focus
* moves to a component.
* Besides actual client components, the source components
* may also be the composition area or any component in an
* input method window.
* <p>
* When handling the focus event for a client component, this
* method checks whether the input context was previously
* active for a different client component, and if so, calls
* endComposition for the previous client component.
*
* @param source the component gaining the focus
*/
private void focusGained(Component source) {
/*
* NOTE: When a Container is removing its Component which
* invokes this.removeNotify(), the Container has the global
* Component lock. It is possible to happen that an
* application thread is calling this.removeNotify() while an
* AWT event queue thread is dispatching a focus event via
* this.dispatchEvent(). If an input method uses AWT
* components (e.g., IIIMP status window), it causes deadlock,
* for example, Component.show()/hide() in this situation
* because hide/show tried to obtain the lock. Therefore,
* it's necessary to obtain the global Component lock before
* activating or deactivating an input method.
*/
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()) {
// Component is being disposed
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
// until we really know we're switching to a different component
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
// coming up
if (!isInputMethodActive) {
activateInputMethod(true);
}
// If the client component is an active client with the below-the-spot
// input style, then make the composition window undecorated without a title bar.
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
// when focus got lost
if (compositionAreaHidden == true) {
((InputMethodContext)this).setCompositionAreaVisible(true);
compositionAreaHidden = false;
}
}
}
}
Activates the current input method of this input context, and grabs
the composition area for use by this input context.
If updateCompositionArea is true, the text in the composition area
is updated (set to false if the text is going to change immediately
to avoid screen flicker).
/**
* Activates the current input method of this input context, and grabs
* the composition area for use by this input context.
* If updateCompositionArea is true, the text in the composition area
* is updated (set to false if the text is going to change immediately
* to avoid screen flicker).
*/
private void activateInputMethod(boolean updateCompositionArea) {
// call hideWindows() if this input context uses a different
// input method than the previously activated one
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
// new input method
((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();
}
}
}
Handles focus lost events for any component that's using
this input context.
These events are generated by AWT when the keyboard focus
moves away from a component.
Besides actual client components, the source components
may also be the composition area or any component in an
input method window.
Params: - source – the component losing the focus
@isTemporary whether the focus change is temporary
/**
* Handles focus lost events for any component that's using
* this input context.
* These events are generated by AWT when the keyboard focus
* moves away from a component.
* Besides actual client components, the source components
* may also be the composition area or any component in an
* input method window.
*
* @param source the component losing the focus
* @isTemporary whether the focus change is temporary
*/
private void focusLost(Component source, boolean isTemporary) {
// see the note on synchronization in focusGained
synchronized (source.getTreeLock()) {
synchronized (this) {
// We need to suppress deactivation if removeNotify has been called earlier.
// This is indicated by isInputMethodActive == false.
if (isInputMethodActive) {
deactivateInputMethod(isTemporary);
}
awtFocussedComponent = null;
if (inputMethod instanceof InputMethodAdapter) {
((InputMethodAdapter) inputMethod).setAWTFocussedComponent(null);
}
// hides the composition area if currently it is visible
InputMethodContext inputContext = ((InputMethodContext)this);
if (inputContext.isCompositionAreaVisible()) {
inputContext.setCompositionAreaVisible(false);
compositionAreaHidden = true;
}
}
}
}
Checks the key event is the input method selection key or not.
/**
* Checks the key event is the input method selection key or not.
*/
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;
}
}
Switches from the current input method to the one described by newLocator.
The current input method, if any, is asked to end composition, deactivated,
and saved for future use. The newLocator is made the current locator. If
the input context is active, an input method instance for the new locator
is obtained; otherwise this is deferred until required.
/**
* Switches from the current input method to the one described by newLocator.
* The current input method, if any, is asked to end composition, deactivated,
* and saved for future use. The newLocator is made the current locator. If
* the input context is active, an input method instance for the new locator
* is obtained; otherwise this is deferred until required.
*/
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.
// So, just record the locator. dispatchEvent will create the input method when needed.
if (inputMethodLocator == null) {
inputMethodLocator = newLocator;
inputMethodCreationFailed = false;
return;
}
// If the same input method is specified, just keep it.
// Adjust the locale if necessary.
if (inputMethodLocator.sameInputMethod(newLocator)) {
Locale newLocale = newLocator.getLocale();
if (newLocale != null && inputMethodLocator.getLocale() != newLocale) {
if (inputMethod != null) {
inputMethod.setLocale(newLocale);
}
inputMethodLocator = newLocator;
}
return;
}
// Switch out the old input method
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);
}
if (null == currentClientComponent.getInputMethodRequests())
wasCompositionEnabledSupported = false;
}
savedLocale = inputMethod.getLocale();
// keep the input method instance around for future use
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();
inputMethod.removeNotify();
inputMethodWindowContext = null;
}
inputMethodLocator = null;
inputMethod = null;
inputMethodCreationFailed = false;
}
// Switch in the new input method
if (newLocator.getLocale() == null && savedLocale != null &&
newLocator.isLocaleAvailable(savedLocale)) {
newLocator = newLocator.deriveLocator(savedLocale);
}
inputMethodLocator = newLocator;
inputMethodCreationFailed = false;
// activate the new input method if the old one was active
if (wasInputMethodActive) {
inputMethod = getInputMethodInstance();
if (inputMethod instanceof InputMethodAdapter) {
((InputMethodAdapter) inputMethod).setAWTFocussedComponent(awtFocussedComponent);
}
activateInputMethod(true);
}
// enable/disable composition if the old one supports querying enable/disable
if (wasCompositionEnabledSupported) {
inputMethod = getInputMethod();
if (inputMethod != null) {
try {
inputMethod.setCompositionEnabled(wasCompositionEnabled);
} catch (UnsupportedOperationException e) { }
}
}
}
Returns the client component.
/**
* Returns the client component.
*/
Component getClientComponent() {
return currentClientComponent;
}
Throws: - NullPointerException – when the component is null.
See Also: - removeNotify.removeNotify
/**
* @see java.awt.im.InputContext#removeNotify
* @exception NullPointerException when the component is null.
*/
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,
// so do the deactivation stuff here too.
if (component == awtFocussedComponent) {
focusLost(component, false);
}
if (component == currentClientComponent) {
if (isInputMethodActive) {
// component wasn't the one that had the focus
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
// area on the event dispatch thread.
if (EventQueue.isDispatchThread()) {
((InputMethodContext)this).releaseCompositionArea();
} else {
EventQueue.invokeLater(new Runnable() {
public void run() {
((InputMethodContext)InputContext.this).releaseCompositionArea();
}
});
}
}
}
Throws: - IllegalStateException – when the currentClientComponent is not null
See Also: - dispose.dispose
/**
* @see java.awt.im.InputContext#dispose
* @exception IllegalStateException when the currentClientComponent is not null
*/
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
// needs to be cleaned up again.
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();
}
}
// cleanup client window notification variables
clientWindowNotificationEnabled = false;
clientWindowListened = null;
perInputMethodState = null;
}
See Also: - getInputMethodControlObject.getInputMethodControlObject
/**
* @see java.awt.im.InputContext#getInputMethodControlObject
*/
public synchronized Object getInputMethodControlObject() {
InputMethod inputMethod = getInputMethod();
if (inputMethod != null) {
return inputMethod.getControlObject();
} else {
return null;
}
}
Throws: - UnsupportedOperationException – when input method is null
See Also: - setCompositionEnabled.setCompositionEnabled(boolean)
/**
* @see java.awt.im.InputContext#setCompositionEnabled(boolean)
* @exception UnsupportedOperationException when input method is null
*/
public void setCompositionEnabled(boolean enable) {
InputMethod inputMethod = getInputMethod();
if (inputMethod == null) {
throw new UnsupportedOperationException();
}
inputMethod.setCompositionEnabled(enable);
}
Throws: - UnsupportedOperationException – when input method is null
See Also: - isCompositionEnabled.isCompositionEnabled
/**
* @see java.awt.im.InputContext#isCompositionEnabled
* @exception UnsupportedOperationException when input method is null
*/
public boolean isCompositionEnabled() {
InputMethod inputMethod = getInputMethod();
if (inputMethod == null) {
throw new UnsupportedOperationException();
}
return inputMethod.isCompositionEnabled();
}
Throws: - UnsupportedOperationException – when input method is null
Returns: a string with information about the current input method.
/**
* @return a string with information about the current input method.
* @exception UnsupportedOperationException when input method is null
*/
public String getInputMethodInfo() {
InputMethod inputMethod = getInputMethod();
if (inputMethod == null) {
throw new UnsupportedOperationException("Null input method");
}
String inputMethodInfo = null;
if (inputMethod instanceof InputMethodAdapter) {
// returns the information about the host native input method.
inputMethodInfo = ((InputMethodAdapter)inputMethod).
getNativeInputMethodInfo();
}
// extracts the information from the InputMethodDescriptor
// associated with the current java input method.
if (inputMethodInfo == null && inputMethodLocator != null) {
inputMethodInfo = inputMethodLocator.getDescriptor().
getInputMethodDisplayName(getLocale(), SunToolkit.
getStartupLocale());
}
if (inputMethodInfo != null && !inputMethodInfo.equals("")) {
return inputMethodInfo;
}
// do our best to return something useful.
return inputMethod.toString() + "-" + inputMethod.getLocale().toString();
}
Turns off the native IM. The native IM is diabled when
the deactive method of InputMethod is called. It is
delayed until the active method is called on a different
peer component. This method is provided to explicitly disable
the native IM.
/**
* Turns off the native IM. The native IM is diabled when
* the deactive method of InputMethod is called. It is
* delayed until the active method is called on a different
* peer component. This method is provided to explicitly disable
* the native IM.
*/
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;
}
Returns an instance of the input method described by
the current input method locator. This may be an input
method that was previously used and switched out of,
or a new instance. The locale, character subsets, and
input method context of the input method are set.
The inputMethodCreationFailed field is set to true if the
instantiation failed.
See Also: Returns: an InputMethod instance
/**
* Returns an instance of the input method described by
* the current input method locator. This may be an input
* method that was previously used and switched out of,
* or a new instance. The locale, character subsets, and
* input method context of the input method are set.
*
* The inputMethodCreationFailed field is set to true if the
* instantiation failed.
*
* @return an InputMethod instance
* @see java.awt.im.spi.InputMethod#setInputMethodContext
* @see java.awt.im.spi.InputMethod#setLocale
* @see java.awt.im.spi.InputMethod#setCharacterSubsets
*/
private InputMethod getInputMethodInstance() {
InputMethodLocator locator = inputMethodLocator;
if (locator == null) {
inputMethodCreationFailed = true;
return null;
}
Locale locale = locator.getLocale();
InputMethod inputMethodInstance = null;
// see whether we have a previously used input method
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;
}
}
// need to create new instance
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
// input method.
inputMethodCreationFailed = true;
// if the instance has been created, then it means either
// setLocale() or setInputMethodContext() failed.
if (inputMethodInstance != null) {
inputMethodInstance = null;
}
} catch (LinkageError e) {
logCreationFailed(e);
// same as above
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;
}
See Also: - endComposition.endComposition
/**
* @see java.awt.im.InputContext#endComposition
*/
public synchronized void endComposition() {
if (inputMethod != null) {
inputMethod.endComposition();
}
}
See Also: - enableClientWindowNotification.enableClientWindowNotification
/**
* @see java.awt.im.spi.InputMethodContext#enableClientWindowNotification
*/
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
// method becomes the current one.
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 the window is invisible or iconified, send null to the input method.
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;
}
Returns true if listeners have been set up for client window
change notification.
/**
* Returns true if listeners have been set up for client window
* change notification.
*/
private boolean addedClientWindowListeners() {
return clientWindowListened != null;
}
/*
* ComponentListener and WindowListener implementation
*/
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) {}
Initializes the input method selection key definition in preference trees
/**
* Initializes the input method selection key definition in preference trees
*/
private void initializeInputMethodSelectionKey() {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
// Look in user's tree
Preferences root = Preferences.userRoot();
inputMethodSelectionKey = getInputMethodSelectionKeyStroke(root);
if (inputMethodSelectionKey == null) {
// Look in system's tree
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;
}
}