|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
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 |
|
*/ |
|
|
|
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 |
|
|
|
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 |
|
|
|
String inputStyle = AccessController.doPrivileged |
|
(new GetPropertyAction("java.awt.im.style", null)); |
|
|
|
if (inputStyle == null) { |
|
inputStyle = Toolkit.getProperty("java.awt.im.style", null); |
|
} |
|
belowTheSpotInputRequested = "below-the-spot".equals(inputStyle); |
|
} |
|
|
|
|
|
|
|
*/ |
|
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; |
|
} |
|
|
|
|
|
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 |
|
|
|
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); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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 |
|
|
|
if (committedCharacterCount == 0 |
|
|| text.getEndIndex() <= text.getBeginIndex()) { |
|
return; |
|
} |
|
long time = System.currentTimeMillis(); |
|
dispatchingCommittedText = true; |
|
try { |
|
InputMethodRequests req = client.getInputMethodRequests(); |
|
if (req != null) { |
|
|
|
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 { |
|
|
|
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 |
|
|
|
if (event instanceof InputMethodEvent) { |
|
if (((Component) event.getSource()).getInputMethodRequests() == null |
|
|| (useBelowTheSpotInput() && !dispatchingCommittedText)) { |
|
getCompositionAreaHandler(true).processInputMethodEvent((InputMethodEvent) event); |
|
} |
|
} else { |
|
|
|
if (!dispatchingCommittedText) { |
|
super.dispatchEvent(event); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private CompositionAreaHandler getCompositionAreaHandler(boolean grab) { |
|
synchronized(compositionAreaHandlerLock) { |
|
if (compositionAreaHandler == null) { |
|
compositionAreaHandler = new CompositionAreaHandler(this); |
|
} |
|
compositionAreaHandler.setClientComponent(getClientComponent()); |
|
if (grab) { |
|
compositionAreaHandler.grabCompositionArea(false); |
|
} |
|
|
|
return compositionAreaHandler; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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, |
|
|
|
CompositionAreaHandler.closeCompositionArea(); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
void releaseCompositionArea() { |
|
synchronized(compositionAreaHandlerLock) { |
|
if (compositionAreaHandler != null) { |
|
compositionAreaHandler.releaseCompositionArea(); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
boolean isCompositionAreaVisible() { |
|
if (compositionAreaHandler != null) { |
|
return compositionAreaHandler.isCompositionAreaVisible(); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
void setCompositionAreaVisible(boolean visible) { |
|
if (compositionAreaHandler != null) { |
|
compositionAreaHandler.setCompositionAreaVisible(visible); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public Rectangle getTextLocation(TextHitInfo offset) { |
|
return getReq().getTextLocation(offset); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public TextHitInfo getLocationOffset(int x, int y) { |
|
return getReq().getLocationOffset(x, y); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public int getInsertPositionOffset() { |
|
return getReq().getInsertPositionOffset(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public AttributedCharacterIterator getCommittedText(int beginIndex, |
|
int endIndex, |
|
Attribute[] attributes) { |
|
return getReq().getCommittedText(beginIndex, endIndex, attributes); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public int getCommittedTextLength() { |
|
return getReq().getCommittedTextLength(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public AttributedCharacterIterator cancelLatestCommittedText(Attribute[] attributes) { |
|
return getReq().cancelLatestCommittedText(attributes); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public AttributedCharacterIterator getSelectedText(Attribute[] attributes) { |
|
return getReq().getSelectedText(attributes); |
|
} |
|
|
|
private InputMethodRequests getReq() { |
|
if (haveActiveClient() && !useBelowTheSpotInput()) { |
|
return getClientComponent().getInputMethodRequests(); |
|
} else { |
|
return getCompositionAreaHandler(false); |
|
} |
|
} |
|
|
|
|
|
public Window createInputMethodWindow(String title, boolean attachToInputContext) { |
|
InputContext context = attachToInputContext ? this : null; |
|
return createInputMethodWindow(title, context, false); |
|
} |
|
|
|
|
|
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"); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void enableClientWindowNotification(InputMethod inputMethod, boolean enable) { |
|
super.enableClientWindowNotification(inputMethod, enable); |
|
} |
|
|
|
|
|
|
|
*/ |
|
void setCompositionAreaUndecorated(boolean undecorated) { |
|
if (compositionAreaHandler != null) { |
|
compositionAreaHandler.setCompositionAreaUndecorated(undecorated); |
|
} |
|
} |
|
} |