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