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