1 /*
   2  * Copyright (c) 1997, 2014, 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 
  27 package sun.awt.windows;
  28 
  29 import java.awt.*;
  30 import java.awt.peer.*;
  31 import java.awt.event.*;
  32 import java.awt.im.*;
  33 import java.awt.im.spi.InputMethodContext;
  34 import java.awt.font.*;
  35 import java.text.*;
  36 import java.text.AttributedCharacterIterator.Attribute;
  37 import java.lang.Character.Subset;
  38 import java.lang.Character.UnicodeBlock;
  39 import java.util.Collections;
  40 import java.util.HashMap;
  41 import java.util.Locale;
  42 import java.util.Map;
  43 import sun.awt.im.InputMethodAdapter;
  44 
  45 final class WInputMethod extends InputMethodAdapter
  46 {
  47     /**
  48      * The input method context, which is used to dispatch input method
  49      * events to the client component and to request information from
  50      * the client component.
  51      */
  52     private InputMethodContext inputContext;
  53 
  54     private Component awtFocussedComponent;
  55     private WComponentPeer awtFocussedComponentPeer = null;
  56     private WComponentPeer lastFocussedComponentPeer = null;
  57     private boolean isLastFocussedActiveClient = false;
  58     private boolean isActive;
  59     private int context;
  60     private boolean open; //default open status;
  61     private int cmode;    //default conversion mode;
  62     private Locale currentLocale;
  63     // indicate whether status window is hidden or not.
  64     private boolean statusWindowHidden = false;
  65 
  66     // attribute definition in Win32 (in IMM.H)
  67     public final static byte ATTR_INPUT                 = 0x00;
  68     public final static byte ATTR_TARGET_CONVERTED      = 0x01;
  69     public final static byte ATTR_CONVERTED             = 0x02;
  70     public final static byte ATTR_TARGET_NOTCONVERTED   = 0x03;
  71     public final static byte ATTR_INPUT_ERROR           = 0x04;
  72     // cmode definition in Win32 (in IMM.H)
  73     public final static int  IME_CMODE_ALPHANUMERIC     = 0x0000;
  74     public final static int  IME_CMODE_NATIVE           = 0x0001;
  75     public final static int  IME_CMODE_KATAKANA         = 0x0002;
  76     public final static int  IME_CMODE_LANGUAGE         = 0x0003;
  77     public final static int  IME_CMODE_FULLSHAPE        = 0x0008;
  78     public final static int  IME_CMODE_HANJACONVERT     = 0x0040;
  79     public final static int  IME_CMODE_ROMAN            = 0x0010;
  80 
  81     // flag values for endCompositionNative() behavior
  82     private final static boolean COMMIT_INPUT           = true;
  83     private final static boolean DISCARD_INPUT          = false;
  84 
  85     private static Map<TextAttribute,Object> [] highlightStyles;
  86 
  87     // Initialize highlight mapping table
  88     static {
  89         @SuppressWarnings({"rawtypes", "unchecked"})
  90         Map<TextAttribute,Object> styles[] = new Map[4];
  91         HashMap<TextAttribute,Object> map;
  92 
  93         // UNSELECTED_RAW_TEXT_HIGHLIGHT
  94         map = new HashMap<>(1);
  95         map.put(TextAttribute.INPUT_METHOD_UNDERLINE, TextAttribute.UNDERLINE_LOW_DOTTED);
  96         styles[0] = Collections.unmodifiableMap(map);
  97 
  98         // SELECTED_RAW_TEXT_HIGHLIGHT
  99         map = new HashMap<>(1);
 100         map.put(TextAttribute.INPUT_METHOD_UNDERLINE, TextAttribute.UNDERLINE_LOW_GRAY);
 101         styles[1] = Collections.unmodifiableMap(map);
 102 
 103         // UNSELECTED_CONVERTED_TEXT_HIGHLIGHT
 104         map = new HashMap<>(1);
 105         map.put(TextAttribute.INPUT_METHOD_UNDERLINE, TextAttribute.UNDERLINE_LOW_DOTTED);
 106         styles[2] = Collections.unmodifiableMap(map);
 107 
 108         // SELECTED_CONVERTED_TEXT_HIGHLIGHT
 109         map = new HashMap<>(4);
 110         Color navyBlue = new Color(0, 0, 128);
 111         map.put(TextAttribute.FOREGROUND, navyBlue);
 112         map.put(TextAttribute.BACKGROUND, Color.white);
 113         map.put(TextAttribute.SWAP_COLORS, TextAttribute.SWAP_COLORS_ON);
 114         map.put(TextAttribute.INPUT_METHOD_UNDERLINE, TextAttribute.UNDERLINE_LOW_ONE_PIXEL);
 115         styles[3] = Collections.unmodifiableMap(map);
 116 
 117         highlightStyles = styles;
 118     }
 119 
 120     public WInputMethod()
 121     {
 122         context = createNativeContext();
 123         cmode = getConversionStatus(context);
 124         open = getOpenStatus(context);
 125         currentLocale = getNativeLocale();
 126         if (currentLocale == null) {
 127             currentLocale = Locale.getDefault();
 128         }
 129     }
 130 
 131     @Override
 132     protected void finalize() throws Throwable
 133     {
 134         // Release the resources used by the native input context.
 135         if (context!=0) {
 136             destroyNativeContext(context);
 137             context=0;
 138         }
 139         super.finalize();
 140     }
 141 
 142     @Override
 143     public synchronized void setInputMethodContext(InputMethodContext context) {
 144         inputContext = context;
 145     }
 146 
 147     @Override
 148     public void dispose() {
 149         // Due to a memory management problem in Windows 98, we should retain
 150         // the native input context until this object is finalized. So do
 151         // nothing here.
 152     }
 153 
 154     /**
 155      * Returns null.
 156      *
 157      * @see java.awt.im.spi.InputMethod#getControlObject
 158      */
 159     @Override
 160     public Object getControlObject() {
 161         return null;
 162     }
 163 
 164     @Override
 165     public boolean setLocale(Locale lang) {
 166         return setLocale(lang, false);
 167     }
 168 
 169     private boolean setLocale(Locale lang, boolean onActivate) {
 170         Locale[] available = WInputMethodDescriptor.getAvailableLocalesInternal();
 171         for (int i = 0; i < available.length; i++) {
 172             Locale locale = available[i];
 173             if (lang.equals(locale) ||
 174                     // special compatibility rule for Japanese and Korean
 175                     locale.equals(Locale.JAPAN) && lang.equals(Locale.JAPANESE) ||
 176                     locale.equals(Locale.KOREA) && lang.equals(Locale.KOREAN)) {
 177                 if (isActive) {
 178                     setNativeLocale(locale.toLanguageTag(), onActivate);
 179                 }
 180                 currentLocale = locale;
 181                 return true;
 182             }
 183         }
 184         return false;
 185     }
 186 
 187     @Override
 188     public Locale getLocale() {
 189         if (isActive) {
 190             currentLocale = getNativeLocale();
 191             if (currentLocale == null) {
 192                 currentLocale = Locale.getDefault();
 193             }
 194         }
 195         return currentLocale;
 196     }
 197 
 198     /**
 199      * Implements InputMethod.setCharacterSubsets for Windows.
 200      *
 201      * @see java.awt.im.spi.InputMethod#setCharacterSubsets
 202      */
 203     @Override
 204     public void setCharacterSubsets(Subset[] subsets) {
 205         if (subsets == null){
 206             setConversionStatus(context, cmode);
 207             setOpenStatus(context, open);
 208             return;
 209         }
 210 
 211         // Use first subset only. Other subsets in array is ignored.
 212         // This is restriction of Win32 implementation.
 213         Subset subset1 = subsets[0];
 214 
 215         Locale locale = getNativeLocale();
 216         int newmode;
 217 
 218         if (locale == null) {
 219             return;
 220         }
 221 
 222         if (locale.getLanguage().equals(Locale.JAPANESE.getLanguage())) {
 223             if (subset1 == UnicodeBlock.BASIC_LATIN || subset1 == InputSubset.LATIN_DIGITS) {
 224                 setOpenStatus(context, false);
 225             } else {
 226                 if (subset1 == UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
 227                     || subset1 == InputSubset.KANJI
 228                     || subset1 == UnicodeBlock.HIRAGANA)
 229                     newmode = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE;
 230                 else if (subset1 == UnicodeBlock.KATAKANA)
 231                     newmode = IME_CMODE_NATIVE | IME_CMODE_KATAKANA| IME_CMODE_FULLSHAPE;
 232                 else if (subset1 == InputSubset.HALFWIDTH_KATAKANA)
 233                     newmode = IME_CMODE_NATIVE | IME_CMODE_KATAKANA;
 234                 else if (subset1 == InputSubset.FULLWIDTH_LATIN)
 235                     newmode = IME_CMODE_FULLSHAPE;
 236                 else
 237                     return;
 238                 setOpenStatus(context, true);
 239                 newmode |= (getConversionStatus(context)&IME_CMODE_ROMAN);   // reserve ROMAN input mode
 240                 setConversionStatus(context, newmode);
 241             }
 242         } else if (locale.getLanguage().equals(Locale.KOREAN.getLanguage())) {
 243             if (subset1 == UnicodeBlock.BASIC_LATIN || subset1 == InputSubset.LATIN_DIGITS) {
 244                 setOpenStatus(context, false);
 245             } else {
 246                 if (subset1 == UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
 247                     || subset1 == InputSubset.HANJA
 248                     || subset1 == UnicodeBlock.HANGUL_SYLLABLES
 249                     || subset1 == UnicodeBlock.HANGUL_JAMO
 250                     || subset1 == UnicodeBlock.HANGUL_COMPATIBILITY_JAMO)
 251                     newmode = IME_CMODE_NATIVE;
 252                 else if (subset1 == InputSubset.FULLWIDTH_LATIN)
 253                     newmode = IME_CMODE_FULLSHAPE;
 254                 else
 255                     return;
 256                 setOpenStatus(context, true);
 257                 setConversionStatus(context, newmode);
 258             }
 259         } else if (locale.getLanguage().equals(Locale.CHINESE.getLanguage())) {
 260             if (subset1 == UnicodeBlock.BASIC_LATIN || subset1 == InputSubset.LATIN_DIGITS) {
 261                 setOpenStatus(context, false);
 262             } else {
 263                 if (subset1 == UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
 264                     || subset1 == InputSubset.TRADITIONAL_HANZI
 265                     || subset1 == InputSubset.SIMPLIFIED_HANZI)
 266                     newmode = IME_CMODE_NATIVE;
 267                 else if (subset1 == InputSubset.FULLWIDTH_LATIN)
 268                     newmode = IME_CMODE_FULLSHAPE;
 269                 else
 270                     return;
 271                 setOpenStatus(context, true);
 272                 setConversionStatus(context, newmode);
 273             }
 274         }
 275     }
 276 
 277     @Override
 278     public void dispatchEvent(AWTEvent e) {
 279         if (e instanceof ComponentEvent) {
 280             Component comp = ((ComponentEvent) e).getComponent();
 281             if (comp == awtFocussedComponent) {
 282                 if (awtFocussedComponentPeer == null ||
 283                     awtFocussedComponentPeer.isDisposed()) {
 284                     awtFocussedComponentPeer = getNearestNativePeer(comp);
 285                 }
 286                 if (awtFocussedComponentPeer != null) {
 287                     handleNativeIMEEvent(awtFocussedComponentPeer, e);
 288                 }
 289             }
 290         }
 291     }
 292 
 293     @Override
 294     public void activate() {
 295         boolean isAc = haveActiveClient();
 296 
 297         // When the last focussed component peer is different from the
 298         // current focussed component or if they are different client
 299         // (active or passive), disable native IME for the old focussed
 300         // component and enable for the new one.
 301         if (lastFocussedComponentPeer != awtFocussedComponentPeer ||
 302             isLastFocussedActiveClient != isAc) {
 303             if (lastFocussedComponentPeer != null) {
 304                 disableNativeIME(lastFocussedComponentPeer);
 305             }
 306             if (awtFocussedComponentPeer != null) {
 307                 enableNativeIME(awtFocussedComponentPeer, context, !isAc);
 308             }
 309             lastFocussedComponentPeer = awtFocussedComponentPeer;
 310             isLastFocussedActiveClient = isAc;
 311         }
 312         isActive = true;
 313         if (currentLocale != null) {
 314             setLocale(currentLocale, true);
 315         }
 316 
 317         /* If the status window or Windows language bar is turned off due to
 318            native input method was switched to java input method, we
 319            have to turn it on otherwise it is gone for good until next time
 320            the user turns it on through Windows Control Panel. See details
 321            from bug 6252674.
 322         */
 323         if (statusWindowHidden) {
 324             setStatusWindowVisible(awtFocussedComponentPeer, true);
 325             statusWindowHidden = false;
 326         }
 327 
 328     }
 329 
 330     @Override
 331     public void deactivate(boolean isTemporary)
 332     {
 333         // Sync currentLocale with the Windows keyboard layout which might be changed
 334         // by hot key
 335         getLocale();
 336 
 337         // Delay calling disableNativeIME until activate is called and the newly
 338         // focussed component has a different peer as the last focussed component.
 339         if (awtFocussedComponentPeer != null) {
 340             lastFocussedComponentPeer = awtFocussedComponentPeer;
 341             isLastFocussedActiveClient = haveActiveClient();
 342         }
 343         isActive = false;
 344     }
 345 
 346     /**
 347      * Explicitly disable the native IME. Native IME is not disabled when
 348      * deactivate is called.
 349      */
 350     @Override
 351     public void disableInputMethod() {
 352         if (lastFocussedComponentPeer != null) {
 353             disableNativeIME(lastFocussedComponentPeer);
 354             lastFocussedComponentPeer = null;
 355             isLastFocussedActiveClient = false;
 356         }
 357     }
 358 
 359     /**
 360      * Returns a string with information about the windows input method,
 361      * or null.
 362      */
 363     @Override
 364     public String getNativeInputMethodInfo() {
 365         return getNativeIMMDescription();
 366     }
 367 
 368      /**
 369      * @see sun.awt.im.InputMethodAdapter#stopListening
 370      * This method is called when the input method is swapped out.
 371      * Calling stopListening to give other input method the keybaord input
 372      * focus.
 373      */
 374     @Override
 375     protected void stopListening() {
 376         // Since the native input method is not disabled when deactivate is
 377         // called, we need to call disableInputMethod to explicitly turn off the
 378         // native IME.
 379         disableInputMethod();
 380     }
 381 
 382     // implements sun.awt.im.InputMethodAdapter.setAWTFocussedComponent
 383     @Override
 384     protected void setAWTFocussedComponent(Component component) {
 385         if (component == null) {
 386             return;
 387         }
 388         WComponentPeer peer = getNearestNativePeer(component);
 389         if (isActive) {
 390             // deactivate/activate are being suppressed during a focus change -
 391             // this may happen when an input method window is made visible
 392             if (awtFocussedComponentPeer != null) {
 393                 disableNativeIME(awtFocussedComponentPeer);
 394             }
 395             if (peer != null) {
 396                 enableNativeIME(peer, context, !haveActiveClient());
 397             }
 398         }
 399         awtFocussedComponent = component;
 400         awtFocussedComponentPeer = peer;
 401     }
 402 
 403     // implements java.awt.im.spi.InputMethod.hideWindows
 404     @Override
 405     public void hideWindows() {
 406         if (awtFocussedComponentPeer != null) {
 407             /* Hide the native status window including the Windows language
 408                bar if it is on. One typical senario this method
 409                gets called is when the native input method is
 410                switched to java input method, for example.
 411             */
 412             setStatusWindowVisible(awtFocussedComponentPeer, false);
 413             statusWindowHidden = true;
 414         }
 415     }
 416 
 417     /**
 418      * @see java.awt.im.spi.InputMethod#removeNotify
 419      */
 420     @Override
 421     public void removeNotify() {
 422         endCompositionNative(context, DISCARD_INPUT);
 423         awtFocussedComponent = null;
 424         awtFocussedComponentPeer = null;
 425     }
 426 
 427     /**
 428      * @see java.awt.Toolkit#mapInputMethodHighlight
 429      */
 430     static Map<TextAttribute,?> mapInputMethodHighlight(InputMethodHighlight highlight) {
 431         int index;
 432         int state = highlight.getState();
 433         if (state == InputMethodHighlight.RAW_TEXT) {
 434             index = 0;
 435         } else if (state == InputMethodHighlight.CONVERTED_TEXT) {
 436             index = 2;
 437         } else {
 438             return null;
 439         }
 440         if (highlight.isSelected()) {
 441             index += 1;
 442         }
 443         return highlightStyles[index];
 444     }
 445 
 446     // see sun.awt.im.InputMethodAdapter.supportsBelowTheSpot
 447     @Override
 448     protected boolean supportsBelowTheSpot() {
 449         return true;
 450     }
 451 
 452     @Override
 453     public void endComposition()
 454     {
 455         //right now the native endCompositionNative() just cancel
 456         //the composition string, maybe a commtting is desired
 457         endCompositionNative(context,
 458             (haveActiveClient() ? COMMIT_INPUT : DISCARD_INPUT));
 459     }
 460 
 461     /**
 462      * @see java.awt.im.spi.InputMethod#setCompositionEnabled(boolean)
 463      */
 464     @Override
 465     public void setCompositionEnabled(boolean enable) {
 466         setOpenStatus(context, enable);
 467     }
 468 
 469     /**
 470      * @see java.awt.im.spi.InputMethod#isCompositionEnabled
 471      */
 472     @Override
 473     public boolean isCompositionEnabled() {
 474         return getOpenStatus(context);
 475     }
 476 
 477     public void sendInputMethodEvent(int id, long when, String text,
 478                                      int[] clauseBoundary, String[] clauseReading,
 479                                      int[] attributeBoundary, byte[] attributeValue,
 480                                      int commitedTextLength, int caretPos, int visiblePos)
 481     {
 482 
 483         AttributedCharacterIterator iterator = null;
 484 
 485         if (text!=null) {
 486 
 487             // construct AttributedString
 488             AttributedString attrStr = new AttributedString(text);
 489 
 490             // set Language Information
 491             attrStr.addAttribute(Attribute.LANGUAGE,
 492                                             Locale.getDefault(), 0, text.length());
 493 
 494             // set Clause and Reading Information
 495             if (clauseBoundary!=null && clauseReading!=null &&
 496                 clauseReading.length!=0 && clauseBoundary.length==clauseReading.length+1 &&
 497                 clauseBoundary[0]==0 && clauseBoundary[clauseReading.length]==text.length() )
 498             {
 499                 for (int i=0; i<clauseBoundary.length-1; i++) {
 500                     attrStr.addAttribute(Attribute.INPUT_METHOD_SEGMENT,
 501                                             new Annotation(null), clauseBoundary[i], clauseBoundary[i+1]);
 502                     attrStr.addAttribute(Attribute.READING,
 503                                             new Annotation(clauseReading[i]), clauseBoundary[i], clauseBoundary[i+1]);
 504                 }
 505             } else {
 506                 // if (clauseBoundary != null)
 507                 //    System.out.println("Invalid clause information!");
 508 
 509                 attrStr.addAttribute(Attribute.INPUT_METHOD_SEGMENT,
 510                                         new Annotation(null), 0, text.length());
 511                 attrStr.addAttribute(Attribute.READING,
 512                                      new Annotation(""), 0, text.length());
 513             }
 514 
 515             // set Hilight Information
 516             if (attributeBoundary!=null && attributeValue!=null &&
 517                 attributeValue.length!=0 && attributeBoundary.length==attributeValue.length+1 &&
 518                 attributeBoundary[0]==0 && attributeBoundary[attributeValue.length]==text.length() )
 519             {
 520                 for (int i=0; i<attributeBoundary.length-1; i++) {
 521                     InputMethodHighlight highlight;
 522                     switch (attributeValue[i]) {
 523                         case ATTR_TARGET_CONVERTED:
 524                             highlight = InputMethodHighlight.SELECTED_CONVERTED_TEXT_HIGHLIGHT;
 525                             break;
 526                         case ATTR_CONVERTED:
 527                             highlight = InputMethodHighlight.UNSELECTED_CONVERTED_TEXT_HIGHLIGHT;
 528                             break;
 529                         case ATTR_TARGET_NOTCONVERTED:
 530                             highlight = InputMethodHighlight.SELECTED_RAW_TEXT_HIGHLIGHT;
 531                             break;
 532                         case ATTR_INPUT:
 533                         case ATTR_INPUT_ERROR:
 534                         default:
 535                             highlight = InputMethodHighlight.UNSELECTED_RAW_TEXT_HIGHLIGHT;
 536                             break;
 537                     }
 538                     attrStr.addAttribute(TextAttribute.INPUT_METHOD_HIGHLIGHT,
 539                                          highlight,
 540                                          attributeBoundary[i], attributeBoundary[i+1]);
 541                 }
 542             } else {
 543                 // if (attributeBoundary != null)
 544                 //    System.out.println("Invalid attribute information!");
 545 
 546                 attrStr.addAttribute(TextAttribute.INPUT_METHOD_HIGHLIGHT,
 547                              InputMethodHighlight.UNSELECTED_CONVERTED_TEXT_HIGHLIGHT,
 548                              0, text.length());
 549             }
 550 
 551             // get iterator
 552             iterator = attrStr.getIterator();
 553 
 554         }
 555 
 556         Component source = getClientComponent();
 557         if (source == null)
 558             return;
 559 
 560         InputMethodEvent event = new InputMethodEvent(source,
 561                                                       id,
 562                                                       when,
 563                                                       iterator,
 564                                                       commitedTextLength,
 565                                                       TextHitInfo.leading(caretPos),
 566                                                       TextHitInfo.leading(visiblePos));
 567         WToolkit.postEvent(WToolkit.targetToAppContext(source), event);
 568     }
 569 
 570     public void inquireCandidatePosition()
 571     {
 572         Component source = getClientComponent();
 573         if (source == null) {
 574             return;
 575         }
 576         // This call should return immediately just to cause
 577         // InputMethodRequests.getTextLocation be called within
 578         // AWT Event thread.  Otherwise, a potential deadlock
 579         // could happen.
 580         Runnable r = new Runnable() {
 581             @Override
 582             public void run() {
 583                 int x = 0;
 584                 int y = 0;
 585                 Component client = getClientComponent();
 586 
 587                 if (client != null) {
 588                     if (haveActiveClient()) {
 589                             Rectangle rc = inputContext.getTextLocation(TextHitInfo.leading(0));
 590                             x = rc.x;
 591                             y = rc.y + rc.height;
 592                     } else {
 593                             Point pt = client.getLocationOnScreen();
 594                             Dimension size = client.getSize();
 595                             x = pt.x;
 596                             y = pt.y + size.height;
 597                     }
 598                 }
 599 
 600                 openCandidateWindow(awtFocussedComponentPeer, x, y);
 601             }
 602         };
 603         WToolkit.postEvent(WToolkit.targetToAppContext(source),
 604                            new InvocationEvent(source, r));
 605     }
 606 
 607     // java.awt.Toolkit#getNativeContainer() is not available
 608     //  from this package
 609     @SuppressWarnings("deprecation")
 610     private WComponentPeer getNearestNativePeer(Component comp)
 611     {
 612         if (comp==null)     return null;
 613 
 614         ComponentPeer peer = comp.getPeer();
 615         if (peer==null)     return null;
 616 
 617         while (peer instanceof java.awt.peer.LightweightPeer) {
 618             comp = comp.getParent();
 619             if (comp==null) return null;
 620             peer = comp.getPeer();
 621             if (peer==null) return null;
 622         }
 623 
 624         if (peer instanceof WComponentPeer)
 625             return (WComponentPeer)peer;
 626         else
 627             return null;
 628 
 629     }
 630 
 631     private native int createNativeContext();
 632     private native void destroyNativeContext(int context);
 633     private native void enableNativeIME(WComponentPeer peer, int context, boolean useNativeCompWindow);
 634     private native void disableNativeIME(WComponentPeer peer);
 635     private native void handleNativeIMEEvent(WComponentPeer peer, AWTEvent e);
 636     private native void endCompositionNative(int context, boolean flag);
 637     private native void setConversionStatus(int context, int cmode);
 638     private native int  getConversionStatus(int context);
 639     private native void setOpenStatus(int context, boolean flag);
 640     private native boolean getOpenStatus(int context);
 641     private native void setStatusWindowVisible(WComponentPeer peer, boolean visible);
 642     private native String getNativeIMMDescription();
 643     static native Locale getNativeLocale();
 644     static native boolean setNativeLocale(String localeName, boolean onActivate);
 645     private native void openCandidateWindow(WComponentPeer peer, int x, int y);
 646 }