/*
 * Copyright (c) 1997, 2011, 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.Component;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.KeyEvent;
import java.awt.event.InputMethodEvent;
import java.awt.font.TextHitInfo;
import java.awt.im.InputMethodRequests;
import java.awt.im.spi.InputMethod;
import java.security.AccessController;
import java.text.AttributedCharacterIterator;
import java.text.AttributedCharacterIterator.Attribute;
import java.text.AttributedString;
import java.text.CharacterIterator;
import javax.swing.JFrame;
import sun.awt.InputMethodSupport;
import sun.security.action.GetPropertyAction;

The InputMethodContext class provides methods that input methods can use to communicate with their client components. It is a subclass of InputContext, which provides methods for use by components.
Author:JavaSoft International
/** * The InputMethodContext class provides methods that input methods * can use to communicate with their client components. * It is a subclass of InputContext, which provides methods for use by * components. * * @author JavaSoft International */
public class InputMethodContext extends sun.awt.im.InputContext implements java.awt.im.spi.InputMethodContext { private boolean dispatchingCommittedText; // Creation of the context's composition area handler is // delayed until we really need a composition area. private CompositionAreaHandler compositionAreaHandler; private Object compositionAreaHandlerLock = new Object(); static private boolean belowTheSpotInputRequested; private boolean inputMethodSupportsBelowTheSpot; static { // check whether we should use below-the-spot input // get property from command line String inputStyle = AccessController.doPrivileged (new GetPropertyAction("java.awt.im.style", null)); // get property from awt.properties file if (inputStyle == null) { inputStyle = Toolkit.getProperty("java.awt.im.style", null); } belowTheSpotInputRequested = "below-the-spot".equals(inputStyle); }
Constructs an InputMethodContext.
/** * Constructs an InputMethodContext. */
public InputMethodContext() { super(); } void setInputMethodSupportsBelowTheSpot(boolean supported) { inputMethodSupportsBelowTheSpot = supported; } boolean useBelowTheSpotInput() { return belowTheSpotInputRequested && inputMethodSupportsBelowTheSpot; } private boolean haveActiveClient() { Component client = getClientComponent(); return client != null && client.getInputMethodRequests() != null; } // implements java.awt.im.spi.InputMethodContext.dispatchInputMethodEvent public void dispatchInputMethodEvent(int id, AttributedCharacterIterator text, int committedCharacterCount, TextHitInfo caret, TextHitInfo visiblePosition) { // We need to record the client component as the source so // that we have correct information if we later have to break up this // event into key events. Component source; source = getClientComponent(); if (source != null) { InputMethodEvent event = new InputMethodEvent(source, id, text, committedCharacterCount, caret, visiblePosition); if (haveActiveClient() && !useBelowTheSpotInput()) { source.dispatchEvent(event); } else { getCompositionAreaHandler(true).processInputMethodEvent(event); } } }
Dispatches committed text to a client component. Called by composition window.
Params:
  • client – The component that the text should get dispatched to.
  • text – The iterator providing access to the committed (and possible composed) text.
  • committedCharacterCount – The number of committed characters in the text.
/** * Dispatches committed text to a client component. * Called by composition window. * * @param client The component that the text should get dispatched to. * @param text The iterator providing access to the committed * (and possible composed) text. * @param committedCharacterCount The number of committed characters in the text. */
synchronized void dispatchCommittedText(Component client, AttributedCharacterIterator text, int committedCharacterCount) { // note that the client is not always the current client component - // some host input method adapters may dispatch input method events // through the Java event queue, and we may have switched clients while // the event was in the queue. if (committedCharacterCount == 0 || text.getEndIndex() <= text.getBeginIndex()) { return; } long time = System.currentTimeMillis(); dispatchingCommittedText = true; try { InputMethodRequests req = client.getInputMethodRequests(); if (req != null) { // active client -> send text as InputMethodEvent int beginIndex = text.getBeginIndex(); AttributedCharacterIterator toBeCommitted = (new AttributedString(text, beginIndex, beginIndex + committedCharacterCount)).getIterator(); InputMethodEvent inputEvent = new InputMethodEvent( client, InputMethodEvent.INPUT_METHOD_TEXT_CHANGED, toBeCommitted, committedCharacterCount, null, null); client.dispatchEvent(inputEvent); } else { // passive client -> send text as KeyEvents char keyChar = text.first(); while (committedCharacterCount-- > 0 && keyChar != CharacterIterator.DONE) { KeyEvent keyEvent = new KeyEvent(client, KeyEvent.KEY_TYPED, time, 0, KeyEvent.VK_UNDEFINED, keyChar); client.dispatchEvent(keyEvent); keyChar = text.next(); } } } finally { dispatchingCommittedText = false; } } public void dispatchEvent(AWTEvent event) { // some host input method adapters may dispatch input method events // through the Java event queue. If the component that the event is // intended for isn't an active client, or if we're using below-the-spot // input, we need to dispatch this event // to the input window. Note that that component is not necessarily the // current client component, since we may have switched clients while // the event was in the queue. if (event instanceof InputMethodEvent) { if (((Component) event.getSource()).getInputMethodRequests() == null || (useBelowTheSpotInput() && !dispatchingCommittedText)) { getCompositionAreaHandler(true).processInputMethodEvent((InputMethodEvent) event); } } else { // make sure we don't dispatch our own key events back to the input method if (!dispatchingCommittedText) { super.dispatchEvent(event); } } }
Gets this context's composition area handler, creating it if necessary. If requested, it grabs the composition area for use by this context. The composition area's text is not updated.
/** * Gets this context's composition area handler, creating it if necessary. * If requested, it grabs the composition area for use by this context. * The composition area's text is not updated. */
private CompositionAreaHandler getCompositionAreaHandler(boolean grab) { synchronized(compositionAreaHandlerLock) { if (compositionAreaHandler == null) { compositionAreaHandler = new CompositionAreaHandler(this); } compositionAreaHandler.setClientComponent(getClientComponent()); if (grab) { compositionAreaHandler.grabCompositionArea(false); } return compositionAreaHandler; } }
Grabs the composition area for use by this context. If doUpdate is true, updates the composition area with previously sent composed text.
/** * Grabs the composition area for use by this context. * If doUpdate is true, updates the composition area with previously sent * composed text. */
void grabCompositionArea(boolean doUpdate) { synchronized(compositionAreaHandlerLock) { if (compositionAreaHandler != null) { compositionAreaHandler.grabCompositionArea(doUpdate); } else { // if this context hasn't seen a need for a composition area yet, // just close it without creating the machinery CompositionAreaHandler.closeCompositionArea(); } } }
Releases and closes the composition area if it is currently owned by this context's composition area handler.
/** * Releases and closes the composition area if it is currently owned by * this context's composition area handler. */
void releaseCompositionArea() { synchronized(compositionAreaHandlerLock) { if (compositionAreaHandler != null) { compositionAreaHandler.releaseCompositionArea(); } } }
Calls CompositionAreaHandler.isCompositionAreaVisible() to see whether the composition area is visible or not. Notice that this method is always called on the AWT event dispatch thread.
/** * Calls CompositionAreaHandler.isCompositionAreaVisible() to see * whether the composition area is visible or not. * Notice that this method is always called on the AWT event dispatch * thread. */
boolean isCompositionAreaVisible() { if (compositionAreaHandler != null) { return compositionAreaHandler.isCompositionAreaVisible(); } return false; }
Calls CompositionAreaHandler.setCompositionAreaVisible to show or hide the composition area. As isCompositionAreaVisible method, it is always called on AWT event dispatch thread.
/** * Calls CompositionAreaHandler.setCompositionAreaVisible to * show or hide the composition area. * As isCompositionAreaVisible method, it is always called * on AWT event dispatch thread. */
void setCompositionAreaVisible(boolean visible) { if (compositionAreaHandler != null) { compositionAreaHandler.setCompositionAreaVisible(visible); } }
Calls the current client component's implementation of getTextLocation.
/** * Calls the current client component's implementation of getTextLocation. */
public Rectangle getTextLocation(TextHitInfo offset) { return getReq().getTextLocation(offset); }
Calls the current client component's implementation of getLocationOffset.
/** * Calls the current client component's implementation of getLocationOffset. */
public TextHitInfo getLocationOffset(int x, int y) { return getReq().getLocationOffset(x, y); }
Calls the current client component's implementation of getInsertPositionOffset.
/** * Calls the current client component's implementation of getInsertPositionOffset. */
public int getInsertPositionOffset() { return getReq().getInsertPositionOffset(); }
Calls the current client component's implementation of getCommittedText.
/** * Calls the current client component's implementation of getCommittedText. */
public AttributedCharacterIterator getCommittedText(int beginIndex, int endIndex, Attribute[] attributes) { return getReq().getCommittedText(beginIndex, endIndex, attributes); }
Calls the current client component's implementation of getCommittedTextLength.
/** * Calls the current client component's implementation of getCommittedTextLength. */
public int getCommittedTextLength() { return getReq().getCommittedTextLength(); }
Calls the current client component's implementation of cancelLatestCommittedText.
/** * Calls the current client component's implementation of cancelLatestCommittedText. */
public AttributedCharacterIterator cancelLatestCommittedText(Attribute[] attributes) { return getReq().cancelLatestCommittedText(attributes); }
Calls the current client component's implementation of getSelectedText.
/** * Calls the current client component's implementation of getSelectedText. */
public AttributedCharacterIterator getSelectedText(Attribute[] attributes) { return getReq().getSelectedText(attributes); } private InputMethodRequests getReq() { if (haveActiveClient() && !useBelowTheSpotInput()) { return getClientComponent().getInputMethodRequests(); } else { return getCompositionAreaHandler(false); } } // implements java.awt.im.spi.InputMethodContext.createInputMethodWindow public Window createInputMethodWindow(String title, boolean attachToInputContext) { InputContext context = attachToInputContext ? this : null; return createInputMethodWindow(title, context, false); } // implements java.awt.im.spi.InputMethodContext.createInputMethodJFrame public JFrame createInputMethodJFrame(String title, boolean attachToInputContext) { InputContext context = attachToInputContext ? this : null; return (JFrame)createInputMethodWindow(title, context, true); } static Window createInputMethodWindow(String title, InputContext context, boolean isSwing) { if (GraphicsEnvironment.isHeadless()) { throw new HeadlessException(); } if (isSwing) { return new InputMethodJFrame(title, context); } else { Toolkit toolkit = Toolkit.getDefaultToolkit(); if (toolkit instanceof InputMethodSupport) { return ((InputMethodSupport)toolkit).createInputMethodWindow( title, context); } } throw new InternalError("Input methods must be supported"); }
See Also:
  • enableClientWindowNotification.enableClientWindowNotification
/** * @see java.awt.im.spi.InputMethodContext#enableClientWindowNotification */
public void enableClientWindowNotification(InputMethod inputMethod, boolean enable) { super.enableClientWindowNotification(inputMethod, enable); }
Disables or enables decorations for the composition window.
/** * Disables or enables decorations for the composition window. */
void setCompositionAreaUndecorated(boolean undecorated) { if (compositionAreaHandler != null) { compositionAreaHandler.setCompositionAreaUndecorated(undecorated); } } }