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 #include "jlong.h"
  27 #include "awtmsg.h"
  28 #include "awt_AWTEvent.h"
  29 #include "awt_Component.h"
  30 #include "awt_Toolkit.h"
  31 #include "locale_str.h"
  32 #include <sun_awt_windows_WInputMethod.h>
  33 #include <sun_awt_windows_WInputMethodDescriptor.h>
  34 #include <java_awt_event_InputMethodEvent.h>
  35 
  36 const UINT SYSCOMMAND_IMM = 0xF000 - 100;
  37 
  38 /************************************************************************
  39  * WInputMethod native methods
  40  */
  41 
  42 extern "C" {
  43 
  44 jobject CreateLocaleObject(JNIEnv *env, const char * name);
  45 HKL getDefaultKeyboardLayout();
  46 
  47 extern BOOL g_bUserHasChangedInputLang;
  48 
  49 /*
  50  * Class:     sun_awt_windows_WInputMethod
  51  * Method:    createNativeContext
  52  * Signature: ()I
  53  */
  54 JNIEXPORT jint JNICALL
  55 Java_sun_awt_windows_WInputMethod_createNativeContext(JNIEnv *env, jobject self)
  56 {
  57     TRY;
  58 
  59     // use special message to call ImmCreateContext() in main thread.
  60     return (jint)AwtToolkit::GetInstance().SendMessage(WM_AWT_CREATECONTEXT);
  61 
  62     CATCH_BAD_ALLOC_RET(0);
  63 }
  64 
  65 
  66 /*
  67  * Class:     sun_awt_windows_WInputMethod
  68  * Method:    destroyNativeContext
  69  * Signature: (I)V
  70  */
  71 JNIEXPORT void JNICALL
  72 Java_sun_awt_windows_WInputMethod_destroyNativeContext(JNIEnv *env, jobject self, jint context)
  73 {
  74     TRY_NO_VERIFY;
  75 
  76     // use special message to call ImmDestroyContext() in main thread.
  77     AwtToolkit::GetInstance().SendMessage(WM_AWT_DESTROYCONTEXT, context, 0);
  78 
  79     CATCH_BAD_ALLOC;
  80 }
  81 
  82 
  83 /*
  84  * Class:     sun_awt_windows_WInputMethod
  85  * Method:    enableNativeIME
  86  * Signature: (Lsun/awt/windows/WComponentPeer;I)V
  87  */
  88 JNIEXPORT void JNICALL
  89 Java_sun_awt_windows_WInputMethod_enableNativeIME(JNIEnv *env, jobject self, jobject peer,
  90                                                   jint context, jboolean useNativeCompWindow)
  91 {
  92     TRY;
  93 
  94     jobject selfGlobalRef = env->NewGlobalRef(self);
  95     jobject peerGlobalRef = env->NewGlobalRef(peer);
  96 
  97     EnableNativeIMEStruct *enis = new EnableNativeIMEStruct;
  98 
  99     enis->self = selfGlobalRef;
 100     enis->peer = peerGlobalRef;
 101     enis->context = context;
 102     enis->useNativeCompWindow = useNativeCompWindow;
 103 
 104     AwtToolkit::GetInstance().SendMessage(WM_AWT_ASSOCIATECONTEXT,
 105                                           reinterpret_cast<WPARAM>(enis), (LPARAM)0);
 106     // global refs are deleted in message handler
 107 
 108     CATCH_BAD_ALLOC;
 109 }
 110 
 111 
 112 /*
 113  * Class:     sun_awt_windows_WInputMethod
 114  * Method:    disableNativeIME
 115  * Signature: (Lsun/awt/windows/WComponentPeer;)V
 116  */
 117 JNIEXPORT void JNICALL
 118 Java_sun_awt_windows_WInputMethod_disableNativeIME(JNIEnv *env, jobject self, jobject peer)
 119 {
 120     TRY_NO_VERIFY;
 121 
 122     jobject peerGlobalRef = env->NewGlobalRef(peer);
 123     // self reference is not used
 124 
 125     EnableNativeIMEStruct *enis = new EnableNativeIMEStruct;
 126     enis->self = NULL;
 127     enis->peer = peerGlobalRef;
 128     enis->context = NULL;
 129     enis->useNativeCompWindow = JNI_TRUE;
 130 
 131     AwtToolkit::GetInstance().SendMessage(WM_AWT_ASSOCIATECONTEXT,
 132                                           reinterpret_cast<WPARAM>(enis), (LPARAM)0);
 133     // global refs are deleted in message handler
 134 
 135     CATCH_BAD_ALLOC;
 136 }
 137 
 138 
 139 /*
 140  * Class:     sun_awt_windows_WComponentPeer
 141  * Method:    handleEvent
 142  * Signature: (Lsun/awt/windows/WComponentPeer;Ljava/awt/AWTEvent;)V
 143  */
 144 JNIEXPORT void JNICALL
 145 Java_sun_awt_windows_WInputMethod_handleNativeIMEEvent(JNIEnv *env, jobject self,
 146                                                        jobject peer, jobject event)
 147 {
 148     TRY;
 149 
 150     PDATA pData;
 151     JNI_CHECK_PEER_RETURN(peer);
 152     AwtComponent* p = (AwtComponent *)pData;
 153 
 154     JNI_CHECK_NULL_RETURN(event, "null AWTEvent");
 155     if (env->EnsureLocalCapacity(1) < 0) {
 156         return;
 157     }
 158     jbyteArray bdata = (jbyteArray)(env)->GetObjectField(event, AwtAWTEvent::bdataID);
 159     if (bdata == 0) {
 160         return;
 161     }
 162     MSG msg;
 163     (env)->GetByteArrayRegion(bdata, 0, sizeof(MSG), (jbyte *)&msg);
 164     (env)->DeleteLocalRef(bdata);
 165     BOOL isConsumed =
 166       (BOOL)(env)->GetBooleanField(event, AwtAWTEvent::consumedID);
 167     int id = (env)->GetIntField(event, AwtAWTEvent::idID);
 168     DASSERT(!safe_ExceptionOccurred(env));
 169 
 170     if (isConsumed || p==NULL)  return;
 171 
 172     if (id >= java_awt_event_InputMethodEvent_INPUT_METHOD_FIRST &&
 173         id <= java_awt_event_InputMethodEvent_INPUT_METHOD_LAST)
 174     {
 175         jobject peerGlobalRef = env->NewGlobalRef(peer);
 176 
 177         // use special message to access pData on the toolkit thread
 178         AwtToolkit::GetInstance().SendMessage(WM_AWT_HANDLE_NATIVE_IME_EVENT,
 179                                               reinterpret_cast<WPARAM>(peerGlobalRef),
 180                                               reinterpret_cast<LPARAM>(&msg));
 181         // global ref is deleted in message handler
 182 
 183         (env)->SetBooleanField(event, AwtAWTEvent::consumedID, JNI_TRUE);
 184     }
 185 
 186     CATCH_BAD_ALLOC;
 187 }
 188 
 189 /*
 190  * Class:     sun_awt_windows_WInputMethod
 191  * Method:    notifyNativeIME
 192  * Signature: (Lsun/awt/windows/WComponentPeer;I)V
 193  */
 194 JNIEXPORT void JNICALL
 195 Java_sun_awt_windows_WInputMethod_endCompositionNative(JNIEnv *env, jobject self,
 196                                                        jint context, jboolean flag)
 197 {
 198     TRY;
 199 
 200     // TODO: currently the flag parameter is ignored and the outstanding input is
 201     //       always discarded.
 202     //       If the flag value is Java_sun_awt_windows_WInputMethod_COMMIT_INPUT,
 203     //       then input text should be committed. Otherwise, should be discarded.
 204     //
 205     // 10/29/98 - Changed to commit it according to the flag.
 206 
 207     // use special message to call ImmNotifyIME() in main thread.
 208     AwtToolkit::GetInstance().SendMessage(WM_AWT_ENDCOMPOSITION, context,
 209         (LPARAM)(flag != sun_awt_windows_WInputMethod_DISCARD_INPUT));
 210 
 211     CATCH_BAD_ALLOC;
 212 }
 213 
 214 /*
 215  * Class:     sun_awt_windows_WInputMethod
 216  * Method:    setConversionStatus
 217  * Signature: (II)V
 218  */
 219 JNIEXPORT void JNICALL
 220 Java_sun_awt_windows_WInputMethod_setConversionStatus(JNIEnv *env, jobject self, jint context, jint request)
 221 {
 222     TRY;
 223 
 224     // use special message to call ImmSetConversionStatus() in main thread.
 225     AwtToolkit::GetInstance().SendMessage(WM_AWT_SETCONVERSIONSTATUS,
 226                                           context,
 227                                           MAKELPARAM((WORD)request, (WORD)0));
 228 
 229     CATCH_BAD_ALLOC;
 230 }
 231 
 232 /*
 233  * Class:     sun_awt_windows_WInputMethod
 234  * Method:    getConversionStatus
 235  * Signature: (I)I
 236  */
 237 JNIEXPORT jint JNICALL
 238 Java_sun_awt_windows_WInputMethod_getConversionStatus(JNIEnv *env, jobject self, jint context)
 239 {
 240     TRY;
 241 
 242     // use special message to call ImmSetConversionStatus() in main thread.
 243     return (jint) AwtToolkit::GetInstance().SendMessage(
 244         WM_AWT_GETCONVERSIONSTATUS, context, 0);
 245 
 246     CATCH_BAD_ALLOC_RET(0);
 247 }
 248 
 249 /*
 250  * Class:     sun_awt_windows_WInputMethod
 251  * Method:    setOpenStatus
 252  * Signature: (IZ)V
 253  */
 254 JNIEXPORT void JNICALL
 255 Java_sun_awt_windows_WInputMethod_setOpenStatus(JNIEnv *env, jobject self, jint context, jboolean flag)
 256 {
 257     TRY;
 258 
 259     // use special message to call ImmSetConversionStatus() in main thread.
 260     AwtToolkit::GetInstance().SendMessage(WM_AWT_SETOPENSTATUS,
 261                                           context, flag);
 262 
 263     CATCH_BAD_ALLOC;
 264 }
 265 
 266 /*
 267  * Class:     sun_awt_windows_WInputMethod
 268  * Method:    getConversionStatus
 269  * Signature: (I)Z
 270  */
 271 JNIEXPORT jboolean JNICALL
 272 Java_sun_awt_windows_WInputMethod_getOpenStatus(JNIEnv *env, jobject self, jint context)
 273 {
 274     TRY;
 275 
 276     // use special message to call ImmSetConversionStatus() in main thread.
 277     return (jboolean)(AwtToolkit::GetInstance().SendMessage(
 278                                                        WM_AWT_GETOPENSTATUS,
 279                                                        context, 0));
 280     CATCH_BAD_ALLOC_RET(0);
 281 }
 282 
 283 /*
 284  * Class:     sun_awt_windows_WInputMethod
 285  * Method:    getNativeLocale
 286  * Signature: ()Ljava/util/Locale;
 287  */
 288 JNIEXPORT jobject JNICALL Java_sun_awt_windows_WInputMethod_getNativeLocale
 289   (JNIEnv *env, jclass cls)
 290 {
 291     TRY;
 292 
 293     const char * javaLocaleName = getJavaIDFromLangID(AwtComponent::GetInputLanguage());
 294     if (javaLocaleName != NULL) {
 295         // Now WInputMethod.currentLocale and AwtComponent::m_idLang are get sync'ed,
 296         // so we can reset this flag.
 297         g_bUserHasChangedInputLang = FALSE;
 298 
 299         jobject ret = CreateLocaleObject(env, javaLocaleName);
 300         free((void *)javaLocaleName);
 301         return ret;
 302     } else {
 303         return NULL;
 304     }
 305 
 306     CATCH_BAD_ALLOC_RET(NULL);
 307 }
 308 
 309 /*
 310  * Class:     sun_awt_windows_WInputMethod
 311  * Method:    setNativeLocale
 312  * Signature: (Ljava/lang/String;Z)Z
 313  */
 314 JNIEXPORT jboolean JNICALL Java_sun_awt_windows_WInputMethod_setNativeLocale
 315   (JNIEnv *env, jclass cls, jstring localeString, jboolean onActivate)
 316 {
 317     TRY;
 318 
 319     // check if current language ID is the requested one.  Note that the
 320     // current language ID (returned from 'getJavaIDFromLangID') is in
 321     // ASCII encoding, so we use 'GetStringUTFChars' to retrieve requested
 322     // language ID from the 'localeString' object.
 323     jboolean isCopy;
 324     const char * requested = env->GetStringUTFChars(localeString, &isCopy);
 325     CHECK_NULL_RETURN(requested, JNI_FALSE);
 326 
 327     const char * current = getJavaIDFromLangID(AwtComponent::GetInputLanguage());
 328     if (current != NULL) {
 329         if (strcmp(current, requested) == 0) {
 330             env->ReleaseStringUTFChars(localeString, requested);
 331             free((void *)current);
 332             return JNI_TRUE;
 333         }
 334         free((void *)current);
 335     }
 336 
 337     // get list of available HKLs.  Adding the user's preferred layout on top of the layout
 338     // list which is returned by GetKeyboardLayoutList ensures to match first when
 339     // looking up suitable layout.
 340     int layoutCount = ::GetKeyboardLayoutList(0, NULL) + 1;  // +1 for user's preferred HKL
 341     HKL FAR * hKLList = (HKL FAR *)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, sizeof(HKL), layoutCount);
 342     if (hKLList == NULL) {
 343         env->ReleaseStringUTFChars(localeString, requested);
 344         return JNI_FALSE;
 345     }
 346     ::GetKeyboardLayoutList(layoutCount - 1, &(hKLList[1]));
 347     hKLList[0] = getDefaultKeyboardLayout(); // put user's preferred layout on top of the list
 348 
 349     // lookup matching LangID
 350     jboolean retValue = JNI_FALSE;
 351     for (int i = 0; i < layoutCount; i++) {
 352         const char * supported = getJavaIDFromLangID(LOWORD(hKLList[i]));
 353         if (supported != NULL) {
 354             if (strcmp(supported, requested) == 0) {
 355                 // use special message to call ActivateKeyboardLayout() in main thread.
 356                 if (AwtToolkit::GetInstance().SendMessage(WM_AWT_ACTIVATEKEYBOARDLAYOUT, (WPARAM)onActivate, (LPARAM)hKLList[i])) {
 357                     //also need to change the same keyboard layout for the Java AWT-EventQueue thread
 358                     AwtToolkit::activateKeyboardLayout(hKLList[i]);
 359                     retValue = JNI_TRUE;
 360                 }
 361                 free((void *)supported);
 362                 break;
 363             }
 364             free((void *)supported);
 365         }
 366     }
 367 
 368     env->ReleaseStringUTFChars(localeString, requested);
 369     free(hKLList);
 370     return retValue;
 371 
 372     CATCH_BAD_ALLOC_RET(JNI_FALSE);
 373 }
 374 
 375 /*
 376  * Class:     sun_awt_windows_WInputMethod
 377  * Method:    hideWindowsNative
 378  * Signature: (Lsun/awt/windows/WComponentPeer;Z)V
 379  */
 380 JNIEXPORT void JNICALL Java_sun_awt_windows_WInputMethod_setStatusWindowVisible
 381   (JNIEnv *env, jobject self, jobject peer, jboolean visible)
 382 {
 383     /* Retrieve the default input method Window handler from AwtToolkit.
 384        Windows system creates a default input method window for the
 385        toolkit thread.
 386     */
 387 
 388     HWND defaultIMEHandler = AwtToolkit::GetInstance().GetInputMethodWindow();
 389 
 390     if (defaultIMEHandler == NULL)
 391     {
 392         jobject peerGlobalRef = env->NewGlobalRef(peer);
 393 
 394         // use special message to access pData on the toolkit thread
 395         LRESULT res = AwtToolkit::GetInstance().SendMessage(WM_AWT_GET_DEFAULT_IME_HANDLER,
 396                                           reinterpret_cast<WPARAM>(peerGlobalRef), 0);
 397         // global ref is deleted in message handler
 398 
 399         if (res == TRUE) {
 400             defaultIMEHandler = AwtToolkit::GetInstance().GetInputMethodWindow();
 401         }
 402     }
 403 
 404     if (defaultIMEHandler != NULL) {
 405         ::SendMessage(defaultIMEHandler, WM_IME_CONTROL,
 406                       visible ? IMC_OPENSTATUSWINDOW : IMC_CLOSESTATUSWINDOW, 0);
 407     }
 408 }
 409 
 410 /*
 411  * Class:     sun_awt_windows_WInputMethod
 412  * Method:    openCandidateWindow
 413  * Signature: (Lsun/awt/windows/WComponentPeer;II)V
 414  */
 415 JNIEXPORT void JNICALL Java_sun_awt_windows_WInputMethod_openCandidateWindow
 416   (JNIEnv *env, jobject self, jobject peer, jint x, jint y)
 417 {
 418     TRY;
 419 
 420     PDATA pData;
 421     JNI_CHECK_PEER_RETURN(peer);
 422 
 423     jobject peerGlobalRef = env->NewGlobalRef(peer);
 424 
 425     // WARNING! MAKELONG macro treats the given values as unsigned.
 426     //   This may lead to some bugs in multiscreen configurations, as
 427     //   coordinates can be negative numbers. So, while handling
 428     //   WM_AWT_OPENCANDIDATEWINDOW message in AwtToolkit, we should
 429     //   carefully extract right x and y values using GET_X_LPARAM and
 430     //   GET_Y_LPARAM, not LOWORD and HIWORD
 431     // See CR 4805862, AwtToolkit::WndProc
 432 
 433     // use special message to open candidate window in main thread.
 434     AwtToolkit::GetInstance().SendMessage(WM_AWT_OPENCANDIDATEWINDOW,
 435                                           (WPARAM)peerGlobalRef, MAKELONG(x, y));
 436     // global ref is deleted in message handler
 437 
 438     CATCH_BAD_ALLOC;
 439 }
 440 
 441 
 442 /************************************************************************
 443  * WInputMethodDescriptor native methods
 444  */
 445 
 446 /*
 447  * Class:     sun_awt_windows_WInputMethodDescriptor
 448  * Method:    getNativeAvailableLocales
 449  * Signature: ()[Ljava/util/Locale;
 450  */
 451 JNIEXPORT jobjectArray JNICALL Java_sun_awt_windows_WInputMethodDescriptor_getNativeAvailableLocales
 452   (JNIEnv *env, jclass self)
 453 {
 454     TRY;
 455 
 456     // get list of available HKLs
 457     const int layoutCount = ::GetKeyboardLayoutList(0, NULL);
 458     HKL FAR * hKLList = (HKL FAR *)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, sizeof(HKL), layoutCount);
 459     CHECK_NULL_RETURN(hKLList, NULL);
 460     ::GetKeyboardLayoutList(layoutCount, hKLList);
 461 
 462     // get list of Java locale names while getting rid of duplicates
 463     int srcIndex = 0;
 464     int destIndex = 0;
 465     int javaLocaleNameCount = 0;
 466     int current = 0;
 467 
 468     const char ** javaLocaleNames = (const char **)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, sizeof(char *), layoutCount);
 469     if (javaLocaleNames == NULL) {
 470         free(hKLList);
 471         return NULL;
 472     }
 473 
 474     for (; srcIndex < layoutCount; srcIndex++) {
 475         const char * srcLocaleName = getJavaIDFromLangID(LOWORD(hKLList[srcIndex]));
 476 
 477         if (srcLocaleName == NULL) {
 478             // could not find corresponding Java locale name for this HKL.
 479             continue;
 480         }
 481 
 482         for (current = 0; current < destIndex; current++) {
 483             if (strcmp(javaLocaleNames[current], srcLocaleName) == 0) {
 484                 // duplicated. ignore this HKL
 485                 free((void *)srcLocaleName);
 486                 break;
 487             }
 488         }
 489 
 490         if (current == destIndex) {
 491             javaLocaleNameCount++;
 492             destIndex++;
 493             javaLocaleNames[current] = srcLocaleName;
 494         }
 495     }
 496 
 497     jobjectArray locales = NULL;
 498     // convert it to an array of Java locale objects
 499     jclass localeClass = env->FindClass("java/util/Locale");
 500     if (localeClass != NULL) {
 501         locales = env->NewObjectArray(javaLocaleNameCount, localeClass, NULL);
 502         if (locales != NULL) {
 503 
 504             for (current = 0; current < javaLocaleNameCount; current++) {
 505                 jobject obj = CreateLocaleObject(env, javaLocaleNames[current]);
 506                 if (env->ExceptionCheck()) {
 507                     env->DeleteLocalRef(locales);
 508                     locales = NULL;
 509                     break;
 510                 }
 511                 env->SetObjectArrayElement(locales,
 512                                            current,
 513                                            obj);
 514             }
 515 
 516         }
 517         env->DeleteLocalRef(localeClass);
 518     }
 519 
 520     for (current = 0; current < javaLocaleNameCount; current++) {
 521         free((void *)javaLocaleNames[current]);
 522     }
 523 
 524     free(hKLList);
 525     free(javaLocaleNames);
 526     return locales;
 527 
 528     CATCH_BAD_ALLOC_RET(NULL);
 529 }
 530 
 531 /*
 532  * Class:     sun_awt_windows_WInputMethod
 533  * Method:    isCompositionStringAvailable
 534  * Signature: (I)Z
 535  */
 536 JNIEXPORT jboolean JNICALL Java_sun_awt_windows_WInputMethod_isCompositionStringAvailable
 537   (JNIEnv *env, jobject self, jint context)
 538 {
 539     LONG length;
 540     length = ImmGetCompositionString((HIMC)IntToPtr(context), GCS_COMPSTR, NULL, 0);
 541     if (length > 0) {
 542         return JNI_TRUE;
 543     } else {
 544         return JNI_FALSE;
 545     }
 546 }
 547 
 548 /**
 549  * Class:     sun_awt_windows_WInputMethod
 550  * Method:    getNativeIMMDescription
 551  * Signature: ()Ljava/lang/String;
 552  *
 553  * This method tries to get the information about the input method associated with
 554  * the current active thread.
 555  *
 556  */
 557 JNIEXPORT jstring JNICALL Java_sun_awt_windows_WInputMethod_getNativeIMMDescription
 558   (JNIEnv *env, jobject self) {
 559 
 560     TRY;
 561 
 562     // Get the keyboard layout of the active thread.
 563     HKL hkl = AwtComponent::GetKeyboardLayout();
 564     LPTSTR szImmDescription = NULL;
 565     UINT buffSize = 0;
 566     jstring infojStr = NULL;
 567 
 568     if ((buffSize = ::ImmGetDescription(hkl, szImmDescription, 0)) > 0) {
 569         szImmDescription = (LPTSTR) SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, (buffSize+1), sizeof(TCHAR));
 570 
 571         if (szImmDescription != NULL) {
 572             ImmGetDescription(hkl, szImmDescription, (buffSize+1));
 573 
 574             infojStr = JNU_NewStringPlatform(env, szImmDescription);
 575 
 576             free(szImmDescription);
 577         }
 578     }
 579 
 580     return infojStr;
 581 
 582     CATCH_BAD_ALLOC_RET(NULL);
 583 }
 584 
 585 /*
 586  * Create a Java locale object from its name string
 587  */
 588 jobject CreateLocaleObject(JNIEnv *env, const char * name)
 589 {
 590     TRY;
 591 
 592     // create Locale object
 593     jobject langtagObj = env->NewStringUTF(name);
 594     CHECK_NULL_RETURN(langtagObj, NULL);
 595     jobject localeObj = JNU_CallStaticMethodByName(env,
 596                                                    NULL,
 597                                                    "java/util/Locale",
 598                                                    "forLanguageTag",
 599                                                    "(Ljava/lang/String;)Ljava/util/Locale;",
 600                                                    langtagObj).l;
 601     env->DeleteLocalRef(langtagObj);
 602 
 603     return localeObj;
 604 
 605     CATCH_BAD_ALLOC_RET(NULL);
 606 }
 607 
 608 
 609 /*
 610  * Gets user's preferred keyboard layout
 611  * Warning: This is version dependent code
 612  */
 613 HKL getDefaultKeyboardLayout() {
 614     LONG ret;
 615     HKL hkl = 0;
 616     HKEY hKey;
 617     BYTE szHKL[16];
 618     DWORD cbHKL = 16;
 619     LPTSTR end;
 620 
 621     ret = ::RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Keyboard Layout\\Preload"), NULL, KEY_READ, &hKey);
 622 
 623     if (ret == ERROR_SUCCESS) {
 624         ret = ::RegQueryValueEx(hKey, TEXT("1"), 0, 0, szHKL, &cbHKL);
 625 
 626         if (ret == ERROR_SUCCESS) {
 627             hkl = reinterpret_cast<HKL>(static_cast<INT_PTR>(
 628                 _tcstoul((LPCTSTR)szHKL, &end, 16)));
 629         }
 630 
 631         ::RegCloseKey(hKey);
 632     }
 633 
 634     return hkl;
 635 }
 636 } /* extern "C" */