< prev index next >

src/java.desktop/aix/classes/sun/awt/X11InputMethod.java

Print this page
rev 50285 : 8201429: Support AIX Input Method Editor (IME) for AWT Input Method Framework (IMF)

*** 1,7 **** /* ! * Copyright (c) 1997, 2017, 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 --- 1,7 ---- /* ! * Copyright (c) 1997, 2018, 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
*** 23,289 **** * questions. */ package sun.awt; - import java.util.Collections; - import java.util.Locale; - import java.util.Map; - import java.util.HashMap; - import java.awt.AWTEvent; import java.awt.AWTException; - import java.awt.Component; - import java.awt.Container; import java.awt.EventQueue; - import java.awt.Window; - import java.awt.im.InputMethodHighlight; - import java.awt.im.spi.InputMethodContext; - import sun.awt.im.InputMethodAdapter; import java.awt.event.InputMethodEvent; import java.awt.font.TextAttribute; import java.awt.font.TextHitInfo; import java.awt.peer.ComponentPeer; - import java.lang.Character.Subset; import java.text.AttributedString; - import java.text.AttributedCharacterIterator; - import java.io.File; - import java.io.FileReader; - import java.io.BufferedReader; - import java.io.IOException; - import java.lang.ref.WeakReference; import sun.util.logging.PlatformLogger; - import java.util.StringTokenizer; - import java.util.regex.Pattern; - /** ! * Input Method Adapter for XIM * * @author JavaSoft International */ ! public abstract class X11InputMethod extends InputMethodAdapter { ! private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11InputMethod"); ! /* ! * The following XIM* values must be the same as those defined in ! * Xlib.h ! */ ! private static final int XIMReverse = (1<<0); ! private static final int XIMUnderline = (1<<1); ! private static final int XIMHighlight = (1<<2); ! private static final int XIMPrimary = (1<<5); ! private static final int XIMSecondary = (1<<6); ! private static final int XIMTertiary = (1<<7); ! ! /* ! * visible position values ! */ ! private static final int XIMVisibleToForward = (1<<8); ! private static final int XIMVisibleToBackward = (1<<9); ! private static final int XIMVisibleCenter = (1<<10); ! private static final int XIMVisibleMask = (XIMVisibleToForward| ! XIMVisibleToBackward| ! XIMVisibleCenter); ! ! private Locale locale; ! private static boolean isXIMOpened = false; ! protected Container clientComponentWindow = null; ! private Component awtFocussedComponent = null; ! private Component lastXICFocussedComponent = null; ! private boolean isLastXICActive = false; ! private boolean isLastTemporary = false; ! private boolean isActive = false; ! private boolean isActiveClient = false; ! private static Map<TextAttribute, ?>[] highlightStyles; ! private boolean disposed = false; ! ! //reset the XIC if necessary ! private boolean needResetXIC = false; ! private WeakReference<Component> needResetXICClient = new WeakReference<>(null); ! ! // The use of compositionEnableSupported is to reduce unnecessary ! // native calls if set/isCompositionEnabled ! // throws UnsupportedOperationException. ! // It is set to false if that exception is thrown first time ! // either of the two methods are called. ! private boolean compositionEnableSupported = true; ! // The savedCompositionState indicates the composition mode when ! // endComposition or setCompositionEnabled is called. It doesn't always ! // reflect the actual composition state because it doesn't get updated ! // when the user changes the composition state through direct interaction ! // with the input method. It is used to save the composition mode when ! // focus is traversed across different client components sharing the ! // same java input context. Also if set/isCompositionEnabled are not ! // supported, it remains false. ! private boolean savedCompositionState = false; ! ! // variables to keep track of preedit context. ! // these variables need to be accessed within AWT_LOCK/UNLOCK ! private String committedText = null; ! private StringBuffer composedText = null; ! private IntBuffer rawFeedbacks; ! ! // private data (X11InputMethodData structure defined in ! // awt_InputMethod.c) for native methods ! // this structure needs to be accessed within AWT_LOCK/UNLOCK ! private transient long pData = 0; // accessed by native ! ! // Initialize highlight mapping table ! static { ! @SuppressWarnings({"unchecked", "rawtypes"}) ! Map<TextAttribute, ?> styles[] = new Map[4]; ! HashMap<TextAttribute, Object> map; ! ! // UNSELECTED_RAW_TEXT_HIGHLIGHT ! map = new HashMap<>(1); ! map.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); ! styles[0] = Collections.unmodifiableMap(map); ! ! // SELECTED_RAW_TEXT_HIGHLIGHT ! map = new HashMap<>(1); ! map.put(TextAttribute.SWAP_COLORS, TextAttribute.SWAP_COLORS_ON); ! styles[1] = Collections.unmodifiableMap(map); ! ! // UNSELECTED_CONVERTED_TEXT_HIGHLIGHT ! map = new HashMap<>(1); ! map.put(TextAttribute.INPUT_METHOD_UNDERLINE, ! TextAttribute.UNDERLINE_LOW_ONE_PIXEL); ! styles[2] = Collections.unmodifiableMap(map); ! ! // SELECTED_CONVERTED_TEXT_HIGHLIGHT ! map = new HashMap<>(1); ! map.put(TextAttribute.SWAP_COLORS, TextAttribute.SWAP_COLORS_ON); ! styles[3] = Collections.unmodifiableMap(map); ! ! highlightStyles = styles; ! } ! ! static { ! initIDs(); ! } ! /** ! * Initialize JNI field and method IDs for fields that may be ! accessed from C. ! */ ! private static native void initIDs(); /** * Constructs an X11InputMethod instance. It initializes the XIM * environment if it's not done yet. * * @exception AWTException if XOpenIM() failed. */ public X11InputMethod() throws AWTException { ! // supports only the locale in which the VM is started ! locale = X11InputMethodDescriptor.getSupportedLocale(); ! if (initXIM() == false) { ! throw new AWTException("Cannot open X Input Method"); ! } ! } ! ! @SuppressWarnings("deprecation") ! protected void finalize() throws Throwable { ! dispose(); ! super.finalize(); ! } ! ! /** ! * Invokes openIM() that invokes XOpenIM() if it's not opened yet. ! * @return true if openXIM() is successful or it's already been opened. ! */ ! private synchronized boolean initXIM() { ! if (isXIMOpened == false) ! isXIMOpened = openXIM(); ! return isXIMOpened; ! } ! ! protected abstract boolean openXIM(); ! ! protected boolean isDisposed() { ! return disposed; ! } ! ! protected abstract void setXICFocus(ComponentPeer peer, ! boolean value, boolean active); ! ! /** ! * Does nothing - this adapter doesn't use the input method context. ! * ! * @see java.awt.im.spi.InputMethod#setInputMethodContext ! */ ! public void setInputMethodContext(InputMethodContext context) { ! } ! ! /** ! * Set locale to input. If input method doesn't support specified locale, ! * false will be returned and its behavior is not changed. ! * ! * @param lang locale to input ! * @return the true is returned when specified locale is supported. ! */ ! public boolean setLocale(Locale lang) { ! if (lang.equals(locale)) { ! return true; ! } ! // special compatibility rule for Japanese and Korean ! if (locale.equals(Locale.JAPAN) && lang.equals(Locale.JAPANESE) || ! locale.equals(Locale.KOREA) && lang.equals(Locale.KOREAN)) { ! return true; ! } ! return false; ! } ! ! /** ! * Returns current input locale. ! */ ! public Locale getLocale() { ! return locale; ! } ! ! /** ! * Does nothing - XIM doesn't let you specify which characters you expect. ! * ! * @see java.awt.im.spi.InputMethod#setCharacterSubsets ! */ ! public void setCharacterSubsets(Subset[] subsets) { ! } ! ! /** ! * Dispatch event to input method. InputContext dispatch event with this ! * method. Input method set consume flag if event is consumed in ! * input method. ! * ! * @param e event ! */ ! public void dispatchEvent(AWTEvent e) { ! } ! ! ! protected final void resetXICifneeded(){ ! /* needResetXIC is used to indicate whether to call ! resetXIC on the active client. resetXIC will always be ! called on the passive client when endComposition is called. ! */ ! if (needResetXIC && haveActiveClient() && ! getClientComponent() != needResetXICClient.get()){ ! resetXIC(); ! ! // needs to reset the last xic focussed component. ! lastXICFocussedComponent = null; ! isLastXICActive = false; ! ! needResetXICClient.clear(); ! needResetXIC = false; ! } } /** * Reset the composition state to the current composition state. */ ! private void resetCompositionState() { ! if (compositionEnableSupported) { try { /* Restore the composition mode to the last saved composition mode. */ setCompositionEnabled(savedCompositionState); } catch (UnsupportedOperationException e) { --- 23,67 ---- * questions. */ package sun.awt; import java.awt.AWTException; import java.awt.EventQueue; import java.awt.event.InputMethodEvent; import java.awt.font.TextAttribute; import java.awt.font.TextHitInfo; import java.awt.peer.ComponentPeer; import java.text.AttributedString; import sun.util.logging.PlatformLogger; /** ! * Input Method Adapter for XIM for AIX * * @author JavaSoft International */ ! public abstract class X11InputMethod extends X11InputMethodBase { ! // to keep the instance of activating if IM resumed ! static protected X11InputMethod activatedInstance = null; /** * Constructs an X11InputMethod instance. It initializes the XIM * environment if it's not done yet. * * @exception AWTException if XOpenIM() failed. */ public X11InputMethod() throws AWTException { ! super(); } /** * Reset the composition state to the current composition state. */ ! protected void resetCompositionState() { ! if (compositionEnableSupported && haveActiveClient()) { try { /* Restore the composition mode to the last saved composition mode. */ setCompositionEnabled(savedCompositionState); } catch (UnsupportedOperationException e) {
*** 291,329 **** } } } /** - * Query and then return the current composition state. - * @return the composition state if isCompositionEnabled call - * is successful. Otherwise, it returns false. - */ - private boolean getCompositionState() { - boolean compositionState = false; - if (compositionEnableSupported) { - try { - compositionState = isCompositionEnabled(); - } catch (UnsupportedOperationException e) { - compositionEnableSupported = false; - } - } - return compositionState; - } - - /** * Activate input method. */ public synchronized void activate() { clientComponentWindow = getClientComponentWindow(); if (clientComponentWindow == null) return; ! if (lastXICFocussedComponent != null){ if (log.isLoggable(PlatformLogger.Level.FINE)) { log.fine("XICFocused {0}, AWTFocused {1}", lastXICFocussedComponent, awtFocussedComponent); } } if (pData == 0) { if (!createXIC()) { return; --- 69,98 ---- } } } /** * Activate input method. */ public synchronized void activate() { + activatedInstance = this; clientComponentWindow = getClientComponentWindow(); if (clientComponentWindow == null) return; ! if (lastXICFocussedComponent != null) { if (log.isLoggable(PlatformLogger.Level.FINE)) { log.fine("XICFocused {0}, AWTFocused {1}", lastXICFocussedComponent, awtFocussedComponent); } + if (lastXICFocussedComponent != awtFocussedComponent) { + ComponentPeer lastXICFocussedComponentPeer = getPeer(lastXICFocussedComponent); + if (lastXICFocussedComponentPeer != null) { + setXICFocus(lastXICFocussedComponentPeer, false, isLastXICActive); + } + } + lastXICFocussedComponent = null; } if (pData == 0) { if (!createXIC()) { return;
*** 332,369 **** } /* reset input context if necessary and set the XIC focus */ resetXICifneeded(); - ComponentPeer lastXICFocussedComponentPeer = null; ComponentPeer awtFocussedComponentPeer = getPeer(awtFocussedComponent); ! if (lastXICFocussedComponent != null) { ! lastXICFocussedComponentPeer = getPeer(lastXICFocussedComponent); } ! ! /* If the last XIC focussed component has a different peer as the ! current focussed component, change the XIC focus to the newly ! focussed component. ! */ ! if (isLastTemporary || lastXICFocussedComponentPeer != awtFocussedComponentPeer || ! isLastXICActive != haveActiveClient()) { ! if (lastXICFocussedComponentPeer != null) { ! setXICFocus(lastXICFocussedComponentPeer, false, isLastXICActive); ! } ! if (awtFocussedComponentPeer != null) { ! setXICFocus(awtFocussedComponentPeer, true, haveActiveClient()); ! } ! lastXICFocussedComponent = awtFocussedComponent; ! isLastXICActive = haveActiveClient(); ! } ! resetCompositionState(); isActive = true; } - protected abstract boolean createXIC(); - /** * Deactivate input method. */ public synchronized void deactivate(boolean isTemporary) { boolean isAc = haveActiveClient(); --- 101,124 ---- } /* reset input context if necessary and set the XIC focus */ resetXICifneeded(); ComponentPeer awtFocussedComponentPeer = getPeer(awtFocussedComponent); + setStatusAreaVisible(true, pData); ! if (awtFocussedComponentPeer != null) { ! setXICFocus(awtFocussedComponentPeer, true, haveActiveClient()); } ! lastXICFocussedComponent = awtFocussedComponent; ! isLastXICActive = haveActiveClient(); isActive = true; + if (savedCompositionState) { + resetCompositionState(); + } } /** * Deactivate input method. */ public synchronized void deactivate(boolean isTemporary) { boolean isAc = haveActiveClient();
*** 383,585 **** called, it can be restored correctly till activate is called on the newly focused component. (See also sun/awt/im/InputContext and bug 6184471). Last note, getCompositionState should be called before setXICFocus since setXICFocus here sets the XIC to 0. */ savedCompositionState = getCompositionState(); ! if (isTemporary){ //turn the status window off... turnoffStatusWindow(); } - /* Delay resetting the XIC focus until activate is called and the newly - focussed component has a different peer as the last focussed component. - */ - lastXICFocussedComponent = awtFocussedComponent; isLastXICActive = isAc; isLastTemporary = isTemporary; isActive = false; ! } ! ! /** ! * Explicitly disable the native IME. Native IME is not disabled when ! * deactivate is called. ! */ ! public void disableInputMethod() { ! if (lastXICFocussedComponent != null) { ! setXICFocus(getPeer(lastXICFocussedComponent), false, isLastXICActive); ! lastXICFocussedComponent = null; ! isLastXICActive = false; ! ! resetXIC(); ! needResetXICClient.clear(); ! needResetXIC = false; ! } } // implements java.awt.im.spi.InputMethod.hideWindows public void hideWindows() { ! // ??? need real implementation ! } ! ! /** ! * @see java.awt.Toolkit#mapInputMethodHighlight ! */ ! public static Map<TextAttribute, ?> mapInputMethodHighlight(InputMethodHighlight highlight) { ! int index; ! int state = highlight.getState(); ! if (state == InputMethodHighlight.RAW_TEXT) { ! index = 0; ! } else if (state == InputMethodHighlight.CONVERTED_TEXT) { ! index = 2; ! } else { ! return null; ! } ! if (highlight.isSelected()) { ! index += 1; ! } ! return highlightStyles[index]; ! } ! ! /** ! * @see sun.awt.im.InputMethodAdapter#setAWTFocussedComponent ! */ ! protected void setAWTFocussedComponent(Component component) { ! if (component == null) { ! return; ! } ! if (isActive) { ! // deactivate/activate are being suppressed during a focus change - ! // this may happen when an input method window is made visible ! boolean ac = haveActiveClient(); ! setXICFocus(getPeer(awtFocussedComponent), false, ac); ! setXICFocus(getPeer(component), true, ac); ! } ! awtFocussedComponent = component; ! } ! ! /** ! * @see sun.awt.im.InputMethodAdapter#stopListening ! */ ! protected void stopListening() { ! // It is desirable to disable XIM by calling XSetICValues with ! // XNPreeditState == XIMPreeditDisable. But Solaris 2.6 and ! // Solaris 7 do not implement this correctly without a patch, ! // so just call resetXIC here. Prior endComposition call commits ! // the existing composed text. ! endComposition(); ! // disable the native input method so that the other input ! // method could get the input focus. ! disableInputMethod(); ! if (needResetXIC) { ! resetXIC(); ! needResetXICClient.clear(); ! needResetXIC = false; ! } ! } ! ! /** ! * Returns the Window instance in which the client component is ! * contained. If not found, null is returned. (IS THIS POSSIBLE?) ! */ ! // NOTE: This method may be called by privileged threads. ! // DO NOT INVOKE CLIENT CODE ON THIS THREAD! ! private Window getClientComponentWindow() { ! Component client = getClientComponent(); ! Container container; ! ! if (client instanceof Container) { ! container = (Container) client; ! } else { ! container = getParent(client); ! } ! ! while (container != null && !(container instanceof java.awt.Window)) { ! container = getParent(container); ! } ! return (Window) container; ! } ! ! protected abstract Container getParent(Component client); ! ! /** ! * Returns peer of the given client component. If the given client component ! * doesn't have peer, peer of the native container of the client is returned. ! */ ! protected abstract ComponentPeer getPeer(Component client); ! ! /** ! * Used to protect preedit data ! */ ! protected abstract void awtLock(); ! protected abstract void awtUnlock(); ! ! /** ! * Creates an input method event from the arguments given ! * and posts it on the AWT event queue. For arguments, ! * see InputMethodEvent. Called by input method. ! * ! * @see java.awt.event.InputMethodEvent#InputMethodEvent ! */ ! private void postInputMethodEvent(int id, ! AttributedCharacterIterator text, ! int committedCharacterCount, ! TextHitInfo caret, ! TextHitInfo visiblePosition, ! long when) { ! Component source = getClientComponent(); ! if (source != null) { ! InputMethodEvent event = new InputMethodEvent(source, ! id, when, text, committedCharacterCount, caret, visiblePosition); ! SunToolkit.postEvent(SunToolkit.targetToAppContext(source), (AWTEvent)event); ! } ! } ! ! private void postInputMethodEvent(int id, ! AttributedCharacterIterator text, ! int committedCharacterCount, ! TextHitInfo caret, ! TextHitInfo visiblePosition) { ! postInputMethodEvent(id, text, committedCharacterCount, ! caret, visiblePosition, EventQueue.getMostRecentEventTime()); ! } ! ! /** ! * Dispatches committed text from XIM to the awt event queue. This ! * method is invoked from the event handler in canvas.c in the ! * AWT Toolkit thread context and thus inside the AWT Lock. ! * @param str committed text ! * @param when when ! */ ! // NOTE: This method may be called by privileged threads. ! // This functionality is implemented in a package-private method ! // to insure that it cannot be overridden by client subclasses. ! // DO NOT INVOKE CLIENT CODE ON THIS THREAD! ! void dispatchCommittedText(String str, long when) { ! if (str == null) ! return; ! ! if (composedText == null) { ! AttributedString attrstr = new AttributedString(str); ! postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED, ! attrstr.getIterator(), ! str.length(), ! null, ! null, ! when); ! } else { ! // if there is composed text, wait until the preedit ! // callback is invoked. ! committedText = str; } } - private void dispatchCommittedText(String str) { - dispatchCommittedText(str, EventQueue.getMostRecentEventTime()); - } - /** * Updates composed text with XIM preedit information and * posts composed text to the awt event queue. The args of * this method correspond to the XIM preedit callback * information. The XIM highlight attributes are translated via --- 138,181 ---- called, it can be restored correctly till activate is called on the newly focused component. (See also sun/awt/im/InputContext and bug 6184471). Last note, getCompositionState should be called before setXICFocus since setXICFocus here sets the XIC to 0. */ + activatedInstance = null; savedCompositionState = getCompositionState(); ! if (isTemporary) { //turn the status window off... turnoffStatusWindow(); + /* Delay resetting the XIC focus until activate is called and the newly + * Focused component has a different peer as the last focused component. + */ + lastXICFocussedComponent = awtFocussedComponent; + } else { + if (awtFocussedComponent != null ) { + ComponentPeer awtFocussedComponentPeer = getPeer(awtFocussedComponent); + if (awtFocussedComponentPeer != null) { + setXICFocus(awtFocussedComponentPeer, false, isAc); + } + } + lastXICFocussedComponent = null; } isLastXICActive = isAc; isLastTemporary = isTemporary; isActive = false; ! setStatusAreaVisible(false, pData); } // implements java.awt.im.spi.InputMethod.hideWindows public void hideWindows() { ! if (pData != 0) { ! setStatusAreaVisible(false, pData); ! turnoffStatusWindow(); } } /** * Updates composed text with XIM preedit information and * posts composed text to the awt event queue. The args of * this method correspond to the XIM preedit callback * information. The XIM highlight attributes are translated via
*** 599,618 **** long when) { if (disposed) { return; } ! //Workaround for deadlock bug on solaris2.6_zh bug#4170760 if (chgText == null && chgStyles == null && chgOffset == 0 && chgLength == 0 && caretPosition == 0 && composedText == null && committedText == null) return; if (composedText == null) { // TODO: avoid reallocation of those buffers composedText = new StringBuffer(INITIAL_SIZE); rawFeedbacks = new IntBuffer(INITIAL_SIZE); } --- 195,249 ---- long when) { if (disposed) { return; } ! // Workaround for deadlock bug on solaris2.6_zh bug#4170760 if (chgText == null && chgStyles == null && chgOffset == 0 && chgLength == 0 && caretPosition == 0 && composedText == null && committedText == null) return; + // Recalculate chgOffset and chgLength for supplementary char + if (composedText != null) { + int tmpChgOffset=chgOffset; + int tmpChgLength=chgLength; + int index = 0; + for (int i=0;i < tmpChgOffset; i++,index++){ + if (index < composedText.length() + && Character.charCount(composedText.codePointAt(index))==2){ + index++; + chgOffset++; + } + } + // The index keeps value + for (int i=0;i < tmpChgLength; i++,index++){ + if (index < composedText.length() + && Character.charCount(composedText.codePointAt(index))==2){ + index++; + chgLength++; + } + } + } + + // Replace control character with a square box + if (chgText != null) { + StringBuffer newChgText = new StringBuffer(); + for (int i=0; i < chgText.length(); i++){ + char c = chgText.charAt(i); + if (Character.isISOControl(c)){ + c = '\u25A1'; + } + newChgText.append(c); + } + chgText = new String(newChgText); + } + if (composedText == null) { // TODO: avoid reallocation of those buffers composedText = new StringBuffer(INITIAL_SIZE); rawFeedbacks = new IntBuffer(INITIAL_SIZE); }
*** 643,654 **** } } } if (chgText != null) { composedText.insert(chgOffset, chgText); ! if (chgStyles != null) rawFeedbacks.insert(chgOffset, chgStyles); } if (composedText.length() == 0) { composedText = null; rawFeedbacks = null; --- 274,324 ---- } } } if (chgText != null) { composedText.insert(chgOffset, chgText); ! if (chgStyles != null) { ! // Recalculate chgStyles for supplementary char ! if (chgText.length() > chgStyles.length){ ! int index=0; ! int[] newStyles = new int[chgText.length()]; ! for (int i=0; i < chgStyles.length; i++, index++){ ! newStyles[index]=chgStyles[i]; ! if (index < chgText.length() ! && Character.charCount(chgText.codePointAt(index))==2){ ! newStyles[++index]=chgStyles[i]; ! } ! } ! chgStyles=newStyles; ! } rawFeedbacks.insert(chgOffset, chgStyles); + } + + } + + else if (chgStyles != null) { + // Recalculate chgStyles to support supplementary char + int count=0; + for (int i=0; i < chgStyles.length; i++){ + if (composedText.length() > chgOffset+i+count + && Character.charCount(composedText.codePointAt(chgOffset+i+count))==2){ + count++; + } + } + if (count>0){ + int index=0; + int[] newStyles = new int[chgStyles.length+count]; + for (int i=0; i < chgStyles.length; i++, index++){ + newStyles[index]=chgStyles[i]; + if (composedText.length() > chgOffset+index + && Character.charCount(composedText.codePointAt(chgOffset+index))==2){ + newStyles[++index]=chgStyles[i]; + } + } + chgStyles=newStyles; + } + rawFeedbacks.replace(chgOffset, chgStyles); } if (composedText.length() == 0) { composedText = null; rawFeedbacks = null;
*** 672,681 **** --- 342,360 ---- when); return; } + // Adjust caretPosition for supplementary char + for (int i=0; i< caretPosition; i++){ + if (i < composedText.length() + && Character.charCount(composedText.codePointAt(i))==2){ + caretPosition++; + i++; + } + } + // Now sending the composed text to the client int composedOffset; AttributedString inputText; // if there is any partially committed text, concatenate it to
*** 737,824 **** TextHitInfo.leading(caretPosition), visiblePositionInfo, when); } ! /** ! * Flushes composed and committed text held in this context. ! * This method is invoked in the AWT Toolkit (X event loop) thread context ! * and thus inside the AWT Lock. ! */ ! // NOTE: This method may be called by privileged threads. ! // This functionality is implemented in a package-private method ! // to insure that it cannot be overridden by client subclasses. ! // DO NOT INVOKE CLIENT CODE ON THIS THREAD! ! void flushText() { ! String flush = (committedText != null ? committedText : ""); ! if (composedText != null) { ! flush += composedText.toString(); } ! if (!flush.equals("")) { ! AttributedString attrstr = new AttributedString(flush); ! postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED, ! attrstr.getIterator(), ! flush.length(), ! null, ! null, ! EventQueue.getMostRecentEventTime()); ! composedText = null; ! committedText = null; } } /* * Subclasses should override disposeImpl() instead of dispose(). Client * code should always invoke dispose(), never disposeImpl(). */ protected synchronized void disposeImpl() { disposeXIC(); awtLock(); ! composedText = null; ! committedText = null; ! rawFeedbacks = null; ! awtUnlock(); awtFocussedComponent = null; lastXICFocussedComponent = null; ! } ! ! /** ! * Frees all X Window resources associated with this object. ! * ! * @see java.awt.im.spi.InputMethod#dispose ! */ ! public final void dispose() { ! boolean call_disposeImpl = false; ! ! if (!disposed) { ! synchronized (this) { ! if (!disposed) { ! disposed = call_disposeImpl = true; ! } ! } ! } ! ! if (call_disposeImpl) { ! disposeImpl(); ! } ! } ! ! /** ! * Returns null. ! * ! * @see java.awt.im.spi.InputMethod#getControlObject ! */ ! public Object getControlObject() { ! return null; ! } ! ! /** ! * @see java.awt.im.spi.InputMethod#removeNotify ! */ ! public synchronized void removeNotify() { ! dispose(); } /** * @see java.awt.im.spi.InputMethod#setCompositionEnabled(boolean) */ --- 416,462 ---- TextHitInfo.leading(caretPosition), visiblePositionInfo, when); } ! /* Some IMs need forced Text clear */ ! void clearComposedText(long when) { ! composedText = null; ! postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED, ! null, 0, null, null, ! when); ! if (committedText != null && committedText.length() > 0) { ! dispatchCommittedText(committedText, when); } + committedText = null; + rawFeedbacks = null; + } ! void clearComposedText() { ! if (EventQueue.isDispatchThread()) { ! clearComposedText(EventQueue.getMostRecentEventTime()); } } /* * Subclasses should override disposeImpl() instead of dispose(). Client * code should always invoke dispose(), never disposeImpl(). */ protected synchronized void disposeImpl() { disposeXIC(); awtLock(); ! try { ! clearComposedText(); ! } finally { ! // Put awtUnlock into finally block in case an exception is thrown in clearComposedText. ! awtUnlock(); ! } awtFocussedComponent = null; lastXICFocussedComponent = null; ! needResetXIC = false; ! savedCompositionState = false; ! compositionEnableSupported = true; } /** * @see java.awt.im.spi.InputMethod#setCompositionEnabled(boolean) */
*** 829,1097 **** setCompositionEnabledNative may throw UnsupportedOperationException. Don't try to catch it since the method may be called by clients. Use package private mthod 'resetCompositionState' if you want the exception to be caught. */ if (setCompositionEnabledNative(enable)) { savedCompositionState = enable; } - } - - /** - * @see java.awt.im.spi.InputMethod#isCompositionEnabled - */ - public boolean isCompositionEnabled() { - /* isCompositionEnabledNative may throw UnsupportedOperationException. - Don't try to catch it since this method may be called by clients. - Use package private method 'getCompositionState' if you want the - exception to be caught. - */ - return isCompositionEnabledNative(); - } - - /** - * Ends any input composition that may currently be going on in this - * context. Depending on the platform and possibly user preferences, - * this may commit or delete uncommitted text. Any changes to the text - * are communicated to the active component using an input method event. - * - * <p> - * A text editing component may call this in a variety of situations, - * for example, when the user moves the insertion point within the text - * (but outside the composed text), or when the component's text is - * saved to a file or copied to the clipboard. - * - */ - public void endComposition() { - if (disposed) { - return; - } - - /* Before calling resetXIC, record the current composition mode - so that it can be restored later. */ - savedCompositionState = getCompositionState(); - boolean active = haveActiveClient(); - if (active && composedText == null && committedText == null){ - needResetXIC = true; - needResetXICClient = new WeakReference<>(getClientComponent()); - return; - } - - String text = resetXIC(); - /* needResetXIC is only set to true for active client. So passive - client should not reset the flag to false. */ - if (active) { - needResetXIC = false; - } ! // Remove any existing composed text by posting an InputMethodEvent ! // with null composed text. It would be desirable to wait for a ! // dispatchComposedText call from X input method engine, but some ! // input method does not conform to the XIM specification and does ! // not call the preedit callback to erase preedit text on calling ! // XmbResetIC. To work around this problem, do it here by ourselves. ! awtLock(); ! composedText = null; ! postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED, ! null, ! 0, ! null, ! null); ! ! if (text != null && text.length() > 0) { ! dispatchCommittedText(text); ! } ! awtUnlock(); ! ! // Restore the preedit state if it was enabled ! if (savedCompositionState) { ! resetCompositionState(); ! } ! } ! ! /** ! * Returns a string with information about the current input method server, or null. ! * On both Linux & SunOS, the value of environment variable XMODIFIERS is ! * returned if set. Otherwise, on SunOS, $HOME/.dtprofile will be parsed ! * to find out the language service engine (atok or wnn) since there is ! * no API in Xlib which returns the information of native ! * IM server or language service and we want to try our best to return as much ! * information as possible. ! * ! * Note: This method could return null on Linux if XMODIFIERS is not set properly or ! * if any IOException is thrown. ! * See man page of XSetLocaleModifiers(3X11) for the usgae of XMODIFIERS, ! * atok12setup(1) and wnn6setup(1) for the information written to ! * $HOME/.dtprofile when you run these two commands. ! * ! */ ! public String getNativeInputMethodInfo() { ! String xmodifiers = System.getenv("XMODIFIERS"); ! String imInfo = null; ! ! // If XMODIFIERS is set, return the value ! if (xmodifiers != null) { ! int imIndex = xmodifiers.indexOf("@im="); ! if (imIndex != -1) { ! imInfo = xmodifiers.substring(imIndex + 4); } - } else if (System.getProperty("os.name").startsWith("SunOS")) { - File dtprofile = new File(System.getProperty("user.home") + - "/.dtprofile"); - String languageEngineInfo = null; - try { - BufferedReader br = new BufferedReader(new FileReader(dtprofile)); - String line = null; - - while ( languageEngineInfo == null && (line = br.readLine()) != null) { - if (line.contains("atok") || line.contains("wnn")) { - StringTokenizer tokens = new StringTokenizer(line); - while (tokens.hasMoreTokens()) { - String token = tokens.nextToken(); - if (Pattern.matches("atok.*setup", token) || - Pattern.matches("wnn.*setup", token)){ - languageEngineInfo = token.substring(0, token.indexOf("setup")); - break; - } - } - } - } - - br.close(); - } catch(IOException ioex) { - // Since this method is provided for internal testing only, - // we dump the stack trace for the ease of debugging. - ioex.printStackTrace(); - } - - imInfo = "htt " + languageEngineInfo; - } - - return imInfo; - } - - - /** - * Performs mapping from an XIM visible feedback value to Java IM highlight. - * @return Java input method highlight - */ - private InputMethodHighlight convertVisualFeedbackToHighlight(int feedback) { - InputMethodHighlight highlight; - - switch (feedback) { - case XIMUnderline: - highlight = InputMethodHighlight.UNSELECTED_CONVERTED_TEXT_HIGHLIGHT; - break; - case XIMReverse: - highlight = InputMethodHighlight.SELECTED_CONVERTED_TEXT_HIGHLIGHT; - break; - case XIMHighlight: - highlight = InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT; - break; - case XIMPrimary: - highlight = InputMethodHighlight.UNSELECTED_CONVERTED_TEXT_HIGHLIGHT; - break; - case XIMSecondary: - highlight = InputMethodHighlight.SELECTED_CONVERTED_TEXT_HIGHLIGHT; - break; - case XIMTertiary: - highlight = InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT; - break; - default: - highlight = InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT; - break; - } - return highlight; - } - - // initial capacity size for string buffer, etc. - private static final int INITIAL_SIZE = 64; - - /** - * IntBuffer is an inner class that manipulates an int array and - * provides UNIX file io stream-like programming interfaces to - * access it. (An alternative would be to use ArrayList which may - * be too expensive for the work.) - */ - private final class IntBuffer { - private int[] intArray; - private int size; - private int index; - - IntBuffer(int initialCapacity) { - intArray = new int[initialCapacity]; - size = 0; - index = 0; - } - - void insert(int offset, int[] values) { - int newSize = size + values.length; - if (intArray.length < newSize) { - int[] newIntArray = new int[newSize * 2]; - System.arraycopy(intArray, 0, newIntArray, 0, size); - intArray = newIntArray; - } - System.arraycopy(intArray, offset, intArray, offset+values.length, - size - offset); - System.arraycopy(values, 0, intArray, offset, values.length); - size += values.length; - if (index > offset) - index = offset; - } - - void remove(int offset, int length) { - if (offset + length != size) - System.arraycopy(intArray, offset+length, intArray, offset, - size - offset - length); - size -= length; - if (index > offset) - index = offset; - } - - void replace(int offset, int[] values) { - System.arraycopy(values, 0, intArray, offset, values.length); - } - - void removeAll() { - size = 0; - index = 0; - } - - void rewind() { - index = 0; - } - - int getNext() { - if (index == size) - return -1; - return intArray[index++]; - } - - void unget() { - if (index != 0) - index--; - } - - int getOffset() { - return index; - } - - public String toString() { - StringBuffer s = new StringBuffer(); - for (int i = 0; i < size;) { - s.append(intArray[i++]); - if (i < size) - s.append(","); - } - return s.toString(); } } ! /* ! * Native methods ! */ ! private native String resetXIC(); ! private native void disposeXIC(); ! private native boolean setCompositionEnabledNative(boolean enable); ! private native boolean isCompositionEnabledNative(); ! private native void turnoffStatusWindow(); } --- 467,490 ---- setCompositionEnabledNative may throw UnsupportedOperationException. Don't try to catch it since the method may be called by clients. Use package private mthod 'resetCompositionState' if you want the exception to be caught. */ + boolean pre, post; + pre=getCompositionState(); + if (setCompositionEnabledNative(enable)) { savedCompositionState = enable; } ! post=getCompositionState(); ! if (pre != post && post == enable){ ! if (enable == false) flushText(); ! if (awtFocussedComponent != null && isActive){ ! setXICFocus(getPeer(awtFocussedComponent), ! true, haveActiveClient()); } } } ! private native void setStatusAreaVisible(boolean value, long data); }
< prev index next >