1 /* 2 * PROJECT: ReactOS Win32k subsystem 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: win32ss/user/ntuser/kbdlayout.c 5 * PURPOSE: Keyboard layout management 6 * COPYRIGHT: Copyright 2007 Saveliy Tretiakov 7 * Copyright 2008 Colin Finck 8 * Copyright 2011 Rafal Harabien 9 */ 10 11 #include <win32k.h> 12 13 // Was included only because of CP_ACP and required the 14 // definition of SYSTEMTIME in ndk\rtltypes.h 15 //#include <winnls.h> 16 #define CP_ACP 0 17 18 DBG_DEFAULT_CHANNEL(UserKbdLayout); 19 20 PKL gspklBaseLayout = NULL; 21 PKBDFILE gpkfList = NULL; 22 DWORD gSystemFS = 0; 23 UINT gSystemCPCharSet = 0; 24 25 typedef PVOID (*PFN_KBDLAYERDESCRIPTOR)(VOID); 26 27 28 /* PRIVATE FUNCTIONS ******************************************************/ 29 30 #if 0 && DBG 31 32 static VOID 33 DumpKbdLayout( 34 IN PKBDTABLES pKbdTbl) 35 { 36 PVK_TO_BIT pVkToBit; 37 PVK_TO_WCHAR_TABLE pVkToWchTbl; 38 PVSC_VK pVscVk; 39 ULONG i; 40 41 DbgPrint("Kbd layout: fLocaleFlags %x bMaxVSCtoVK %x\n", 42 pKbdTbl->fLocaleFlags, pKbdTbl->bMaxVSCtoVK); 43 DbgPrint("wMaxModBits %x\n", 44 pKbdTbl->pCharModifiers ? pKbdTbl->pCharModifiers->wMaxModBits 45 : 0); 46 47 if (pKbdTbl->pCharModifiers) 48 { 49 pVkToBit = pKbdTbl->pCharModifiers->pVkToBit; 50 if (pVkToBit) 51 { 52 for (; pVkToBit->Vk; ++pVkToBit) 53 { 54 DbgPrint("VkToBit %x -> %x\n", pVkToBit->Vk, pVkToBit->ModBits); 55 } 56 } 57 58 for (i = 0; i <= pKbdTbl->pCharModifiers->wMaxModBits; ++i) 59 { 60 DbgPrint("ModNumber %x -> %x\n", i, pKbdTbl->pCharModifiers->ModNumber[i]); 61 } 62 } 63 64 pVkToWchTbl = pKbdTbl->pVkToWcharTable; 65 if (pVkToWchTbl) 66 { 67 for (; pVkToWchTbl->pVkToWchars; ++pVkToWchTbl) 68 { 69 PVK_TO_WCHARS1 pVkToWch = pVkToWchTbl->pVkToWchars; 70 71 DbgPrint("pVkToWchTbl nModifications %x cbSize %x\n", 72 pVkToWchTbl->nModifications, pVkToWchTbl->cbSize); 73 if (pVkToWch) 74 { 75 while (pVkToWch->VirtualKey) 76 { 77 DbgPrint("pVkToWch VirtualKey %x Attributes %x wc { ", 78 pVkToWch->VirtualKey, pVkToWch->Attributes); 79 for (i = 0; i < pVkToWchTbl->nModifications; ++i) 80 { 81 DbgPrint("%x ", pVkToWch->wch[i]); 82 } 83 DbgPrint("}\n"); 84 pVkToWch = (PVK_TO_WCHARS1)(((PBYTE)pVkToWch) + pVkToWchTbl->cbSize); 85 } 86 } 87 } 88 } 89 90 // TODO: DeadKeys, KeyNames, KeyNamesExt, KeyNamesDead 91 92 DbgPrint("pusVSCtoVK: { "); 93 if (pKbdTbl->pusVSCtoVK) 94 { 95 for (i = 0; i < pKbdTbl->bMaxVSCtoVK; ++i) 96 { 97 DbgPrint("%x -> %x, ", i, pKbdTbl->pusVSCtoVK[i]); 98 } 99 } 100 DbgPrint("}\n"); 101 102 DbgPrint("pVSCtoVK_E0: { "); 103 pVscVk = pKbdTbl->pVSCtoVK_E0; 104 if (pVscVk) 105 { 106 for (; pVscVk->Vsc; ++pVscVk) 107 { 108 DbgPrint("%x -> %x, ", pVscVk->Vsc, pVscVk->Vk); 109 } 110 } 111 DbgPrint("}\n"); 112 113 DbgPrint("pVSCtoVK_E1: { "); 114 pVscVk = pKbdTbl->pVSCtoVK_E1; 115 if (pVscVk) 116 { 117 for (; pVscVk->Vsc; ++pVscVk) 118 { 119 DbgPrint("%x -> %x, ", pVscVk->Vsc, pVscVk->Vk); 120 } 121 } 122 DbgPrint("}\n"); 123 124 // TODO: Ligatures 125 } 126 127 #endif // DBG 128 129 130 /* 131 * UserLoadKbdDll 132 * 133 * Loads keyboard layout DLL and gets address to KbdTables 134 */ 135 static BOOL 136 UserLoadKbdDll(WCHAR *pwszLayoutPath, 137 HANDLE *phModule, 138 PKBDTABLES *pKbdTables) 139 { 140 PFN_KBDLAYERDESCRIPTOR pfnKbdLayerDescriptor; 141 142 /* Load keyboard layout DLL */ 143 TRACE("Loading Keyboard DLL %ws\n", pwszLayoutPath); 144 *phModule = EngLoadImage(pwszLayoutPath); 145 if (!(*phModule)) 146 { 147 ERR("Failed to load dll %ws\n", pwszLayoutPath); 148 return FALSE; 149 } 150 151 /* Find KbdLayerDescriptor function and get layout tables */ 152 TRACE("Loaded %ws\n", pwszLayoutPath); 153 pfnKbdLayerDescriptor = EngFindImageProcAddress(*phModule, "KbdLayerDescriptor"); 154 155 /* FIXME: Windows reads file instead of executing! 156 It's not safe to kbdlayout DLL in kernel mode! */ 157 158 if (pfnKbdLayerDescriptor) 159 *pKbdTables = pfnKbdLayerDescriptor(); 160 else 161 ERR("Error: %ws has no KbdLayerDescriptor()\n", pwszLayoutPath); 162 163 if (!pfnKbdLayerDescriptor || !*pKbdTables) 164 { 165 ERR("Failed to load the keyboard layout.\n"); 166 EngUnloadImage(*phModule); 167 return FALSE; 168 } 169 170 #if 0 && DBG 171 /* Dump keyboard layout */ 172 DumpKbdLayout(*pKbdTables); 173 #endif 174 175 return TRUE; 176 } 177 178 /* 179 * UserLoadKbdFile 180 * 181 * Loads keyboard layout DLL and creates KBDFILE object 182 */ 183 static PKBDFILE 184 UserLoadKbdFile(PUNICODE_STRING pwszKLID) 185 { 186 PKBDFILE pkf, pRet = NULL; 187 NTSTATUS Status; 188 ULONG cbSize; 189 HKEY hKey = NULL; 190 WCHAR wszLayoutPath[MAX_PATH] = L"\\SystemRoot\\System32\\"; 191 WCHAR wszLayoutRegKey[256] = L"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\" 192 L"Control\\Keyboard Layouts\\"; 193 194 /* Create keyboard layout file object */ 195 pkf = UserCreateObject(gHandleTable, NULL, NULL, NULL, TYPE_KBDFILE, sizeof(KBDFILE)); 196 if (!pkf) 197 { 198 ERR("Failed to create object!\n"); 199 return NULL; 200 } 201 202 /* Set keyboard layout name */ 203 swprintf(pkf->awchKF, L"%wZ", pwszKLID); 204 205 /* Open layout registry key */ 206 RtlStringCbCatW(wszLayoutRegKey, sizeof(wszLayoutRegKey), pkf->awchKF); 207 Status = RegOpenKey(wszLayoutRegKey, &hKey); 208 if (!NT_SUCCESS(Status)) 209 { 210 ERR("Failed to open keyboard layouts registry key %ws (%lx)\n", wszLayoutRegKey, Status); 211 goto cleanup; 212 } 213 214 /* Read filename of layout DLL */ 215 cbSize = (ULONG)(sizeof(wszLayoutPath) - wcslen(wszLayoutPath)*sizeof(WCHAR)); 216 Status = RegQueryValue(hKey, 217 L"Layout File", 218 REG_SZ, 219 wszLayoutPath + wcslen(wszLayoutPath), 220 &cbSize); 221 222 if (!NT_SUCCESS(Status)) 223 { 224 ERR("Can't get layout filename for %wZ (%lx)\n", pwszKLID, Status); 225 goto cleanup; 226 } 227 228 /* Load keyboard file now */ 229 if (!UserLoadKbdDll(wszLayoutPath, &pkf->hBase, &pkf->pKbdTbl)) 230 { 231 ERR("Failed to load %ws dll!\n", wszLayoutPath); 232 goto cleanup; 233 } 234 235 /* Update next field */ 236 pkf->pkfNext = gpkfList; 237 gpkfList = pkf; 238 239 /* Return keyboard file */ 240 pRet = pkf; 241 242 cleanup: 243 if (hKey) 244 ZwClose(hKey); 245 if (pkf) 246 UserDereferenceObject(pkf); // we dont need ptr anymore 247 if (!pRet) 248 { 249 /* We have failed - destroy created object */ 250 if (pkf) 251 UserDeleteObject(pkf->head.h, TYPE_KBDFILE); 252 } 253 254 return pRet; 255 } 256 257 /* 258 * UserLoadKbdLayout 259 * 260 * Loads keyboard layout and creates KL object 261 */ 262 static PKL 263 UserLoadKbdLayout(PUNICODE_STRING pustrKLID, HKL hKL) 264 { 265 LCID lCid; 266 CHARSETINFO cs; 267 PKL pKl; 268 269 /* Create keyboard layout object */ 270 pKl = UserCreateObject(gHandleTable, NULL, NULL, NULL, TYPE_KBDLAYOUT, sizeof(KL)); 271 if (!pKl) 272 { 273 ERR("Failed to create object!\n"); 274 return NULL; 275 } 276 277 pKl->hkl = hKL; 278 pKl->spkf = UserLoadKbdFile(pustrKLID); 279 280 /* Dereference keyboard layout */ 281 UserDereferenceObject(pKl); 282 283 /* If we failed, remove KL object */ 284 if (!pKl->spkf) 285 { 286 ERR("UserLoadKbdFile(%wZ) failed!\n", pustrKLID); 287 UserDeleteObject(pKl->head.h, TYPE_KBDLAYOUT); 288 return NULL; 289 } 290 291 // Up to Language Identifiers.. 292 if (!NT_SUCCESS(RtlUnicodeStringToInteger(pustrKLID, 16, (PULONG)&lCid))) 293 { 294 ERR("RtlUnicodeStringToInteger failed for '%wZ'\n", pustrKLID); 295 UserDeleteObject(pKl->head.h, TYPE_KBDLAYOUT); 296 return NULL; 297 } 298 299 TRACE("Language Identifiers %wZ LCID 0x%x\n", pustrKLID, lCid); 300 if (co_IntGetCharsetInfo(lCid, &cs)) 301 { 302 pKl->iBaseCharset = cs.ciCharset; 303 pKl->dwFontSigs = cs.fs.fsCsb[0]; 304 pKl->CodePage = (USHORT)cs.ciACP; 305 TRACE("Charset %u Font Sig %lu CodePage %u\n", 306 pKl->iBaseCharset, pKl->dwFontSigs, pKl->CodePage); 307 } 308 else 309 { 310 pKl->iBaseCharset = ANSI_CHARSET; 311 pKl->dwFontSigs = FS_LATIN1; 312 pKl->CodePage = CP_ACP; 313 } 314 315 // Set initial system character set and font signature. 316 if (gSystemFS == 0) 317 { 318 gSystemCPCharSet = pKl->iBaseCharset; 319 gSystemFS = pKl->dwFontSigs; 320 } 321 322 return pKl; 323 } 324 325 /* 326 * UnloadKbdFile 327 * 328 * Destroys specified Keyboard File object 329 */ 330 static 331 VOID 332 UnloadKbdFile(_In_ PKBDFILE pkf) 333 { 334 PKBDFILE *ppkfLink = &gpkfList; 335 NT_ASSERT(pkf != NULL); 336 337 /* Find previous object */ 338 while (*ppkfLink) 339 { 340 if (*ppkfLink == pkf) 341 break; 342 343 ppkfLink = &(*ppkfLink)->pkfNext; 344 } 345 346 if (*ppkfLink == pkf) 347 *ppkfLink = pkf->pkfNext; 348 349 EngUnloadImage(pkf->hBase); 350 UserDeleteObject(pkf->head.h, TYPE_KBDFILE); 351 } 352 353 /* 354 * UserUnloadKbl 355 * 356 * Unloads specified Keyboard Layout if possible 357 */ 358 BOOL 359 UserUnloadKbl(PKL pKl) 360 { 361 /* According to msdn, UnloadKeyboardLayout can fail 362 if the keyboard layout identifier was preloaded. */ 363 if (pKl == gspklBaseLayout) 364 { 365 if (pKl->pklNext == pKl->pklPrev) 366 { 367 /* There is only one layout */ 368 return FALSE; 369 } 370 371 /* Set next layout as default */ 372 gspklBaseLayout = pKl->pklNext; 373 } 374 375 if (pKl->head.cLockObj > 1) 376 { 377 /* Layout is used by other threads */ 378 pKl->dwKL_Flags |= KLF_UNLOAD; 379 return FALSE; 380 } 381 382 /* Unload the layout */ 383 pKl->pklPrev->pklNext = pKl->pklNext; 384 pKl->pklNext->pklPrev = pKl->pklPrev; 385 UnloadKbdFile(pKl->spkf); 386 UserDeleteObject(pKl->head.h, TYPE_KBDLAYOUT); 387 return TRUE; 388 } 389 390 /* 391 * W32kGetDefaultKeyLayout 392 * 393 * Returns default layout for new threads 394 */ 395 PKL 396 W32kGetDefaultKeyLayout(VOID) 397 { 398 PKL pKl = gspklBaseLayout; 399 400 if (!pKl) 401 return NULL; 402 403 /* Return not unloaded layout */ 404 do 405 { 406 if (!(pKl->dwKL_Flags & KLF_UNLOAD)) 407 return pKl; 408 409 pKl = pKl->pklPrev; /* Confirmed on Win2k */ 410 } while(pKl != gspklBaseLayout); 411 412 /* We have not found proper KL */ 413 return NULL; 414 } 415 416 /* 417 * UserHklToKbl 418 * 419 * Gets KL object from hkl value 420 */ 421 PKL 422 NTAPI 423 UserHklToKbl(HKL hKl) 424 { 425 PKL pKl = gspklBaseLayout; 426 427 if (!gspklBaseLayout) 428 return NULL; 429 430 do 431 { 432 if (pKl->hkl == hKl) 433 return pKl; 434 435 pKl = pKl->pklNext; 436 } while (pKl != gspklBaseLayout); 437 438 return NULL; 439 } 440 441 /* 442 * UserSetDefaultInputLang 443 * 444 * Sets default kyboard layout for system. Called from UserSystemParametersInfo. 445 */ 446 BOOL 447 NTAPI 448 UserSetDefaultInputLang(HKL hKl) 449 { 450 PKL pKl; 451 452 pKl = UserHklToKbl(hKl); 453 if (!pKl) 454 return FALSE; 455 456 gspklBaseLayout = pKl; 457 return TRUE; 458 } 459 460 /* 461 * co_UserActivateKbl 462 * 463 * Activates given layout in specified thread 464 */ 465 static PKL 466 co_UserActivateKbl(PTHREADINFO pti, PKL pKl, UINT Flags) 467 { 468 PKL pklPrev; 469 PWND pWnd; 470 471 pklPrev = pti->KeyboardLayout; 472 if (pklPrev) 473 UserDereferenceObject(pklPrev); 474 475 pti->KeyboardLayout = pKl; 476 pti->pClientInfo->hKL = pKl->hkl; 477 UserReferenceObject(pKl); 478 479 if (Flags & KLF_SETFORPROCESS) 480 { 481 // FIXME 482 } 483 484 if (!(pWnd = pti->MessageQueue->spwndFocus)) 485 { 486 pWnd = pti->MessageQueue->spwndActive; 487 } 488 489 // Send WM_INPUTLANGCHANGE to thread's focus window 490 co_IntSendMessage( pWnd ? UserHMGetHandle(pWnd) : 0, 491 WM_INPUTLANGCHANGE, 492 (WPARAM)pKl->iBaseCharset, // FIXME: How to set it? 493 (LPARAM)pKl->hkl); // hkl 494 495 return pklPrev; 496 } 497 498 /* EXPORTS *******************************************************************/ 499 500 /* 501 * UserGetKeyboardLayout 502 * 503 * Returns hkl of given thread keyboard layout 504 */ 505 HKL FASTCALL 506 UserGetKeyboardLayout( 507 DWORD dwThreadId) 508 { 509 PTHREADINFO pti; 510 PLIST_ENTRY ListEntry; 511 PKL pKl; 512 513 pti = PsGetCurrentThreadWin32Thread(); 514 515 if (!dwThreadId) 516 { 517 pKl = pti->KeyboardLayout; 518 return pKl ? pKl->hkl : NULL; 519 } 520 521 ListEntry = pti->rpdesk->PtiList.Flink; 522 523 // 524 // Search the Desktop Thread list for related Desktop active Threads. 525 // 526 while(ListEntry != &pti->rpdesk->PtiList) 527 { 528 pti = CONTAINING_RECORD(ListEntry, THREADINFO, PtiLink); 529 530 if (PsGetThreadId(pti->pEThread) == UlongToHandle(dwThreadId)) 531 { 532 pKl = pti->KeyboardLayout; 533 return pKl ? pKl->hkl : NULL; 534 } 535 536 ListEntry = ListEntry->Flink; 537 } 538 539 return NULL; 540 } 541 542 /* 543 * NtUserGetKeyboardLayoutList 544 * 545 * Returns list of loaded keyboard layouts in system 546 */ 547 UINT 548 APIENTRY 549 NtUserGetKeyboardLayoutList( 550 ULONG nBuff, 551 HKL *pHklBuff) 552 { 553 UINT uRet = 0; 554 PKL pKl; 555 556 if (!pHklBuff) 557 nBuff = 0; 558 559 UserEnterShared(); 560 561 if (!gspklBaseLayout) 562 { 563 UserLeave(); 564 return 0; 565 } 566 pKl = gspklBaseLayout; 567 568 if (nBuff == 0) 569 { 570 do 571 { 572 uRet++; 573 pKl = pKl->pklNext; 574 } while (pKl != gspklBaseLayout); 575 } 576 else 577 { 578 _SEH2_TRY 579 { 580 ProbeForWrite(pHklBuff, nBuff*sizeof(HKL), 4); 581 582 while (uRet < nBuff) 583 { 584 pHklBuff[uRet] = pKl->hkl; 585 uRet++; 586 pKl = pKl->pklNext; 587 if (pKl == gspklBaseLayout) 588 break; 589 } 590 } 591 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 592 { 593 SetLastNtError(_SEH2_GetExceptionCode()); 594 uRet = 0; 595 } 596 _SEH2_END; 597 } 598 599 UserLeave(); 600 return uRet; 601 } 602 603 /* 604 * NtUserGetKeyboardLayoutName 605 * 606 * Returns KLID of current thread keyboard layout 607 */ 608 BOOL 609 APIENTRY 610 NtUserGetKeyboardLayoutName( 611 LPWSTR pwszName) 612 { 613 BOOL bRet = FALSE; 614 PKL pKl; 615 PTHREADINFO pti; 616 617 UserEnterShared(); 618 619 pti = PsGetCurrentThreadWin32Thread(); 620 pKl = pti->KeyboardLayout; 621 622 if (!pKl) 623 goto cleanup; 624 625 _SEH2_TRY 626 { 627 ProbeForWrite(pwszName, KL_NAMELENGTH*sizeof(WCHAR), 1); 628 wcscpy(pwszName, pKl->spkf->awchKF); 629 bRet = TRUE; 630 } 631 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 632 { 633 SetLastNtError(_SEH2_GetExceptionCode()); 634 } 635 _SEH2_END; 636 637 cleanup: 638 UserLeave(); 639 return bRet; 640 } 641 642 /* 643 * NtUserLoadKeyboardLayoutEx 644 * 645 * Loads keyboard layout with given locale id 646 */ 647 HKL 648 APIENTRY 649 NtUserLoadKeyboardLayoutEx( 650 IN HANDLE Handle, // hFile (See downloads.securityfocus.com/vulnerabilities/exploits/43774.c) 651 IN DWORD offTable, // Offset to KbdTables 652 IN PUNICODE_STRING puszKeyboardName, // Not used? 653 IN HKL hklUnload, 654 IN PUNICODE_STRING pustrKLID, 655 IN DWORD hkl, 656 IN UINT Flags) 657 { 658 HKL hklRet = NULL; 659 PKL pKl = NULL, pklLast; 660 WCHAR Buffer[9]; 661 UNICODE_STRING ustrSafeKLID; 662 663 if (Flags & ~(KLF_ACTIVATE|KLF_NOTELLSHELL|KLF_REORDER|KLF_REPLACELANG| 664 KLF_SUBSTITUTE_OK|KLF_SETFORPROCESS|KLF_UNLOADPREVIOUS| 665 KLF_RESET|KLF_SHIFTLOCK)) 666 { 667 ERR("Invalid flags: %x\n", Flags); 668 EngSetLastError(ERROR_INVALID_FLAGS); 669 return NULL; 670 } 671 672 /* FIXME: It seems KLF_RESET is only supported for WINLOGON */ 673 674 RtlInitEmptyUnicodeString(&ustrSafeKLID, Buffer, sizeof(Buffer)); 675 _SEH2_TRY 676 { 677 ProbeForRead(pustrKLID, sizeof(*pustrKLID), 1); 678 ProbeForRead(pustrKLID->Buffer, sizeof(pustrKLID->Length), 1); 679 RtlCopyUnicodeString(&ustrSafeKLID, pustrKLID); 680 } 681 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 682 { 683 SetLastNtError(_SEH2_GetExceptionCode()); 684 _SEH2_YIELD(return NULL); 685 } 686 _SEH2_END; 687 688 UserEnterExclusive(); 689 690 /* If hklUnload is specified, unload it and load new layput as default */ 691 if (hklUnload && (hklUnload != UlongToHandle(hkl))) 692 { 693 pKl = UserHklToKbl(hklUnload); 694 if (pKl) 695 UserUnloadKbl(pKl); 696 } 697 698 /* Let's see if layout was already loaded. */ 699 pKl = UserHklToKbl(UlongToHandle(hkl)); 700 if (!pKl) 701 { 702 /* It wasn't, so load it. */ 703 pKl = UserLoadKbdLayout(&ustrSafeKLID, UlongToHandle(hkl)); 704 if (!pKl) 705 goto cleanup; 706 707 if (gspklBaseLayout) 708 { 709 /* Find last not unloaded layout */ 710 pklLast = gspklBaseLayout->pklPrev; 711 while (pklLast != gspklBaseLayout && pklLast->dwKL_Flags & KLF_UNLOAD) 712 pklLast = pklLast->pklPrev; 713 714 /* Add new layout to the list */ 715 pKl->pklNext = pklLast->pklNext; 716 pKl->pklPrev = pklLast; 717 pKl->pklNext->pklPrev = pKl; 718 pKl->pklPrev->pklNext = pKl; 719 } 720 else 721 { 722 /* This is the first layout */ 723 pKl->pklNext = pKl; 724 pKl->pklPrev = pKl; 725 gspklBaseLayout = pKl; 726 } 727 } 728 729 /* If this layout was prepared to unload, undo it */ 730 pKl->dwKL_Flags &= ~KLF_UNLOAD; 731 732 /* Activate this layout in current thread */ 733 if (Flags & KLF_ACTIVATE) 734 co_UserActivateKbl(PsGetCurrentThreadWin32Thread(), pKl, Flags); 735 736 /* Send shell message */ 737 if (!(Flags & KLF_NOTELLSHELL)) 738 co_IntShellHookNotify(HSHELL_LANGUAGE, 0, (LPARAM)hkl); 739 740 /* Return hkl on success */ 741 hklRet = UlongToHandle(hkl); 742 743 /* FIXME: KLF_REPLACELANG 744 KLF_REORDER */ 745 746 cleanup: 747 UserLeave(); 748 return hklRet; 749 } 750 751 /* 752 * NtUserActivateKeyboardLayout 753 * 754 * Activates specified layout for thread or process 755 */ 756 HKL 757 APIENTRY 758 NtUserActivateKeyboardLayout( 759 HKL hKl, 760 ULONG Flags) 761 { 762 PKL pKl = NULL; 763 HKL hkl = NULL; 764 PTHREADINFO pti; 765 766 UserEnterExclusive(); 767 768 pti = PsGetCurrentThreadWin32Thread(); 769 770 /* hKl can have special value HKL_NEXT or HKL_PREV */ 771 if (hKl == (HKL)HKL_NEXT) 772 { 773 /* Get next keyboard layout starting with current */ 774 if (pti->KeyboardLayout) 775 pKl = pti->KeyboardLayout->pklNext; 776 } 777 else if (hKl == (HKL)HKL_PREV) 778 { 779 /* Get previous keyboard layout starting with current */ 780 if (pti->KeyboardLayout) 781 pKl = pti->KeyboardLayout->pklPrev; 782 } 783 else 784 pKl = UserHklToKbl(hKl); 785 786 if (!pKl) 787 { 788 ERR("Invalid HKL %p!\n", hKl); 789 goto cleanup; 790 } 791 792 hkl = pKl->hkl; 793 794 /* FIXME: KLF_RESET 795 KLF_SHIFTLOCK */ 796 797 if (Flags & KLF_REORDER) 798 gspklBaseLayout = pKl; 799 800 if (pKl != pti->KeyboardLayout) 801 { 802 /* Activate layout for current thread */ 803 pKl = co_UserActivateKbl(pti, pKl, Flags); 804 805 /* Send shell message */ 806 if (!(Flags & KLF_NOTELLSHELL)) 807 co_IntShellHookNotify(HSHELL_LANGUAGE, 0, (LPARAM)hkl); 808 } 809 810 cleanup: 811 UserLeave(); 812 return hkl; 813 } 814 815 /* 816 * NtUserUnloadKeyboardLayout 817 * 818 * Unloads keyboard layout with specified hkl value 819 */ 820 BOOL 821 APIENTRY 822 NtUserUnloadKeyboardLayout( 823 HKL hKl) 824 { 825 PKL pKl; 826 BOOL bRet = FALSE; 827 828 UserEnterExclusive(); 829 830 pKl = UserHklToKbl(hKl); 831 if (pKl) 832 bRet = UserUnloadKbl(pKl); 833 else 834 ERR("Invalid HKL %p!\n", hKl); 835 836 UserLeave(); 837 return bRet; 838 } 839 840 /* EOF */ 841