1 /* 2 * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.awt; 27 28 import java.awt.AWTEvent; 29 import java.awt.AWTException; 30 import java.awt.Component; 31 import java.awt.Container; 32 import java.awt.EventQueue; 33 import java.awt.Window; 34 import java.awt.event.InputMethodEvent; 35 import java.awt.font.TextAttribute; 36 import java.awt.font.TextHitInfo; 37 import java.awt.im.InputMethodHighlight; 38 import java.awt.im.spi.InputMethodContext; 39 import java.awt.peer.ComponentPeer; 40 import java.io.BufferedReader; 41 import java.io.File; 42 import java.io.FileReader; 43 import java.io.IOException; 44 import java.lang.Character.Subset; 45 import java.lang.ref.WeakReference; 46 import java.text.AttributedCharacterIterator; 47 import java.text.AttributedString; 48 import java.util.Collections; 49 import java.util.HashMap; 50 import java.util.Locale; 51 import java.util.Map; 52 import java.util.StringTokenizer; 53 import java.util.regex.Pattern; 54 55 import sun.awt.im.InputMethodAdapter; 56 import sun.util.logging.PlatformLogger; 57 58 /** 59 * Input Method Adapter for XIM 60 * 61 * @author JavaSoft International 62 */ 63 public abstract class X11InputMethodBase extends InputMethodAdapter { 64 protected static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11InputMethod"); 65 /* 66 * The following XIM* values must be the same as those defined in 67 * Xlib.h 68 */ 69 private static final int XIMReverse = (1<<0); 70 private static final int XIMUnderline = (1<<1); 71 private static final int XIMHighlight = (1<<2); 72 private static final int XIMPrimary = (1<<5); 73 private static final int XIMSecondary = (1<<6); 74 private static final int XIMTertiary = (1<<7); 75 76 /* 77 * visible position values 78 */ 79 protected static final int XIMVisibleToForward = (1<<8); 80 protected static final int XIMVisibleToBackward = (1<<9); 81 protected static final int XIMVisibleCenter = (1<<10); 82 protected static final int XIMVisibleMask = 83 (XIMVisibleToForward | XIMVisibleToBackward | XIMVisibleCenter); 84 85 private Locale locale; 86 private static boolean isXIMOpened = false; 87 protected Container clientComponentWindow = null; 88 protected Component awtFocussedComponent = null; 89 protected Component lastXICFocussedComponent = null; 90 protected boolean isLastXICActive = false; 91 protected boolean isLastTemporary = false; 92 protected boolean isActive = false; 93 private static Map<TextAttribute, ?>[] highlightStyles; 94 protected boolean disposed = false; 95 96 //reset the XIC if necessary 97 protected boolean needResetXIC = false; 98 private WeakReference<Component> needResetXICClient = new WeakReference<>(null); 99 100 // The use of compositionEnableSupported is to reduce unnecessary 101 // native calls if set/isCompositionEnabled 102 // throws UnsupportedOperationException. 103 // It is set to false if that exception is thrown first time 104 // either of the two methods are called. 105 protected boolean compositionEnableSupported = true; 106 // The savedCompositionState indicates the composition mode when 107 // endComposition or setCompositionEnabled is called. It doesn't always 108 // reflect the actual composition state because it doesn't get updated 109 // when the user changes the composition state through direct interaction 110 // with the input method. It is used to save the composition mode when 111 // focus is traversed across different client components sharing the 112 // same java input context. Also if set/isCompositionEnabled are not 113 // supported, it remains false. 114 protected boolean savedCompositionState = false; 115 116 // variables to keep track of preedit context. 117 // these variables need to be accessed within AWT_LOCK/UNLOCK 118 protected String committedText = null; 119 protected StringBuffer composedText = null; 120 protected IntBuffer rawFeedbacks; 121 122 // private data (X11InputMethodData structure defined in 123 // awt_InputMethod.c) for native methods 124 // this structure needs to be accessed within AWT_LOCK/UNLOCK 125 protected transient long pData = 0; // accessed by native 126 127 // Initialize highlight mapping table 128 static { 129 @SuppressWarnings({"unchecked", "rawtypes"}) 130 Map<TextAttribute, ?>[] styles = new Map[4]; 131 HashMap<TextAttribute, Object> map; 132 133 // UNSELECTED_RAW_TEXT_HIGHLIGHT 134 map = new HashMap<>(1); map.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD)135 map.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); 136 styles[0] = Collections.unmodifiableMap(map); 137 138 // SELECTED_RAW_TEXT_HIGHLIGHT 139 map = new HashMap<>(1); map.put(TextAttribute.SWAP_COLORS, TextAttribute.SWAP_COLORS_ON)140 map.put(TextAttribute.SWAP_COLORS, TextAttribute.SWAP_COLORS_ON); 141 styles[1] = Collections.unmodifiableMap(map); 142 143 // UNSELECTED_CONVERTED_TEXT_HIGHLIGHT 144 map = new HashMap<>(1); map.put(TextAttribute.INPUT_METHOD_UNDERLINE, TextAttribute.UNDERLINE_LOW_ONE_PIXEL)145 map.put(TextAttribute.INPUT_METHOD_UNDERLINE, 146 TextAttribute.UNDERLINE_LOW_ONE_PIXEL); 147 styles[2] = Collections.unmodifiableMap(map); 148 149 // SELECTED_CONVERTED_TEXT_HIGHLIGHT 150 map = new HashMap<>(1); map.put(TextAttribute.SWAP_COLORS, TextAttribute.SWAP_COLORS_ON)151 map.put(TextAttribute.SWAP_COLORS, TextAttribute.SWAP_COLORS_ON); 152 styles[3] = Collections.unmodifiableMap(map); 153 154 highlightStyles = styles; 155 } 156 157 static { initIDs()158 initIDs(); 159 } 160 161 /** 162 * Constructs an X11InputMethod instance. It initializes the XIM 163 * environment if it's not done yet. 164 * 165 * @exception AWTException if XOpenIM() failed. 166 */ X11InputMethodBase()167 public X11InputMethodBase() throws AWTException { 168 // supports only the locale in which the VM is started 169 locale = X11InputMethodDescriptor.getSupportedLocale(); 170 if (initXIM() == false) { 171 throw new AWTException("Cannot open X Input Method"); 172 } 173 } 174 175 @SuppressWarnings("deprecation") finalize()176 protected void finalize() throws Throwable { 177 dispose(); 178 super.finalize(); 179 } 180 181 /** 182 * Invokes openIM() that invokes XOpenIM() if it's not opened yet. 183 * @return true if openXIM() is successful or it's already been opened. 184 */ initXIM()185 private synchronized boolean initXIM() { 186 if (isXIMOpened == false) 187 isXIMOpened = openXIM(); 188 return isXIMOpened; 189 } 190 openXIM()191 protected abstract boolean openXIM(); 192 isDisposed()193 protected boolean isDisposed() { 194 return disposed; 195 } 196 setXICFocus(ComponentPeer peer, boolean value, boolean active)197 protected abstract void setXICFocus(ComponentPeer peer, 198 boolean value, boolean active); 199 200 /** 201 * Does nothing - this adapter doesn't use the input method context. 202 * 203 * @see java.awt.im.spi.InputMethod#setInputMethodContext 204 */ setInputMethodContext(InputMethodContext context)205 public void setInputMethodContext(InputMethodContext context) { 206 } 207 208 /** 209 * Set locale to input. If input method doesn't support specified locale, 210 * false will be returned and its behavior is not changed. 211 * 212 * @param lang locale to input 213 * @return the true is returned when specified locale is supported. 214 */ setLocale(Locale lang)215 public boolean setLocale(Locale lang) { 216 if (lang.equals(locale)) { 217 return true; 218 } 219 // special compatibility rule for Japanese and Korean 220 if (locale.equals(Locale.JAPAN) && lang.equals(Locale.JAPANESE) || 221 locale.equals(Locale.KOREA) && lang.equals(Locale.KOREAN)) { 222 return true; 223 } 224 return false; 225 } 226 227 /** 228 * Returns current input locale. 229 */ getLocale()230 public Locale getLocale() { 231 return locale; 232 } 233 234 /** 235 * Does nothing - XIM doesn't let you specify which characters you expect. 236 * 237 * @see java.awt.im.spi.InputMethod#setCharacterSubsets 238 */ setCharacterSubsets(Subset[] subsets)239 public void setCharacterSubsets(Subset[] subsets) { 240 } 241 242 /** 243 * Dispatch event to input method. InputContext dispatch event with this 244 * method. Input method set consume flag if event is consumed in 245 * input method. 246 * 247 * @param e event 248 */ dispatchEvent(AWTEvent e)249 public void dispatchEvent(AWTEvent e) { 250 } 251 resetXICifneeded()252 protected final void resetXICifneeded(){ 253 /* needResetXIC is used to indicate whether to call 254 resetXIC on the active client. resetXIC will always be 255 called on the passive client when endComposition is called. 256 */ 257 if (needResetXIC && haveActiveClient() && 258 getClientComponent() != needResetXICClient.get()){ 259 resetXIC(); 260 261 // needs to reset the last xic focussed component. 262 lastXICFocussedComponent = null; 263 isLastXICActive = false; 264 265 needResetXICClient.clear(); 266 needResetXIC = false; 267 } 268 } 269 270 /** 271 * Reset the composition state to the current composition state. 272 */ resetCompositionState()273 protected abstract void resetCompositionState(); 274 275 /** 276 * Query and then return the current composition state. 277 * @return the composition state if isCompositionEnabled call 278 * is successful. Otherwise, it returns false. 279 */ getCompositionState()280 protected boolean getCompositionState() { 281 boolean compositionState = false; 282 if (compositionEnableSupported) { 283 try { 284 compositionState = isCompositionEnabled(); 285 } catch (UnsupportedOperationException e) { 286 compositionEnableSupported = false; 287 } 288 } 289 return compositionState; 290 } 291 292 /** 293 * Activate input method. 294 */ activate()295 public abstract void activate(); 296 createXIC()297 protected abstract boolean createXIC(); 298 299 /** 300 * Deactivate input method. 301 */ deactivate(boolean isTemporary)302 public abstract void deactivate(boolean isTemporary); 303 304 /** 305 * Explicitly disable the native IME. Native IME is not disabled when 306 * deactivate is called. 307 */ disableInputMethod()308 public void disableInputMethod() { 309 if (lastXICFocussedComponent != null) { 310 setXICFocus(getPeer(lastXICFocussedComponent), false, isLastXICActive); 311 lastXICFocussedComponent = null; 312 isLastXICActive = false; 313 314 resetXIC(); 315 needResetXICClient.clear(); 316 needResetXIC = false; 317 } 318 } 319 320 // implements java.awt.im.spi.InputMethod.hideWindows hideWindows()321 public abstract void hideWindows(); 322 323 /** 324 * @see java.awt.Toolkit#mapInputMethodHighlight 325 */ mapInputMethodHighlight(InputMethodHighlight highlight)326 public static Map<TextAttribute, ?> mapInputMethodHighlight(InputMethodHighlight highlight) { 327 int index; 328 int state = highlight.getState(); 329 if (state == InputMethodHighlight.RAW_TEXT) { 330 index = 0; 331 } else if (state == InputMethodHighlight.CONVERTED_TEXT) { 332 index = 2; 333 } else { 334 return null; 335 } 336 if (highlight.isSelected()) { 337 index += 1; 338 } 339 return highlightStyles[index]; 340 } 341 342 /** 343 * @see sun.awt.im.InputMethodAdapter#setAWTFocussedComponent 344 */ setAWTFocussedComponent(Component component)345 protected void setAWTFocussedComponent(Component component) { 346 if (component == null) { 347 return; 348 } 349 if (isActive) { 350 // deactivate/activate are being suppressed during a focus change - 351 // this may happen when an input method window is made visible 352 boolean ac = haveActiveClient(); 353 setXICFocus(getPeer(awtFocussedComponent), false, ac); 354 setXICFocus(getPeer(component), true, ac); 355 } 356 awtFocussedComponent = component; 357 } 358 359 /** 360 * @see sun.awt.im.InputMethodAdapter#stopListening 361 */ stopListening()362 protected void stopListening() { 363 // It is desirable to disable XIM by calling XSetICValues with 364 // XNPreeditState == XIMPreeditDisable. But Solaris 2.6 and 365 // Solaris 7 do not implement this correctly without a patch, 366 // so just call resetXIC here. Prior endComposition call commits 367 // the existing composed text. 368 endComposition(); 369 // disable the native input method so that the other input 370 // method could get the input focus. 371 disableInputMethod(); 372 if (needResetXIC) { 373 resetXIC(); 374 needResetXICClient.clear(); 375 needResetXIC = false; 376 } 377 } 378 379 /** 380 * Returns the Window instance in which the client component is 381 * contained. If not found, null is returned. (IS THIS POSSIBLE?) 382 */ 383 // NOTE: This method may be called by privileged threads. 384 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! getClientComponentWindow()385 protected Window getClientComponentWindow() { 386 Component client = getClientComponent(); 387 Container container; 388 389 if (client instanceof Container) { 390 container = (Container) client; 391 } else { 392 container = getParent(client); 393 } 394 395 while (container != null && !(container instanceof java.awt.Window)) { 396 container = getParent(container); 397 } 398 return (Window) container; 399 } 400 getParent(Component client)401 protected abstract Container getParent(Component client); 402 403 /** 404 * Returns peer of the given client component. If the given client component 405 * doesn't have peer, peer of the native container of the client is returned. 406 */ getPeer(Component client)407 protected abstract ComponentPeer getPeer(Component client); 408 409 /** 410 * Used to protect preedit data 411 */ awtLock()412 protected abstract void awtLock(); awtUnlock()413 protected abstract void awtUnlock(); 414 415 /** 416 * Creates an input method event from the arguments given 417 * and posts it on the AWT event queue. For arguments, 418 * see InputMethodEvent. Called by input method. 419 * 420 * @see java.awt.event.InputMethodEvent#InputMethodEvent 421 */ postInputMethodEvent(int id, AttributedCharacterIterator text, int committedCharacterCount, TextHitInfo caret, TextHitInfo visiblePosition, long when)422 protected void postInputMethodEvent(int id, 423 AttributedCharacterIterator text, 424 int committedCharacterCount, 425 TextHitInfo caret, 426 TextHitInfo visiblePosition, 427 long when) { 428 Component source = getClientComponent(); 429 if (source != null) { 430 InputMethodEvent event = new InputMethodEvent(source, 431 id, when, text, committedCharacterCount, caret, visiblePosition); 432 SunToolkit.postEvent(SunToolkit.targetToAppContext(source), (AWTEvent)event); 433 } 434 } 435 postInputMethodEvent(int id, AttributedCharacterIterator text, int committedCharacterCount, TextHitInfo caret, TextHitInfo visiblePosition)436 private void postInputMethodEvent(int id, 437 AttributedCharacterIterator text, 438 int committedCharacterCount, 439 TextHitInfo caret, 440 TextHitInfo visiblePosition) { 441 postInputMethodEvent(id, text, committedCharacterCount, 442 caret, visiblePosition, EventQueue.getMostRecentEventTime()); 443 } 444 445 /** 446 * Dispatches committed text from XIM to the awt event queue. This 447 * method is invoked from the event handler in canvas.c in the 448 * AWT Toolkit thread context and thus inside the AWT Lock. 449 * @param str committed text 450 * @param when when 451 */ 452 // NOTE: This method may be called by privileged threads. 453 // This functionality is implemented in a package-private method 454 // to insure that it cannot be overridden by client subclasses. 455 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! dispatchCommittedText(String str, long when)456 void dispatchCommittedText(String str, long when) { 457 if (str == null) 458 return; 459 460 if (composedText == null) { 461 AttributedString attrstr = new AttributedString(str); 462 postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED, 463 attrstr.getIterator(), 464 str.length(), 465 null, 466 null, 467 when); 468 } else { 469 // if there is composed text, wait until the preedit 470 // callback is invoked. 471 committedText = str; 472 } 473 } 474 dispatchCommittedText(String str)475 private void dispatchCommittedText(String str) { 476 dispatchCommittedText(str, EventQueue.getMostRecentEventTime()); 477 } 478 479 /** 480 * Updates composed text with XIM preedit information and 481 * posts composed text to the awt event queue. The args of 482 * this method correspond to the XIM preedit callback 483 * information. The XIM highlight attributes are translated via 484 * fixed mapping (i.e., independent from any underlying input 485 * method engine). This method is invoked in the AWT Toolkit 486 * (X event loop) thread context and thus inside the AWT Lock. 487 */ 488 // NOTE: This method may be called by privileged threads. 489 // This functionality is implemented in a package-private method 490 // to insure that it cannot be overridden by client subclasses. 491 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! dispatchComposedText(String chgText, int[] chgStyles, int chgOffset, int chgLength, int caretPosition, long when)492 abstract void dispatchComposedText(String chgText, 493 int[] chgStyles, 494 int chgOffset, 495 int chgLength, 496 int caretPosition, 497 long when); 498 499 /** 500 * Flushes composed and committed text held in this context. 501 * This method is invoked in the AWT Toolkit (X event loop) thread context 502 * and thus inside the AWT Lock. 503 */ 504 // NOTE: This method may be called by privileged threads. 505 // This functionality is implemented in a package-private method 506 // to insure that it cannot be overridden by client subclasses. 507 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! flushText()508 void flushText() { 509 String flush = (committedText != null ? committedText : ""); 510 if (composedText != null) { 511 flush += composedText.toString(); 512 } 513 514 if (!flush.isEmpty()) { 515 AttributedString attrstr = new AttributedString(flush); 516 postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED, 517 attrstr.getIterator(), 518 flush.length(), 519 null, 520 null, 521 EventQueue.getMostRecentEventTime()); 522 composedText = null; 523 committedText = null; 524 } 525 } 526 527 /* 528 * Subclasses should override disposeImpl() instead of dispose(). Client 529 * code should always invoke dispose(), never disposeImpl(). 530 */ disposeImpl()531 protected abstract void disposeImpl(); 532 533 /** 534 * Frees all X Window resources associated with this object. 535 * 536 * @see java.awt.im.spi.InputMethod#dispose 537 */ dispose()538 public final void dispose() { 539 boolean call_disposeImpl = false; 540 541 if (!disposed) { 542 synchronized (this) { 543 if (!disposed) { 544 disposed = call_disposeImpl = true; 545 } 546 } 547 } 548 549 if (call_disposeImpl) { 550 disposeImpl(); 551 } 552 } 553 554 /** 555 * Returns null. 556 * 557 * @see java.awt.im.spi.InputMethod#getControlObject 558 */ getControlObject()559 public Object getControlObject() { 560 return null; 561 } 562 563 /** 564 * @see java.awt.im.spi.InputMethod#removeNotify 565 */ removeNotify()566 public synchronized void removeNotify() { 567 dispose(); 568 } 569 570 /** 571 * @see java.awt.im.spi.InputMethod#setCompositionEnabled(boolean) 572 */ setCompositionEnabled(boolean enable)573 public abstract void setCompositionEnabled(boolean enable); 574 575 /** 576 * @see java.awt.im.spi.InputMethod#isCompositionEnabled 577 */ isCompositionEnabled()578 public boolean isCompositionEnabled() { 579 /* isCompositionEnabledNative may throw UnsupportedOperationException. 580 Don't try to catch it since this method may be called by clients. 581 Use package private method 'getCompositionState' if you want the 582 exception to be caught. 583 */ 584 return isCompositionEnabledNative(); 585 } 586 587 /** 588 * Ends any input composition that may currently be going on in this 589 * context. Depending on the platform and possibly user preferences, 590 * this may commit or delete uncommitted text. Any changes to the text 591 * are communicated to the active component using an input method event. 592 * 593 * <p> 594 * A text editing component may call this in a variety of situations, 595 * for example, when the user moves the insertion point within the text 596 * (but outside the composed text), or when the component's text is 597 * saved to a file or copied to the clipboard. 598 * 599 */ endComposition()600 public void endComposition() { 601 if (disposed) { 602 return; 603 } 604 605 /* Before calling resetXIC, record the current composition mode 606 so that it can be restored later. */ 607 savedCompositionState = getCompositionState(); 608 boolean active = haveActiveClient(); 609 if (active && composedText == null && committedText == null){ 610 needResetXIC = true; 611 needResetXICClient = new WeakReference<>(getClientComponent()); 612 return; 613 } 614 615 String text = resetXIC(); 616 /* needResetXIC is only set to true for active client. So passive 617 client should not reset the flag to false. */ 618 if (active) { 619 needResetXIC = false; 620 } 621 622 // Remove any existing composed text by posting an InputMethodEvent 623 // with null composed text. It would be desirable to wait for a 624 // dispatchComposedText call from X input method engine, but some 625 // input method does not conform to the XIM specification and does 626 // not call the preedit callback to erase preedit text on calling 627 // XmbResetIC. To work around this problem, do it here by ourselves. 628 awtLock(); 629 try { 630 composedText = null; 631 postInputMethodEvent(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED, 632 null, 633 0, 634 null, 635 null); 636 637 if (text != null && text.length() > 0) { 638 dispatchCommittedText(text); 639 } 640 } finally { 641 // Put awtUnlock into finally block in case an exception is thrown. 642 awtUnlock(); 643 } 644 645 // Restore the preedit state if it was enabled 646 if (savedCompositionState) { 647 resetCompositionState(); 648 } 649 } 650 651 /** 652 * Returns a string with information about the current input method server, or null. 653 * On both Linux & SunOS, the value of environment variable XMODIFIERS is 654 * returned if set. Otherwise, on SunOS, $HOME/.dtprofile will be parsed 655 * to find out the language service engine (atok or wnn) since there is 656 * no API in Xlib which returns the information of native 657 * IM server or language service and we want to try our best to return as much 658 * information as possible. 659 * 660 * Note: This method could return null on Linux if XMODIFIERS is not set properly or 661 * if any IOException is thrown. 662 * See man page of XSetLocaleModifiers(3X11) for the usgae of XMODIFIERS, 663 * atok12setup(1) and wnn6setup(1) for the information written to 664 * $HOME/.dtprofile when you run these two commands. 665 * 666 */ getNativeInputMethodInfo()667 public String getNativeInputMethodInfo() { 668 String xmodifiers = System.getenv("XMODIFIERS"); 669 String imInfo = null; 670 671 // If XMODIFIERS is set, return the value 672 if (xmodifiers != null) { 673 int imIndex = xmodifiers.indexOf("@im="); 674 if (imIndex != -1) { 675 imInfo = xmodifiers.substring(imIndex + 4); 676 } 677 } 678 679 return imInfo; 680 } 681 682 683 /** 684 * Performs mapping from an XIM visible feedback value to Java IM highlight. 685 * @return Java input method highlight 686 */ convertVisualFeedbackToHighlight(int feedback)687 protected InputMethodHighlight convertVisualFeedbackToHighlight(int feedback) { 688 InputMethodHighlight highlight; 689 690 switch (feedback) { 691 case XIMUnderline: 692 highlight = InputMethodHighlight.UNSELECTED_CONVERTED_TEXT_HIGHLIGHT; 693 break; 694 case XIMReverse: 695 highlight = InputMethodHighlight.SELECTED_CONVERTED_TEXT_HIGHLIGHT; 696 break; 697 case XIMHighlight: 698 highlight = InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT; 699 break; 700 case 0: //None of the values are set by Wnn 701 case XIMPrimary: 702 highlight = InputMethodHighlight.UNSELECTED_CONVERTED_TEXT_HIGHLIGHT; 703 break; 704 case XIMSecondary: 705 highlight = InputMethodHighlight.SELECTED_CONVERTED_TEXT_HIGHLIGHT; 706 break; 707 case XIMTertiary: 708 highlight = InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT; 709 break; 710 default: 711 highlight = InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT; 712 break; 713 } 714 return highlight; 715 } 716 717 // initial capacity size for string buffer, etc. 718 protected static final int INITIAL_SIZE = 64; 719 720 /** 721 * IntBuffer is an inner class that manipulates an int array and 722 * provides UNIX file io stream-like programming interfaces to 723 * access it. (An alternative would be to use ArrayList which may 724 * be too expensive for the work.) 725 */ 726 protected final class IntBuffer { 727 private int[] intArray; 728 private int size; 729 private int index; 730 IntBuffer(int initialCapacity)731 IntBuffer(int initialCapacity) { 732 intArray = new int[initialCapacity]; 733 size = 0; 734 index = 0; 735 } 736 insert(int offset, int[] values)737 void insert(int offset, int[] values) { 738 int newSize = size + values.length; 739 if (intArray.length < newSize) { 740 int[] newIntArray = new int[newSize * 2]; 741 System.arraycopy(intArray, 0, newIntArray, 0, size); 742 intArray = newIntArray; 743 } 744 System.arraycopy(intArray, offset, intArray, offset+values.length, 745 size - offset); 746 System.arraycopy(values, 0, intArray, offset, values.length); 747 size += values.length; 748 if (index > offset) 749 index = offset; 750 } 751 remove(int offset, int length)752 void remove(int offset, int length) { 753 if (offset + length != size) 754 System.arraycopy(intArray, offset+length, intArray, offset, 755 size - offset - length); 756 size -= length; 757 if (index > offset) 758 index = offset; 759 } 760 replace(int offset, int[] values)761 void replace(int offset, int[] values) { 762 System.arraycopy(values, 0, intArray, offset, values.length); 763 } 764 removeAll()765 void removeAll() { 766 size = 0; 767 index = 0; 768 } 769 rewind()770 void rewind() { 771 index = 0; 772 } 773 getNext()774 int getNext() { 775 if (index == size) 776 return -1; 777 return intArray[index++]; 778 } 779 unget()780 void unget() { 781 if (index != 0) 782 index--; 783 } 784 getOffset()785 int getOffset() { 786 return index; 787 } 788 toString()789 public String toString() { 790 StringBuffer s = new StringBuffer(); 791 for (int i = 0; i < size;) { 792 s.append(intArray[i++]); 793 if (i < size) 794 s.append(","); 795 } 796 return s.toString(); 797 } 798 } 799 800 /* 801 * Native methods 802 */ 803 804 /** 805 * Initialize JNI field and method IDs for fields that may be 806 * accessed from C. 807 */ initIDs()808 private static native void initIDs(); 809 turnoffStatusWindow()810 protected native void turnoffStatusWindow(); 811 disposeXIC()812 protected native void disposeXIC(); 813 resetXIC()814 private native String resetXIC(); 815 setCompositionEnabledNative(boolean enable)816 protected native boolean setCompositionEnabledNative(boolean enable); 817 isCompositionEnabledNative()818 private native boolean isCompositionEnabledNative(); 819 } 820