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