1 /* 2 * Copyright (c) 1997, 2018, 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.equals("")) { 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 } else if (System.getProperty("os.name").startsWith("SunOS")) { 678 File dtprofile = new File(System.getProperty("user.home") + 679 "/.dtprofile"); 680 String languageEngineInfo = null; 681 try { 682 BufferedReader br = new BufferedReader(new FileReader(dtprofile)); 683 String line = null; 684 685 while ( languageEngineInfo == null && (line = br.readLine()) != null) { 686 if (line.contains("atok") || line.contains("wnn")) { 687 StringTokenizer tokens = new StringTokenizer(line); 688 while (tokens.hasMoreTokens()) { 689 String token = tokens.nextToken(); 690 if (Pattern.matches("atok.*setup", token) || 691 Pattern.matches("wnn.*setup", token)){ 692 languageEngineInfo = token.substring(0, token.indexOf("setup")); 693 break; 694 } 695 } 696 } 697 } 698 699 br.close(); 700 } catch(IOException ioex) { 701 // Since this method is provided for internal testing only, 702 // we dump the stack trace for the ease of debugging. 703 ioex.printStackTrace(); 704 } 705 706 imInfo = "htt " + languageEngineInfo; 707 } 708 709 return imInfo; 710 } 711 712 713 /** 714 * Performs mapping from an XIM visible feedback value to Java IM highlight. 715 * @return Java input method highlight 716 */ convertVisualFeedbackToHighlight(int feedback)717 protected InputMethodHighlight convertVisualFeedbackToHighlight(int feedback) { 718 InputMethodHighlight highlight; 719 720 switch (feedback) { 721 case XIMUnderline: 722 highlight = InputMethodHighlight.UNSELECTED_CONVERTED_TEXT_HIGHLIGHT; 723 break; 724 case XIMReverse: 725 highlight = InputMethodHighlight.SELECTED_CONVERTED_TEXT_HIGHLIGHT; 726 break; 727 case XIMHighlight: 728 highlight = InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT; 729 break; 730 case 0: //None of the values are set by Wnn 731 case XIMPrimary: 732 highlight = InputMethodHighlight.UNSELECTED_CONVERTED_TEXT_HIGHLIGHT; 733 break; 734 case XIMSecondary: 735 highlight = InputMethodHighlight.SELECTED_CONVERTED_TEXT_HIGHLIGHT; 736 break; 737 case XIMTertiary: 738 highlight = InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT; 739 break; 740 default: 741 highlight = InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT; 742 break; 743 } 744 return highlight; 745 } 746 747 // initial capacity size for string buffer, etc. 748 protected static final int INITIAL_SIZE = 64; 749 750 /** 751 * IntBuffer is an inner class that manipulates an int array and 752 * provides UNIX file io stream-like programming interfaces to 753 * access it. (An alternative would be to use ArrayList which may 754 * be too expensive for the work.) 755 */ 756 protected final class IntBuffer { 757 private int[] intArray; 758 private int size; 759 private int index; 760 IntBuffer(int initialCapacity)761 IntBuffer(int initialCapacity) { 762 intArray = new int[initialCapacity]; 763 size = 0; 764 index = 0; 765 } 766 insert(int offset, int[] values)767 void insert(int offset, int[] values) { 768 int newSize = size + values.length; 769 if (intArray.length < newSize) { 770 int[] newIntArray = new int[newSize * 2]; 771 System.arraycopy(intArray, 0, newIntArray, 0, size); 772 intArray = newIntArray; 773 } 774 System.arraycopy(intArray, offset, intArray, offset+values.length, 775 size - offset); 776 System.arraycopy(values, 0, intArray, offset, values.length); 777 size += values.length; 778 if (index > offset) 779 index = offset; 780 } 781 remove(int offset, int length)782 void remove(int offset, int length) { 783 if (offset + length != size) 784 System.arraycopy(intArray, offset+length, intArray, offset, 785 size - offset - length); 786 size -= length; 787 if (index > offset) 788 index = offset; 789 } 790 replace(int offset, int[] values)791 void replace(int offset, int[] values) { 792 System.arraycopy(values, 0, intArray, offset, values.length); 793 } 794 removeAll()795 void removeAll() { 796 size = 0; 797 index = 0; 798 } 799 rewind()800 void rewind() { 801 index = 0; 802 } 803 getNext()804 int getNext() { 805 if (index == size) 806 return -1; 807 return intArray[index++]; 808 } 809 unget()810 void unget() { 811 if (index != 0) 812 index--; 813 } 814 getOffset()815 int getOffset() { 816 return index; 817 } 818 toString()819 public String toString() { 820 StringBuffer s = new StringBuffer(); 821 for (int i = 0; i < size;) { 822 s.append(intArray[i++]); 823 if (i < size) 824 s.append(","); 825 } 826 return s.toString(); 827 } 828 } 829 830 /* 831 * Native methods 832 */ 833 834 /** 835 * Initialize JNI field and method IDs for fields that may be 836 * accessed from C. 837 */ initIDs()838 private static native void initIDs(); 839 turnoffStatusWindow()840 protected native void turnoffStatusWindow(); 841 disposeXIC()842 protected native void disposeXIC(); 843 resetXIC()844 private native String resetXIC(); 845 setCompositionEnabledNative(boolean enable)846 protected native boolean setCompositionEnabledNative(boolean enable); 847 isCompositionEnabledNative()848 private native boolean isCompositionEnabledNative(); 849 } 850