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 * Copyright 2022 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 10 */ 11 12 #include <win32k.h> 13 #include <ddk/immdev.h> 14 15 // Was included only because of CP_ACP and required the 16 // definition of SYSTEMTIME in ndk\rtltypes.h 17 //#include <winnls.h> 18 #define CP_ACP 0 19 20 DBG_DEFAULT_CHANNEL(UserKbdLayout); 21 22 PKL gspklBaseLayout = NULL; /* FIXME: Please move this to pWinSta->spklList */ 23 PKBDFILE gpkfList = NULL; 24 DWORD gSystemFS = 0; 25 UINT gSystemCPCharSet = 0; 26 DWORD gLCIDSentToShell = 0; 27 28 typedef PVOID (*PFN_KBDLAYERDESCRIPTOR)(VOID); 29 30 /* PRIVATE FUNCTIONS ******************************************************/ 31 32 /* 33 * Retrieves a PKL by an input locale identifier (HKL). 34 * @implemented 35 * Win: HKLtoPKL 36 */ 37 PKL FASTCALL IntHKLtoPKL(_Inout_ PTHREADINFO pti, _In_ HKL hKL) 38 { 39 PKL pFirstKL, pKL; 40 41 pFirstKL = pti->KeyboardLayout; 42 if (!pFirstKL) 43 return NULL; 44 45 pKL = pFirstKL; 46 47 /* hKL can have special value HKL_NEXT or HKL_PREV */ 48 if (hKL == (HKL)(ULONG_PTR)HKL_NEXT) /* Looking forward */ 49 { 50 do 51 { 52 pKL = pKL->pklNext; 53 if (!(pKL->dwKL_Flags & KLF_UNLOAD)) 54 return pKL; 55 } while (pKL != pFirstKL); 56 } 57 else if (hKL == (HKL)(ULONG_PTR)HKL_PREV) /* Looking backward */ 58 { 59 do 60 { 61 pKL = pKL->pklPrev; 62 if (!(pKL->dwKL_Flags & KLF_UNLOAD)) 63 return pKL; 64 } while (pKL != pFirstKL); 65 } 66 else if (HIWORD(hKL)) /* hKL is a full input locale identifier */ 67 { 68 /* No KLF_UNLOAD check */ 69 do 70 { 71 if (pKL->hkl == hKL) 72 return pKL; 73 74 pKL = pKL->pklNext; 75 } while (pKL != pFirstKL); 76 } 77 else /* Language only specified */ 78 { 79 /* No KLF_UNLOAD check */ 80 do 81 { 82 if (LOWORD(pKL->hkl) == LOWORD(hKL)) /* Low word is language ID */ 83 return pKL; 84 85 pKL = pKL->pklNext; 86 } while (pKL != pFirstKL); 87 } 88 89 return NULL; 90 } 91 92 /* 93 * A helper function for NtUserGetKeyboardLayoutList. 94 * @implemented 95 * Win: _GetKeyboardLayoutList 96 */ 97 static UINT APIENTRY 98 IntGetKeyboardLayoutList( 99 _Inout_ PWINSTATION_OBJECT pWinSta, 100 _In_ ULONG nBuff, 101 _Out_ HKL *pHklBuff) 102 { 103 UINT ret = 0; 104 PKL pKL, pFirstKL; 105 106 pFirstKL = gspklBaseLayout; /* FIXME: Use pWinSta->spklList instead */ 107 if (!pWinSta || !pFirstKL) 108 return 0; 109 110 pKL = pFirstKL; 111 112 if (nBuff == 0) 113 { 114 /* Count the effective PKLs */ 115 do 116 { 117 if (!(pKL->dwKL_Flags & KLF_UNLOAD)) 118 ++ret; 119 pKL = pKL->pklNext; 120 } while (pKL != pFirstKL); 121 } 122 else 123 { 124 /* Copy the effective HKLs to pHklBuff */ 125 do 126 { 127 if (!(pKL->dwKL_Flags & KLF_UNLOAD)) 128 { 129 *pHklBuff = pKL->hkl; 130 ++pHklBuff; 131 ++ret; 132 --nBuff; 133 134 if (nBuff == 0) 135 break; 136 } 137 pKL = pKL->pklNext; 138 } while (pKL != pFirstKL); 139 } 140 141 return ret; 142 } 143 144 #if 0 && DBG 145 146 static VOID 147 DumpKbdLayout( 148 IN PKBDTABLES pKbdTbl) 149 { 150 PVK_TO_BIT pVkToBit; 151 PVK_TO_WCHAR_TABLE pVkToWchTbl; 152 PVSC_VK pVscVk; 153 ULONG i; 154 155 DbgPrint("Kbd layout: fLocaleFlags %x bMaxVSCtoVK %x\n", 156 pKbdTbl->fLocaleFlags, pKbdTbl->bMaxVSCtoVK); 157 DbgPrint("wMaxModBits %x\n", 158 pKbdTbl->pCharModifiers ? pKbdTbl->pCharModifiers->wMaxModBits 159 : 0); 160 161 if (pKbdTbl->pCharModifiers) 162 { 163 pVkToBit = pKbdTbl->pCharModifiers->pVkToBit; 164 if (pVkToBit) 165 { 166 for (; pVkToBit->Vk; ++pVkToBit) 167 { 168 DbgPrint("VkToBit %x -> %x\n", pVkToBit->Vk, pVkToBit->ModBits); 169 } 170 } 171 172 for (i = 0; i <= pKbdTbl->pCharModifiers->wMaxModBits; ++i) 173 { 174 DbgPrint("ModNumber %x -> %x\n", i, pKbdTbl->pCharModifiers->ModNumber[i]); 175 } 176 } 177 178 pVkToWchTbl = pKbdTbl->pVkToWcharTable; 179 if (pVkToWchTbl) 180 { 181 for (; pVkToWchTbl->pVkToWchars; ++pVkToWchTbl) 182 { 183 PVK_TO_WCHARS1 pVkToWch = pVkToWchTbl->pVkToWchars; 184 185 DbgPrint("pVkToWchTbl nModifications %x cbSize %x\n", 186 pVkToWchTbl->nModifications, pVkToWchTbl->cbSize); 187 if (pVkToWch) 188 { 189 while (pVkToWch->VirtualKey) 190 { 191 DbgPrint("pVkToWch VirtualKey %x Attributes %x wc { ", 192 pVkToWch->VirtualKey, pVkToWch->Attributes); 193 for (i = 0; i < pVkToWchTbl->nModifications; ++i) 194 { 195 DbgPrint("%x ", pVkToWch->wch[i]); 196 } 197 DbgPrint("}\n"); 198 pVkToWch = (PVK_TO_WCHARS1)(((PBYTE)pVkToWch) + pVkToWchTbl->cbSize); 199 } 200 } 201 } 202 } 203 204 // TODO: DeadKeys, KeyNames, KeyNamesExt, KeyNamesDead 205 206 DbgPrint("pusVSCtoVK: { "); 207 if (pKbdTbl->pusVSCtoVK) 208 { 209 for (i = 0; i < pKbdTbl->bMaxVSCtoVK; ++i) 210 { 211 DbgPrint("%x -> %x, ", i, pKbdTbl->pusVSCtoVK[i]); 212 } 213 } 214 DbgPrint("}\n"); 215 216 DbgPrint("pVSCtoVK_E0: { "); 217 pVscVk = pKbdTbl->pVSCtoVK_E0; 218 if (pVscVk) 219 { 220 for (; pVscVk->Vsc; ++pVscVk) 221 { 222 DbgPrint("%x -> %x, ", pVscVk->Vsc, pVscVk->Vk); 223 } 224 } 225 DbgPrint("}\n"); 226 227 DbgPrint("pVSCtoVK_E1: { "); 228 pVscVk = pKbdTbl->pVSCtoVK_E1; 229 if (pVscVk) 230 { 231 for (; pVscVk->Vsc; ++pVscVk) 232 { 233 DbgPrint("%x -> %x, ", pVscVk->Vsc, pVscVk->Vk); 234 } 235 } 236 DbgPrint("}\n"); 237 238 // TODO: Ligatures 239 } 240 241 #endif // DBG 242 243 244 /* 245 * UserLoadKbdDll 246 * 247 * Loads keyboard layout DLL and gets address to KbdTables 248 */ 249 static BOOL 250 UserLoadKbdDll(WCHAR *pwszLayoutPath, 251 HANDLE *phModule, 252 PKBDTABLES *pKbdTables) 253 { 254 PFN_KBDLAYERDESCRIPTOR pfnKbdLayerDescriptor; 255 256 /* Load keyboard layout DLL */ 257 TRACE("Loading Keyboard DLL %ws\n", pwszLayoutPath); 258 *phModule = EngLoadImage(pwszLayoutPath); 259 if (!(*phModule)) 260 { 261 ERR("Failed to load dll %ws\n", pwszLayoutPath); 262 return FALSE; 263 } 264 265 /* Find KbdLayerDescriptor function and get layout tables */ 266 TRACE("Loaded %ws\n", pwszLayoutPath); 267 pfnKbdLayerDescriptor = EngFindImageProcAddress(*phModule, "KbdLayerDescriptor"); 268 269 /* FIXME: Windows reads file instead of executing! 270 It's not safe to kbdlayout DLL in kernel mode! */ 271 272 if (pfnKbdLayerDescriptor) 273 *pKbdTables = pfnKbdLayerDescriptor(); 274 else 275 ERR("Error: %ws has no KbdLayerDescriptor()\n", pwszLayoutPath); 276 277 if (!pfnKbdLayerDescriptor || !*pKbdTables) 278 { 279 ERR("Failed to load the keyboard layout.\n"); 280 EngUnloadImage(*phModule); 281 return FALSE; 282 } 283 284 #if 0 && DBG 285 /* Dump keyboard layout */ 286 DumpKbdLayout(*pKbdTables); 287 #endif 288 289 return TRUE; 290 } 291 292 /* 293 * UserLoadKbdFile 294 * 295 * Loads keyboard layout DLL and creates KBDFILE object 296 */ 297 static PKBDFILE 298 UserLoadKbdFile(PUNICODE_STRING pwszKLID) 299 { 300 PKBDFILE pkf, pRet = NULL; 301 NTSTATUS Status; 302 ULONG cbSize; 303 HKEY hKey = NULL; 304 WCHAR wszLayoutPath[MAX_PATH] = L"\\SystemRoot\\System32\\"; 305 WCHAR wszLayoutRegKey[256] = L"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\" 306 L"Control\\Keyboard Layouts\\"; 307 308 /* Create keyboard layout file object */ 309 pkf = UserCreateObject(gHandleTable, NULL, NULL, NULL, TYPE_KBDFILE, sizeof(KBDFILE)); 310 if (!pkf) 311 { 312 ERR("Failed to create object!\n"); 313 return NULL; 314 } 315 316 /* Set keyboard layout name */ 317 swprintf(pkf->awchKF, L"%wZ", pwszKLID); 318 319 /* Open layout registry key */ 320 RtlStringCbCatW(wszLayoutRegKey, sizeof(wszLayoutRegKey), pkf->awchKF); 321 Status = RegOpenKey(wszLayoutRegKey, &hKey); 322 if (!NT_SUCCESS(Status)) 323 { 324 ERR("Failed to open keyboard layouts registry key %ws (%lx)\n", wszLayoutRegKey, Status); 325 goto cleanup; 326 } 327 328 /* Read filename of layout DLL */ 329 cbSize = (ULONG)(sizeof(wszLayoutPath) - wcslen(wszLayoutPath)*sizeof(WCHAR)); 330 Status = RegQueryValue(hKey, 331 L"Layout File", 332 REG_SZ, 333 wszLayoutPath + wcslen(wszLayoutPath), 334 &cbSize); 335 336 if (!NT_SUCCESS(Status)) 337 { 338 ERR("Can't get layout filename for %wZ (%lx)\n", pwszKLID, Status); 339 goto cleanup; 340 } 341 342 /* Load keyboard file now */ 343 if (!UserLoadKbdDll(wszLayoutPath, &pkf->hBase, &pkf->pKbdTbl)) 344 { 345 ERR("Failed to load %ws dll!\n", wszLayoutPath); 346 goto cleanup; 347 } 348 349 /* Update next field */ 350 pkf->pkfNext = gpkfList; 351 gpkfList = pkf; 352 353 /* Return keyboard file */ 354 pRet = pkf; 355 356 cleanup: 357 if (hKey) 358 ZwClose(hKey); 359 if (pkf) 360 UserDereferenceObject(pkf); // we dont need ptr anymore 361 if (!pRet) 362 { 363 /* We have failed - destroy created object */ 364 if (pkf) 365 UserDeleteObject(pkf->head.h, TYPE_KBDFILE); 366 } 367 368 return pRet; 369 } 370 371 /* 372 * UserLoadKbdLayout 373 * 374 * Loads keyboard layout and creates KL object 375 */ 376 static PKL 377 UserLoadKbdLayout(PUNICODE_STRING pustrKLID, HKL hKL) 378 { 379 LCID lCid; 380 CHARSETINFO cs; 381 PKL pKl; 382 383 /* Create keyboard layout object */ 384 pKl = UserCreateObject(gHandleTable, NULL, NULL, NULL, TYPE_KBDLAYOUT, sizeof(KL)); 385 if (!pKl) 386 { 387 ERR("Failed to create object!\n"); 388 return NULL; 389 } 390 391 pKl->hkl = hKL; 392 pKl->spkf = UserLoadKbdFile(pustrKLID); 393 394 /* Dereference keyboard layout */ 395 UserDereferenceObject(pKl); 396 397 /* If we failed, remove KL object */ 398 if (!pKl->spkf) 399 { 400 ERR("UserLoadKbdFile(%wZ) failed!\n", pustrKLID); 401 UserDeleteObject(pKl->head.h, TYPE_KBDLAYOUT); 402 return NULL; 403 } 404 405 // Up to Language Identifiers.. 406 if (!NT_SUCCESS(RtlUnicodeStringToInteger(pustrKLID, 16, (PULONG)&lCid))) 407 { 408 ERR("RtlUnicodeStringToInteger failed for '%wZ'\n", pustrKLID); 409 UserDeleteObject(pKl->head.h, TYPE_KBDLAYOUT); 410 return NULL; 411 } 412 413 TRACE("Language Identifiers %wZ LCID 0x%x\n", pustrKLID, lCid); 414 if (co_IntGetCharsetInfo(lCid, &cs)) 415 { 416 pKl->iBaseCharset = cs.ciCharset; 417 pKl->dwFontSigs = cs.fs.fsCsb[0]; 418 pKl->CodePage = (USHORT)cs.ciACP; 419 TRACE("Charset %u Font Sig %lu CodePage %u\n", 420 pKl->iBaseCharset, pKl->dwFontSigs, pKl->CodePage); 421 } 422 else 423 { 424 pKl->iBaseCharset = ANSI_CHARSET; 425 pKl->dwFontSigs = FS_LATIN1; 426 pKl->CodePage = CP_ACP; 427 } 428 429 // Set initial system character set and font signature. 430 if (gSystemFS == 0) 431 { 432 gSystemCPCharSet = pKl->iBaseCharset; 433 gSystemFS = pKl->dwFontSigs; 434 } 435 436 return pKl; 437 } 438 439 /* 440 * UnloadKbdFile 441 * 442 * Destroys specified Keyboard File object 443 */ 444 static 445 VOID 446 UnloadKbdFile(_In_ PKBDFILE pkf) 447 { 448 PKBDFILE *ppkfLink = &gpkfList; 449 NT_ASSERT(pkf != NULL); 450 451 /* Find previous object */ 452 while (*ppkfLink) 453 { 454 if (*ppkfLink == pkf) 455 break; 456 457 ppkfLink = &(*ppkfLink)->pkfNext; 458 } 459 460 if (*ppkfLink == pkf) 461 *ppkfLink = pkf->pkfNext; 462 463 EngUnloadImage(pkf->hBase); 464 UserDeleteObject(pkf->head.h, TYPE_KBDFILE); 465 } 466 467 /* 468 * UserUnloadKbl 469 * 470 * Unloads specified Keyboard Layout if possible 471 */ 472 BOOL 473 UserUnloadKbl(PKL pKl) 474 { 475 /* According to msdn, UnloadKeyboardLayout can fail 476 if the keyboard layout identifier was preloaded. */ 477 if (pKl == gspklBaseLayout) 478 { 479 if (pKl->pklNext == pKl->pklPrev) 480 { 481 /* There is only one layout */ 482 return FALSE; 483 } 484 485 /* Set next layout as default */ 486 gspklBaseLayout = pKl->pklNext; 487 } 488 489 if (pKl->head.cLockObj > 1) 490 { 491 /* Layout is used by other threads */ 492 pKl->dwKL_Flags |= KLF_UNLOAD; 493 return FALSE; 494 } 495 496 /* Unload the layout */ 497 pKl->pklPrev->pklNext = pKl->pklNext; 498 pKl->pklNext->pklPrev = pKl->pklPrev; 499 UnloadKbdFile(pKl->spkf); 500 UserDeleteObject(pKl->head.h, TYPE_KBDLAYOUT); 501 return TRUE; 502 } 503 504 /* 505 * W32kGetDefaultKeyLayout 506 * 507 * Returns default layout for new threads 508 */ 509 PKL 510 W32kGetDefaultKeyLayout(VOID) 511 { 512 PKL pKl = gspklBaseLayout; 513 514 if (!pKl) 515 return NULL; 516 517 /* Return not unloaded layout */ 518 do 519 { 520 if (!(pKl->dwKL_Flags & KLF_UNLOAD)) 521 return pKl; 522 523 pKl = pKl->pklPrev; /* Confirmed on Win2k */ 524 } while(pKl != gspklBaseLayout); 525 526 /* We have not found proper KL */ 527 return NULL; 528 } 529 530 /* 531 * UserHklToKbl 532 * 533 * Gets KL object from hkl value 534 */ 535 PKL 536 NTAPI 537 UserHklToKbl(HKL hKl) 538 { 539 PKL pKl = gspklBaseLayout; 540 541 if (!gspklBaseLayout) 542 return NULL; 543 544 do 545 { 546 if (pKl->hkl == hKl) 547 return pKl; 548 549 pKl = pKl->pklNext; 550 } while (pKl != gspklBaseLayout); 551 552 return NULL; 553 } 554 555 /* 556 * UserSetDefaultInputLang 557 * 558 * Sets default kyboard layout for system. Called from UserSystemParametersInfo. 559 */ 560 BOOL 561 NTAPI 562 UserSetDefaultInputLang(HKL hKl) 563 { 564 PKL pKl; 565 566 pKl = UserHklToKbl(hKl); 567 if (!pKl) 568 return FALSE; 569 570 gspklBaseLayout = pKl; 571 return TRUE; 572 } 573 574 /* 575 * co_UserActivateKbl 576 * 577 * Activates given layout in specified thread 578 */ 579 static PKL 580 co_UserActivateKbl(PTHREADINFO pti, PKL pKl, UINT Flags) 581 { 582 PKL pklPrev; 583 PWND pWnd; 584 585 pklPrev = pti->KeyboardLayout; 586 587 UserAssignmentLock((PVOID*)&(pti->KeyboardLayout), pKl); 588 pti->pClientInfo->hKL = pKl->hkl; 589 590 if (Flags & KLF_SETFORPROCESS) 591 { 592 FIXME("KLF_SETFORPROCESS\n"); 593 } 594 595 if (!(pWnd = pti->MessageQueue->spwndFocus)) 596 { 597 pWnd = pti->MessageQueue->spwndActive; 598 } 599 600 // Send WM_INPUTLANGCHANGE to thread's focus window 601 co_IntSendMessage( pWnd ? UserHMGetHandle(pWnd) : 0, 602 WM_INPUTLANGCHANGE, 603 (WPARAM)pKl->iBaseCharset, // FIXME: How to set it? 604 (LPARAM)pKl->hkl); // hkl 605 606 return pklPrev; 607 } 608 609 // Win: xxxImmActivateLayout 610 VOID APIENTRY 611 IntImmActivateLayout( 612 _Inout_ PTHREADINFO pti, 613 _Inout_ PKL pKL) 614 { 615 PWND pImeWnd; 616 HWND hImeWnd; 617 USER_REFERENCE_ENTRY Ref; 618 619 if (pti->KeyboardLayout == pKL) 620 return; 621 622 pImeWnd = pti->spwndDefaultIme; 623 if (pImeWnd) 624 { 625 UserRefObjectCo(pImeWnd, &Ref); 626 hImeWnd = UserHMGetHandle(pImeWnd); 627 co_IntSendMessage(hImeWnd, WM_IME_SYSTEM, IMS_ACTIVATELAYOUT, (LPARAM)pKL->hkl); 628 UserDerefObjectCo(pImeWnd); 629 } 630 631 UserAssignmentLock((PVOID*)&(pti->KeyboardLayout), pKL); 632 pti->pClientInfo->hKL = pKL->hkl; 633 } 634 635 /* Win: xxxInternalActivateKeyboardLayout */ 636 HKL APIENTRY 637 co_UserActivateKeyboardLayout( 638 _Inout_ PKL pKL, 639 _In_ ULONG uFlags, 640 _Inout_ PWND pWnd) 641 { 642 HKL hOldKL = NULL; 643 PKL pOldKL = NULL; 644 PTHREADINFO pti = GetW32ThreadInfo(); 645 PWND pTargetWnd, pImeWnd; 646 HWND hTargetWnd, hImeWnd; 647 USER_REFERENCE_ENTRY Ref1, Ref2; 648 PCLIENTINFO ClientInfo = pti->pClientInfo; 649 650 if (pti->KeyboardLayout) 651 { 652 pOldKL = pti->KeyboardLayout; 653 if (pOldKL) 654 hOldKL = pOldKL->hkl; 655 } 656 657 if (uFlags & KLF_RESET) 658 { 659 FIXME("KLF_RESET\n"); 660 } 661 662 if (!(uFlags & KLF_SETFORPROCESS) && pKL == pti->KeyboardLayout) 663 return hOldKL; 664 665 pKL->wchDiacritic = 0; 666 667 if (pOldKL) 668 UserRefObjectCo(pOldKL, &Ref1); 669 670 if (pti->TIF_flags & TIF_CSRSSTHREAD) 671 { 672 UserAssignmentLock((PVOID*)&pti->KeyboardLayout, pKL); 673 ClientInfo->CodePage = pKL->CodePage; 674 ClientInfo->hKL = pKL->hkl; 675 } 676 else if (uFlags & KLF_SETFORPROCESS) 677 { 678 FIXME("KLF_SETFORPROCESS\n"); 679 } 680 else 681 { 682 if (IS_IMM_MODE()) 683 IntImmActivateLayout(pti, pKL); 684 else 685 UserAssignmentLock((PVOID*)&pti->KeyboardLayout, pKL); 686 687 ClientInfo->CodePage = pKL->CodePage; 688 ClientInfo->hKL = pKL->hkl; 689 } 690 691 if (gptiForeground && (gptiForeground->ppi == pti->ppi)) 692 { 693 /* Send shell message */ 694 co_IntShellHookNotify(HSHELL_LANGUAGE, 0, (LPARAM)pKL->hkl); 695 } 696 697 if (pti->MessageQueue) 698 { 699 /* Determine the target window */ 700 pTargetWnd = pti->MessageQueue->spwndFocus; 701 if (!pTargetWnd) 702 { 703 pTargetWnd = pti->MessageQueue->spwndActive; 704 if (!pTargetWnd) 705 pTargetWnd = pWnd; 706 } 707 708 /* Send WM_INPUTLANGCHANGE message */ 709 if (pTargetWnd) 710 { 711 UserRefObjectCo(pTargetWnd, &Ref2); 712 hTargetWnd = UserHMGetHandle(pTargetWnd); 713 co_IntSendMessage(hTargetWnd, WM_INPUTLANGCHANGE, pKL->iBaseCharset, (LPARAM)pKL->hkl); 714 UserDerefObjectCo(pTargetWnd); 715 } 716 } 717 718 /* Send WM_IME_SYSTEM:IMS_SENDNOTIFICATION message if necessary */ 719 if (pti && !(pti->TIF_flags & TIF_CSRSSTHREAD)) 720 { 721 if (IS_IME_HKL(pKL->hkl) || (gpsi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)) 722 { 723 pImeWnd = pti->spwndDefaultIme; 724 if (pImeWnd) 725 { 726 UserRefObjectCo(pImeWnd, &Ref2); 727 BOOL bProcess = !!(pti->TIF_flags & KLF_SETFORPROCESS); 728 hImeWnd = UserHMGetHandle(pImeWnd); 729 co_IntSendMessage(hImeWnd, WM_IME_SYSTEM, IMS_SENDNOTIFICATION, bProcess); 730 UserDerefObjectCo(pImeWnd); 731 } 732 } 733 } 734 735 if (pOldKL) 736 UserDerefObjectCo(pOldKL); 737 return hOldKL; 738 } 739 740 // Win: ReorderKeyboardLayouts 741 VOID FASTCALL 742 IntReorderKeyboardLayouts( 743 _Inout_ PWINSTATION_OBJECT pWinSta, 744 _Inout_ PKL pKL) 745 { 746 /* FIXME */ 747 gspklBaseLayout = pKL; 748 } 749 750 /* Win: xxxActivateKeyboardLayout */ 751 HKL APIENTRY 752 co_IntActivateKeyboardLayout( 753 _Inout_ PWINSTATION_OBJECT pWinSta, 754 _In_ HKL hKL, 755 _In_ ULONG uFlags, 756 _Inout_ PWND pWnd) 757 { 758 PKL pKL; 759 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 760 761 pKL = IntHKLtoPKL(pti, hKL); 762 if (!pKL) 763 { 764 ERR("Invalid HKL %p!\n", hKL); 765 return NULL; 766 } 767 768 if (uFlags & KLF_REORDER) 769 IntReorderKeyboardLayouts(pWinSta, pKL); 770 771 return co_UserActivateKeyboardLayout(pKL, uFlags, pWnd); 772 } 773 774 // Win: xxxInternalUnloadKeyboardLayout 775 static BOOL APIENTRY 776 co_IntUnloadKeyboardLayoutEx( 777 _Inout_ PWINSTATION_OBJECT pWinSta, 778 _Inout_ PKL pKL, 779 _In_ DWORD dwFlags) 780 { 781 PKL pNextKL; 782 USER_REFERENCE_ENTRY Ref1, Ref2; 783 PTHREADINFO pti = gptiCurrent; 784 785 if (pKL == gspklBaseLayout && !(dwFlags & 0x80000000)) 786 return FALSE; 787 788 UserRefObjectCo(pKL, &Ref1); /* Add reference */ 789 790 /* Regard as unloaded */ 791 UserMarkObjectDestroy(pKL); 792 pKL->dwKL_Flags |= KLF_UNLOAD; 793 794 if (!(dwFlags & 0x80000000) && pti->KeyboardLayout == pKL) 795 { 796 pNextKL = IntHKLtoPKL(pti, (HKL)(ULONG_PTR)HKL_NEXT); 797 if (pNextKL) 798 { 799 UserRefObjectCo(pNextKL, &Ref2); /* Add reference */ 800 co_UserActivateKeyboardLayout(pNextKL, dwFlags, NULL); 801 UserDerefObjectCo(pNextKL); /* Release reference */ 802 } 803 } 804 805 if (gspklBaseLayout == pKL && pKL != pKL->pklNext) 806 { 807 /* Set next layout as default (FIXME: Use UserAssignmentLock?) */ 808 gspklBaseLayout = pKL->pklNext; 809 } 810 811 UserDerefObjectCo(pKL); /* Release reference */ 812 813 if (pti->pDeskInfo->fsHooks) 814 { 815 co_IntShellHookNotify(HSHELL_LANGUAGE, 0, 0); 816 gLCIDSentToShell = 0; 817 } 818 819 return TRUE; 820 } 821 822 // Win: xxxUnloadKeyboardLayout 823 static BOOL APIENTRY 824 IntUnloadKeyboardLayout(_Inout_ PWINSTATION_OBJECT pWinSta, _In_ HKL hKL) 825 { 826 PKL pKL = IntHKLtoPKL(gptiCurrent, hKL); 827 if (!pKL) 828 { 829 ERR("Invalid HKL %p!\n", hKL); 830 return FALSE; 831 } 832 return co_IntUnloadKeyboardLayoutEx(pWinSta, pKL, 0); 833 } 834 835 /* EXPORTS *******************************************************************/ 836 837 /* 838 * UserGetKeyboardLayout 839 * 840 * Returns hkl of given thread keyboard layout 841 */ 842 HKL FASTCALL 843 UserGetKeyboardLayout( 844 DWORD dwThreadId) 845 { 846 PTHREADINFO pti; 847 PLIST_ENTRY ListEntry; 848 PKL pKl; 849 850 pti = PsGetCurrentThreadWin32Thread(); 851 852 if (!dwThreadId) 853 { 854 pKl = pti->KeyboardLayout; 855 return pKl ? pKl->hkl : NULL; 856 } 857 858 ListEntry = pti->rpdesk->PtiList.Flink; 859 860 // 861 // Search the Desktop Thread list for related Desktop active Threads. 862 // 863 while(ListEntry != &pti->rpdesk->PtiList) 864 { 865 pti = CONTAINING_RECORD(ListEntry, THREADINFO, PtiLink); 866 867 if (PsGetThreadId(pti->pEThread) == UlongToHandle(dwThreadId)) 868 { 869 pKl = pti->KeyboardLayout; 870 return pKl ? pKl->hkl : NULL; 871 } 872 873 ListEntry = ListEntry->Flink; 874 } 875 876 return NULL; 877 } 878 879 /* 880 * NtUserGetKeyboardLayoutList 881 * 882 * Returns list of loaded keyboard layouts in system 883 */ 884 UINT 885 APIENTRY 886 NtUserGetKeyboardLayoutList( 887 ULONG nBuff, 888 HKL *pHklBuff) 889 { 890 UINT ret = 0; 891 PWINSTATION_OBJECT pWinSta; 892 893 if (!pHklBuff) 894 nBuff = 0; 895 896 UserEnterShared(); 897 898 if (nBuff > MAXULONG / sizeof(HKL)) 899 { 900 SetLastNtError(ERROR_INVALID_PARAMETER); 901 goto Quit; 902 } 903 904 _SEH2_TRY 905 { 906 ProbeForWrite(pHklBuff, nBuff * sizeof(HKL), 1); 907 } 908 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 909 { 910 SetLastNtError(_SEH2_GetExceptionCode()); 911 goto Quit; 912 } 913 _SEH2_END; 914 915 pWinSta = IntGetProcessWindowStation(NULL); 916 917 _SEH2_TRY 918 { 919 ret = IntGetKeyboardLayoutList(pWinSta, nBuff, pHklBuff); 920 } 921 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 922 { 923 SetLastNtError(_SEH2_GetExceptionCode()); 924 goto Quit; 925 } 926 _SEH2_END; 927 928 Quit: 929 UserLeave(); 930 return ret; 931 } 932 933 /* 934 * NtUserGetKeyboardLayoutName 935 * 936 * Returns KLID of current thread keyboard layout 937 */ 938 BOOL 939 APIENTRY 940 NtUserGetKeyboardLayoutName( 941 _Inout_ PUNICODE_STRING pustrName) 942 { 943 BOOL bRet = FALSE; 944 PKL pKl; 945 PTHREADINFO pti; 946 UNICODE_STRING ustrNameSafe; 947 NTSTATUS Status; 948 949 UserEnterShared(); 950 951 pti = PsGetCurrentThreadWin32Thread(); 952 pKl = pti->KeyboardLayout; 953 954 if (!pKl) 955 goto cleanup; 956 957 _SEH2_TRY 958 { 959 ProbeForWriteUnicodeString(pustrName); 960 ustrNameSafe = *pustrName; 961 962 ProbeForWrite(ustrNameSafe.Buffer, ustrNameSafe.MaximumLength, 1); 963 964 if (IS_IME_HKL(pKl->hkl)) 965 { 966 Status = RtlIntegerToUnicodeString((ULONG)(ULONG_PTR)pKl->hkl, 16, &ustrNameSafe); 967 } 968 else 969 { 970 if (ustrNameSafe.MaximumLength < KL_NAMELENGTH * sizeof(WCHAR)) 971 { 972 EngSetLastError(ERROR_INVALID_PARAMETER); 973 goto cleanup; 974 } 975 976 /* FIXME: Do not use awchKF */ 977 ustrNameSafe.Length = 0; 978 Status = RtlAppendUnicodeToString(&ustrNameSafe, pKl->spkf->awchKF); 979 } 980 981 if (NT_SUCCESS(Status)) 982 { 983 *pustrName = ustrNameSafe; 984 bRet = TRUE; 985 } 986 } 987 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 988 { 989 SetLastNtError(_SEH2_GetExceptionCode()); 990 } 991 _SEH2_END; 992 993 cleanup: 994 UserLeave(); 995 return bRet; 996 } 997 998 /* 999 * NtUserLoadKeyboardLayoutEx 1000 * 1001 * Loads keyboard layout with given locale id 1002 */ 1003 HKL 1004 APIENTRY 1005 NtUserLoadKeyboardLayoutEx( 1006 IN HANDLE Handle, // hFile (See downloads.securityfocus.com/vulnerabilities/exploits/43774.c) 1007 IN DWORD offTable, // Offset to KbdTables 1008 IN PUNICODE_STRING puszKeyboardName, // Not used? 1009 IN HKL hklUnload, 1010 IN PUNICODE_STRING pustrKLID, 1011 IN DWORD hkl, 1012 IN UINT Flags) 1013 { 1014 HKL hklRet = NULL; 1015 PKL pKl = NULL, pklLast; 1016 WCHAR Buffer[9]; 1017 UNICODE_STRING ustrSafeKLID; 1018 1019 if (Flags & ~(KLF_ACTIVATE|KLF_NOTELLSHELL|KLF_REORDER|KLF_REPLACELANG| 1020 KLF_SUBSTITUTE_OK|KLF_SETFORPROCESS|KLF_UNLOADPREVIOUS| 1021 KLF_RESET|KLF_SHIFTLOCK)) 1022 { 1023 ERR("Invalid flags: %x\n", Flags); 1024 EngSetLastError(ERROR_INVALID_FLAGS); 1025 return NULL; 1026 } 1027 1028 /* FIXME: It seems KLF_RESET is only supported for WINLOGON */ 1029 1030 RtlInitEmptyUnicodeString(&ustrSafeKLID, Buffer, sizeof(Buffer)); 1031 _SEH2_TRY 1032 { 1033 ProbeForRead(pustrKLID, sizeof(*pustrKLID), 1); 1034 ProbeForRead(pustrKLID->Buffer, sizeof(pustrKLID->Length), 1); 1035 RtlCopyUnicodeString(&ustrSafeKLID, pustrKLID); 1036 } 1037 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1038 { 1039 SetLastNtError(_SEH2_GetExceptionCode()); 1040 _SEH2_YIELD(return NULL); 1041 } 1042 _SEH2_END; 1043 1044 UserEnterExclusive(); 1045 1046 /* If hklUnload is specified, unload it and load new layput as default */ 1047 if (hklUnload && (hklUnload != UlongToHandle(hkl))) 1048 { 1049 pKl = UserHklToKbl(hklUnload); 1050 if (pKl) 1051 UserUnloadKbl(pKl); 1052 } 1053 1054 /* Let's see if layout was already loaded. */ 1055 pKl = UserHklToKbl(UlongToHandle(hkl)); 1056 if (!pKl) 1057 { 1058 /* It wasn't, so load it. */ 1059 pKl = UserLoadKbdLayout(&ustrSafeKLID, UlongToHandle(hkl)); 1060 if (!pKl) 1061 goto cleanup; 1062 1063 if (gspklBaseLayout) 1064 { 1065 /* Find last not unloaded layout */ 1066 pklLast = gspklBaseLayout->pklPrev; 1067 while (pklLast != gspklBaseLayout && pklLast->dwKL_Flags & KLF_UNLOAD) 1068 pklLast = pklLast->pklPrev; 1069 1070 /* Add new layout to the list */ 1071 pKl->pklNext = pklLast->pklNext; 1072 pKl->pklPrev = pklLast; 1073 pKl->pklNext->pklPrev = pKl; 1074 pKl->pklPrev->pklNext = pKl; 1075 } 1076 else 1077 { 1078 /* This is the first layout */ 1079 pKl->pklNext = pKl; 1080 pKl->pklPrev = pKl; 1081 gspklBaseLayout = pKl; 1082 } 1083 } 1084 1085 /* If this layout was prepared to unload, undo it */ 1086 pKl->dwKL_Flags &= ~KLF_UNLOAD; 1087 1088 /* Activate this layout in current thread */ 1089 if (Flags & KLF_ACTIVATE) 1090 co_UserActivateKbl(PsGetCurrentThreadWin32Thread(), pKl, Flags); 1091 1092 /* Send shell message */ 1093 if (!(Flags & KLF_NOTELLSHELL)) 1094 co_IntShellHookNotify(HSHELL_LANGUAGE, 0, (LPARAM)hkl); 1095 1096 /* Return hkl on success */ 1097 hklRet = UlongToHandle(hkl); 1098 1099 /* FIXME: KLF_REPLACELANG 1100 KLF_REORDER */ 1101 1102 cleanup: 1103 UserLeave(); 1104 return hklRet; 1105 } 1106 1107 /* 1108 * NtUserActivateKeyboardLayout 1109 * 1110 * Activates specified layout for thread or process 1111 */ 1112 HKL 1113 NTAPI 1114 NtUserActivateKeyboardLayout( 1115 HKL hKL, 1116 ULONG Flags) 1117 { 1118 PWINSTATION_OBJECT pWinSta; 1119 HKL hOldKL; 1120 1121 UserEnterExclusive(); 1122 1123 /* FIXME */ 1124 1125 pWinSta = IntGetProcessWindowStation(NULL); 1126 hOldKL = co_IntActivateKeyboardLayout(pWinSta, hKL, Flags, NULL); 1127 UserLeave(); 1128 1129 return hOldKL; 1130 } 1131 1132 /* 1133 * NtUserUnloadKeyboardLayout 1134 * 1135 * Unloads keyboard layout with specified hkl value 1136 */ 1137 BOOL 1138 APIENTRY 1139 NtUserUnloadKeyboardLayout( 1140 HKL hKl) 1141 { 1142 BOOL ret; 1143 PWINSTATION_OBJECT pWinSta; 1144 1145 UserEnterExclusive(); 1146 1147 pWinSta = IntGetProcessWindowStation(NULL); 1148 ret = IntUnloadKeyboardLayout(pWinSta, hKl); 1149 1150 UserLeave(); 1151 return ret; 1152 } 1153 1154 /* EOF */ 1155