Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenkbdlayout.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Win32k subsystem 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: subsystems/win32/win32k/ntuser/kbdlayout.c 00005 * PURPOSE: Keyboard layout management 00006 * COPYRIGHT: Copyright 2007 Saveliy Tretiakov 00007 * Copyright 2008 Colin Finck 00008 * Copyright 2011 Rafal Harabien 00009 */ 00010 00011 #include <win32k.h> 00012 DBG_DEFAULT_CHANNEL(UserKbdLayout); 00013 00014 PKL gspklBaseLayout = NULL; 00015 PKBDFILE gpkfList = NULL; 00016 00017 typedef PVOID (*PFN_KBDLAYERDESCRIPTOR)(VOID); 00018 00019 00020 /* PRIVATE FUNCTIONS ******************************************************/ 00021 00022 /* 00023 * UserLoadKbdDll 00024 * 00025 * Loads keyboard layout DLL and gets address to KbdTables 00026 */ 00027 static BOOL 00028 UserLoadKbdDll(WCHAR *pwszLayoutPath, 00029 HANDLE *phModule, 00030 PKBDTABLES *pKbdTables) 00031 { 00032 PFN_KBDLAYERDESCRIPTOR pfnKbdLayerDescriptor; 00033 00034 /* Load keyboard layout DLL */ 00035 TRACE("Loading Keyboard DLL %ws\n", pwszLayoutPath); 00036 *phModule = EngLoadImage(pwszLayoutPath); 00037 if (!(*phModule)) 00038 { 00039 ERR("Failed to load dll %ws\n", pwszLayoutPath); 00040 return FALSE; 00041 } 00042 00043 /* Find KbdLayerDescriptor function and get layout tables */ 00044 TRACE("Loaded %ws\n", pwszLayoutPath); 00045 pfnKbdLayerDescriptor = EngFindImageProcAddress(*phModule, "KbdLayerDescriptor"); 00046 00047 /* FIXME: Windows reads file instead of executing! 00048 It's not safe to kbdlayout DLL in kernel mode! */ 00049 00050 if (pfnKbdLayerDescriptor) 00051 *pKbdTables = pfnKbdLayerDescriptor(); 00052 else 00053 ERR("Error: %ws has no KbdLayerDescriptor()\n", pwszLayoutPath); 00054 00055 if (!pfnKbdLayerDescriptor || !*pKbdTables) 00056 { 00057 ERR("Failed to load the keyboard layout.\n"); 00058 EngUnloadImage(*phModule); 00059 return FALSE; 00060 } 00061 00062 #if 0 /* Dump keyboard layout */ 00063 { 00064 unsigned i; 00065 PVK_TO_BIT pVkToBit = (*pKbdTables)->pCharModifiers->pVkToBit; 00066 PVK_TO_WCHAR_TABLE pVkToWchTbl = (*pKbdTables)->pVkToWcharTable; 00067 PVSC_VK pVscVk = (*pKbdTables)->pVSCtoVK_E0; 00068 DbgPrint("Kbd layout: fLocaleFlags %x bMaxVSCtoVK %x\n", (*pKbdTables)->fLocaleFlags, (*pKbdTables)->bMaxVSCtoVK); 00069 DbgPrint("wMaxModBits %x\n", (*pKbdTables)->pCharModifiers->wMaxModBits); 00070 while (pVkToBit->Vk) 00071 { 00072 DbgPrint("VkToBit %x -> %x\n", pVkToBit->Vk, pVkToBit->ModBits); 00073 ++pVkToBit; 00074 } 00075 for (i = 0; i <= (*pKbdTables)->pCharModifiers->wMaxModBits; ++i) 00076 DbgPrint("ModNumber %x -> %x\n", i, (*pKbdTables)->pCharModifiers->ModNumber[i]); 00077 while (pVkToWchTbl->pVkToWchars) 00078 { 00079 PVK_TO_WCHARS1 pVkToWch = pVkToWchTbl->pVkToWchars; 00080 DbgPrint("pVkToWchTbl nModifications %x cbSize %x\n", pVkToWchTbl->nModifications, pVkToWchTbl->cbSize); 00081 while (pVkToWch->VirtualKey) 00082 { 00083 DbgPrint("pVkToWch VirtualKey %x Attributes %x wc { ", pVkToWch->VirtualKey, pVkToWch->Attributes); 00084 for (i = 0; i < pVkToWchTbl->nModifications; ++i) 00085 DbgPrint("%x ", pVkToWch->wch[i]); 00086 DbgPrint("}\n"); 00087 pVkToWch = (PVK_TO_WCHARS1)(((PBYTE)pVkToWch) + pVkToWchTbl->cbSize); 00088 } 00089 ++pVkToWchTbl; 00090 } 00091 DbgPrint("pusVSCtoVK: { "); 00092 for (i = 0; i < (*pKbdTables)->bMaxVSCtoVK; ++i) 00093 DbgPrint("%x -> %x, ", i, (*pKbdTables)->pusVSCtoVK[i]); 00094 DbgPrint("}\n"); 00095 DbgPrint("pVSCtoVK_E0: { "); 00096 while (pVscVk->Vsc) 00097 { 00098 DbgPrint("%x -> %x, ", pVscVk->Vsc, pVscVk->Vk); 00099 ++pVscVk; 00100 } 00101 DbgPrint("}\n"); 00102 pVscVk = (*pKbdTables)->pVSCtoVK_E1; 00103 DbgPrint("pVSCtoVK_E1: { "); 00104 while (pVscVk->Vsc) 00105 { 00106 DbgPrint("%x -> %x, ", pVscVk->Vsc, pVscVk->Vk); 00107 ++pVscVk; 00108 } 00109 DbgPrint("}\n"); 00110 DbgBreakPoint(); 00111 } 00112 #endif 00113 00114 return TRUE; 00115 } 00116 00117 /* 00118 * UserLoadKbdFile 00119 * 00120 * Loads keyboard layout DLL and creates KBDFILE object 00121 */ 00122 static PKBDFILE 00123 UserLoadKbdFile(PUNICODE_STRING pwszKLID) 00124 { 00125 PKBDFILE pkf, pRet = NULL; 00126 NTSTATUS Status; 00127 ULONG cbSize; 00128 HKEY hKey = NULL; 00129 WCHAR wszLayoutPath[MAX_PATH] = L"\\SystemRoot\\System32\\"; 00130 WCHAR wszLayoutRegKey[256] = L"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\" 00131 L"Control\\Keyboard Layouts\\"; 00132 00133 /* Create keyboard layout file object */ 00134 pkf = UserCreateObject(gHandleTable, NULL, NULL, otKBDfile, sizeof(KBDFILE)); 00135 if (!pkf) 00136 { 00137 ERR("Failed to create object!\n"); 00138 return NULL; 00139 } 00140 00141 /* Set keyboard layout name */ 00142 swprintf(pkf->awchKF, L"%wZ", pwszKLID); 00143 00144 /* Open layout registry key */ 00145 RtlStringCbCatW(wszLayoutRegKey, sizeof(wszLayoutRegKey), pkf->awchKF); 00146 Status = RegOpenKey(wszLayoutRegKey, &hKey); 00147 if (!NT_SUCCESS(Status)) 00148 { 00149 ERR("Failed to open keyboard layouts registry key %ws (%lx)\n", wszLayoutRegKey, Status); 00150 goto cleanup; 00151 } 00152 00153 /* Read filename of layout DLL */ 00154 cbSize = sizeof(wszLayoutPath) - wcslen(wszLayoutPath)*sizeof(WCHAR); 00155 Status = RegQueryValue(hKey, 00156 L"Layout File", 00157 REG_SZ, 00158 wszLayoutPath + wcslen(wszLayoutPath), 00159 &cbSize); 00160 00161 if (!NT_SUCCESS(Status)) 00162 { 00163 ERR("Can't get layout filename for %wZ (%lx)\n", pwszKLID, Status); 00164 goto cleanup; 00165 } 00166 00167 /* Load keyboard file now */ 00168 if (!UserLoadKbdDll(wszLayoutPath, &pkf->hBase, &pkf->pKbdTbl)) 00169 { 00170 ERR("Failed to load %ws dll!\n", wszLayoutPath); 00171 goto cleanup; 00172 } 00173 00174 /* Update next field */ 00175 pkf->pkfNext = gpkfList; 00176 gpkfList = pkf; 00177 00178 /* Return keyboard file */ 00179 pRet = pkf; 00180 00181 cleanup: 00182 if (hKey) 00183 ZwClose(hKey); 00184 if (pkf) 00185 UserDereferenceObject(pkf); // we dont need ptr anymore 00186 if (!pRet) 00187 { 00188 /* We have failed - destroy created object */ 00189 if (pkf) 00190 UserDeleteObject(pkf->head.h, otKBDfile); 00191 } 00192 00193 return pRet; 00194 } 00195 00196 /* 00197 * UserLoadKbdLayout 00198 * 00199 * Loads keyboard layout and creates KL object 00200 */ 00201 static PKL 00202 UserLoadKbdLayout(PUNICODE_STRING pwszKLID, HKL hKL) 00203 { 00204 PKL pKl; 00205 00206 /* Create keyboard layout object */ 00207 pKl = UserCreateObject(gHandleTable, NULL, NULL, otKBDlayout, sizeof(KL)); 00208 if (!pKl) 00209 { 00210 ERR("Failed to create object!\n"); 00211 return NULL; 00212 } 00213 00214 pKl->hkl = hKL; 00215 pKl->spkf = UserLoadKbdFile(pwszKLID); 00216 00217 /* Dereference keyboard layout */ 00218 UserDereferenceObject(pKl); 00219 00220 /* If we failed, remove KL object */ 00221 if (!pKl->spkf) 00222 { 00223 ERR("UserLoadKbdFile(%wZ) failed!\n", pwszKLID); 00224 UserDeleteObject(pKl->head.h, otKBDlayout); 00225 return NULL; 00226 } 00227 00228 return pKl; 00229 } 00230 00231 /* 00232 * UnloadKbdFile 00233 * 00234 * Destroys specified Keyboard File object 00235 */ 00236 static 00237 VOID 00238 UnloadKbdFile(PKBDFILE pkf) 00239 { 00240 PKBDFILE *ppkfLink = &gpkfList; 00241 00242 /* Find previous object */ 00243 while (*ppkfLink) 00244 { 00245 if (*ppkfLink == pkf) 00246 break; 00247 00248 ppkfLink = &(*ppkfLink)->pkfNext; 00249 } 00250 00251 if (*ppkfLink == pkf) 00252 *ppkfLink = pkf->pkfNext; 00253 00254 EngUnloadImage(pkf->hBase); 00255 UserDeleteObject(pkf->head.h, otKBDfile); 00256 } 00257 00258 /* 00259 * UserUnloadKbl 00260 * 00261 * Unloads specified Keyboard Layout if possible 00262 */ 00263 BOOL 00264 UserUnloadKbl(PKL pKl) 00265 { 00266 /* According to msdn, UnloadKeyboardLayout can fail 00267 if the keyboard layout identifier was preloaded. */ 00268 if (pKl == gspklBaseLayout) 00269 { 00270 if (pKl->pklNext == pKl->pklPrev) 00271 { 00272 /* There is only one layout */ 00273 return FALSE; 00274 } 00275 00276 /* Set next layout as default */ 00277 gspklBaseLayout = pKl->pklNext; 00278 } 00279 00280 if (pKl->head.cLockObj > 1) 00281 { 00282 /* Layout is used by other threads */ 00283 pKl->dwKL_Flags |= KLF_UNLOAD; 00284 return FALSE; 00285 } 00286 00287 /* Unload the layout */ 00288 pKl->pklPrev->pklNext = pKl->pklNext; 00289 pKl->pklNext->pklPrev = pKl->pklPrev; 00290 UnloadKbdFile(pKl->spkf); 00291 UserDeleteObject(pKl->head.h, otKBDlayout); 00292 return TRUE; 00293 } 00294 00295 /* 00296 * W32kGetDefaultKeyLayout 00297 * 00298 * Returns default layout for new threads 00299 */ 00300 PKL 00301 W32kGetDefaultKeyLayout(VOID) 00302 { 00303 PKL pKl = gspklBaseLayout; 00304 00305 if (!pKl) 00306 return NULL; 00307 00308 /* Return not unloaded layout */ 00309 do 00310 { 00311 if (!(pKl->dwKL_Flags & KLF_UNLOAD)) 00312 return pKl; 00313 00314 pKl = pKl->pklPrev; /* Confirmed on Win2k */ 00315 } while(pKl != gspklBaseLayout); 00316 00317 /* We have not found proper KL */ 00318 return NULL; 00319 } 00320 00321 /* 00322 * UserHklToKbl 00323 * 00324 * Gets KL object from hkl value 00325 */ 00326 PKL 00327 NTAPI 00328 UserHklToKbl(HKL hKl) 00329 { 00330 PKL pKl = gspklBaseLayout; 00331 00332 if (!gspklBaseLayout) 00333 return NULL; 00334 00335 do 00336 { 00337 if (pKl->hkl == hKl) 00338 return pKl; 00339 00340 pKl = pKl->pklNext; 00341 } while (pKl != gspklBaseLayout); 00342 00343 return NULL; 00344 } 00345 00346 /* 00347 * UserSetDefaultInputLang 00348 * 00349 * Sets default kyboard layout for system. Called from UserSystemParametersInfo. 00350 */ 00351 BOOL 00352 NTAPI 00353 UserSetDefaultInputLang(HKL hKl) 00354 { 00355 PKL pKl; 00356 00357 pKl = UserHklToKbl(hKl); 00358 if (!pKl) 00359 return FALSE; 00360 00361 gspklBaseLayout = pKl; 00362 return TRUE; 00363 } 00364 00365 /* 00366 * co_UserActivateKbl 00367 * 00368 * Activates given layout in specified thread 00369 */ 00370 static PKL 00371 co_UserActivateKbl(PTHREADINFO pti, PKL pKl, UINT Flags) 00372 { 00373 PKL pklPrev; 00374 00375 pklPrev = pti->KeyboardLayout; 00376 if (pklPrev) 00377 UserDereferenceObject(pklPrev); 00378 00379 pti->KeyboardLayout = pKl; 00380 pti->pClientInfo->hKL = pKl->hkl; 00381 UserReferenceObject(pKl); 00382 00383 if (Flags & KLF_SETFORPROCESS) 00384 { 00385 // FIXME 00386 } 00387 00388 // Send WM_INPUTLANGCHANGE to thread's focus window 00389 co_IntSendMessage(pti->MessageQueue->spwndFocus ? UserHMGetHandle(pti->MessageQueue->spwndFocus) : 0, 00390 WM_INPUTLANGCHANGE, 00391 (WPARAM)pKl->iBaseCharset, // FIXME: How to set it? 00392 (LPARAM)pKl->hkl); // hkl 00393 00394 return pklPrev; 00395 } 00396 00397 /* EXPORTS *******************************************************************/ 00398 00399 /* 00400 * UserGetKeyboardLayout 00401 * 00402 * Returns hkl of given thread keyboard layout 00403 */ 00404 HKL FASTCALL 00405 UserGetKeyboardLayout( 00406 DWORD dwThreadId) 00407 { 00408 NTSTATUS Status; 00409 PETHREAD pThread; 00410 PTHREADINFO pti; 00411 PKL pKl; 00412 HKL hKl; 00413 00414 if (!dwThreadId) 00415 { 00416 pti = PsGetCurrentThreadWin32Thread(); 00417 pKl = pti->KeyboardLayout; 00418 return pKl ? pKl->hkl : NULL; 00419 } 00420 00421 Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)dwThreadId, &pThread); 00422 if (!NT_SUCCESS(Status)) 00423 { 00424 EngSetLastError(ERROR_INVALID_PARAMETER); 00425 return NULL; 00426 } 00427 00428 pti = PsGetThreadWin32Thread(pThread); 00429 pKl = pti->KeyboardLayout; 00430 hKl = pKl ? pKl->hkl : NULL;; 00431 ObDereferenceObject(pThread); 00432 return hKl; 00433 } 00434 00435 /* 00436 * NtUserGetKeyboardLayoutList 00437 * 00438 * Returns list of loaded keyboard layouts in system 00439 */ 00440 UINT 00441 APIENTRY 00442 NtUserGetKeyboardLayoutList( 00443 ULONG nBuff, 00444 HKL *pHklBuff) 00445 { 00446 UINT uRet = 0; 00447 PKL pKl; 00448 00449 if (!pHklBuff) 00450 nBuff = 0; 00451 00452 UserEnterShared(); 00453 00454 if (!gspklBaseLayout) 00455 return 0; 00456 pKl = gspklBaseLayout; 00457 00458 if (nBuff == 0) 00459 { 00460 do 00461 { 00462 uRet++; 00463 pKl = pKl->pklNext; 00464 } while (pKl != gspklBaseLayout); 00465 } 00466 else 00467 { 00468 _SEH2_TRY 00469 { 00470 ProbeForWrite(pHklBuff, nBuff*sizeof(HKL), 4); 00471 00472 while (uRet < nBuff) 00473 { 00474 pHklBuff[uRet] = pKl->hkl; 00475 uRet++; 00476 pKl = pKl->pklNext; 00477 if (pKl == gspklBaseLayout) 00478 break; 00479 } 00480 } 00481 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00482 { 00483 SetLastNtError(_SEH2_GetExceptionCode()); 00484 uRet = 0; 00485 } 00486 _SEH2_END; 00487 } 00488 00489 UserLeave(); 00490 return uRet; 00491 } 00492 00493 /* 00494 * NtUserGetKeyboardLayoutName 00495 * 00496 * Returns KLID of current thread keyboard layout 00497 */ 00498 BOOL 00499 APIENTRY 00500 NtUserGetKeyboardLayoutName( 00501 LPWSTR pwszName) 00502 { 00503 BOOL bRet = FALSE; 00504 PKL pKl; 00505 PTHREADINFO pti; 00506 00507 UserEnterShared(); 00508 00509 pti = PsGetCurrentThreadWin32Thread(); 00510 pKl = pti->KeyboardLayout; 00511 00512 if (!pKl) 00513 goto cleanup; 00514 00515 _SEH2_TRY 00516 { 00517 ProbeForWrite(pwszName, KL_NAMELENGTH*sizeof(WCHAR), 1); 00518 wcscpy(pwszName, pKl->spkf->awchKF); 00519 bRet = TRUE; 00520 } 00521 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00522 { 00523 SetLastNtError(_SEH2_GetExceptionCode()); 00524 } 00525 _SEH2_END; 00526 00527 cleanup: 00528 UserLeave(); 00529 return bRet; 00530 } 00531 00532 /* 00533 * NtUserLoadKeyboardLayoutEx 00534 * 00535 * Loads keyboard layout with given locale id 00536 */ 00537 HKL 00538 APIENTRY 00539 NtUserLoadKeyboardLayoutEx( 00540 IN HANDLE Handle, // hFile (See downloads.securityfocus.com/vulnerabilities/exploits/43774.c) 00541 IN DWORD offTable, // Offset to KbdTables 00542 IN PUNICODE_STRING puszKeyboardName, // Not used? 00543 IN HKL hklUnload, 00544 IN PUNICODE_STRING pustrKLID, 00545 IN DWORD hkl, 00546 IN UINT Flags) 00547 { 00548 HKL hklRet = NULL; 00549 PKL pKl = NULL, pklLast; 00550 WCHAR Buffer[9]; 00551 UNICODE_STRING ustrSafeKLID; 00552 00553 if (Flags & ~(KLF_ACTIVATE|KLF_NOTELLSHELL|KLF_REORDER|KLF_REPLACELANG| 00554 KLF_SUBSTITUTE_OK|KLF_SETFORPROCESS|KLF_UNLOADPREVIOUS| 00555 KLF_RESET|KLF_SETFORPROCESS|KLF_SHIFTLOCK)) 00556 { 00557 ERR("Invalid flags: %x\n", Flags); 00558 EngSetLastError(ERROR_INVALID_FLAGS); 00559 return NULL; 00560 } 00561 00562 /* FIXME: It seems KLF_RESET is only supported for WINLOGON */ 00563 00564 RtlInitEmptyUnicodeString(&ustrSafeKLID, Buffer, sizeof(Buffer)); 00565 _SEH2_TRY 00566 { 00567 ProbeForRead(pustrKLID, sizeof(*pustrKLID), 1); 00568 ProbeForRead(pustrKLID->Buffer, sizeof(pustrKLID->Length), 1); 00569 RtlCopyUnicodeString(&ustrSafeKLID, pustrKLID); 00570 } 00571 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00572 { 00573 SetLastNtError(_SEH2_GetExceptionCode()); 00574 _SEH2_YIELD(return NULL); 00575 } 00576 _SEH2_END; 00577 00578 UserEnterExclusive(); 00579 00580 /* If hklUnload is specified, unload it and load new layput as default */ 00581 if (hklUnload && hklUnload != (HKL)hkl) 00582 { 00583 pKl = UserHklToKbl(hklUnload); 00584 if (pKl) 00585 UserUnloadKbl(pKl); 00586 } 00587 00588 /* Let's see if layout was already loaded. */ 00589 pKl = UserHklToKbl((HKL)hkl); 00590 if (!pKl) 00591 { 00592 /* It wasn't, so load it. */ 00593 pKl = UserLoadKbdLayout(&ustrSafeKLID, (HKL)hkl); 00594 if (!pKl) 00595 goto cleanup; 00596 00597 if (gspklBaseLayout) 00598 { 00599 /* Find last not unloaded layout */ 00600 pklLast = gspklBaseLayout->pklPrev; 00601 while (pklLast != gspklBaseLayout && pklLast->dwKL_Flags & KLF_UNLOAD) 00602 pklLast = pklLast->pklPrev; 00603 00604 /* Add new layout to the list */ 00605 pKl->pklNext = pklLast->pklNext; 00606 pKl->pklPrev = pklLast; 00607 pKl->pklNext->pklPrev = pKl; 00608 pKl->pklPrev->pklNext = pKl; 00609 } 00610 else 00611 { 00612 /* This is the first layout */ 00613 pKl->pklNext = pKl; 00614 pKl->pklPrev = pKl; 00615 gspklBaseLayout = pKl; 00616 } 00617 } 00618 00619 /* If this layout was prepared to unload, undo it */ 00620 pKl->dwKL_Flags &= ~KLF_UNLOAD; 00621 00622 /* Activate this layout in current thread */ 00623 if (Flags & KLF_ACTIVATE) 00624 co_UserActivateKbl(PsGetCurrentThreadWin32Thread(), pKl, Flags); 00625 00626 /* Send shell message */ 00627 if (!(Flags & KLF_NOTELLSHELL)) 00628 co_IntShellHookNotify(HSHELL_LANGUAGE, (LPARAM)hkl); 00629 00630 /* Return hkl on success */ 00631 hklRet = (HKL)hkl; 00632 00633 /* FIXME: KLF_REPLACELANG 00634 KLF_REORDER */ 00635 00636 cleanup: 00637 UserLeave(); 00638 return hklRet; 00639 } 00640 00641 /* 00642 * NtUserActivateKeyboardLayout 00643 * 00644 * Activates specified layout for thread or process 00645 */ 00646 HKL 00647 APIENTRY 00648 NtUserActivateKeyboardLayout( 00649 HKL hKl, 00650 ULONG Flags) 00651 { 00652 PKL pKl = NULL; 00653 HKL hkl = NULL; 00654 PTHREADINFO pti; 00655 00656 UserEnterExclusive(); 00657 00658 pti = PsGetCurrentThreadWin32Thread(); 00659 00660 /* hKl can have special value HKL_NEXT or HKL_PREV */ 00661 if (hKl == (HKL)HKL_NEXT) 00662 { 00663 /* Get next keyboard layout starting with current */ 00664 if (pti->KeyboardLayout) 00665 pKl = pti->KeyboardLayout->pklNext; 00666 } 00667 else if (hKl == (HKL)HKL_PREV) 00668 { 00669 /* Get previous keyboard layout starting with current */ 00670 if (pti->KeyboardLayout) 00671 pKl = pti->KeyboardLayout->pklNext; 00672 } 00673 else 00674 pKl = UserHklToKbl(hKl); 00675 00676 if (!pKl) 00677 { 00678 ERR("Invalid HKL %x!\n", hKl); 00679 goto cleanup; 00680 } 00681 00682 hkl = pKl->hkl; 00683 00684 /* FIXME: KLF_RESET 00685 KLF_SHIFTLOCK */ 00686 00687 if (Flags & KLF_REORDER) 00688 gspklBaseLayout = pKl; 00689 00690 if (pKl != pti->KeyboardLayout) 00691 { 00692 /* Activate layout for current thread */ 00693 pKl = co_UserActivateKbl(pti, pKl, Flags); 00694 00695 /* Send shell message */ 00696 if (!(Flags & KLF_NOTELLSHELL)) 00697 co_IntShellHookNotify(HSHELL_LANGUAGE, (LPARAM)hkl); 00698 } 00699 00700 cleanup: 00701 UserLeave(); 00702 return hkl; 00703 } 00704 00705 /* 00706 * NtUserUnloadKeyboardLayout 00707 * 00708 * Unloads keyboard layout with specified hkl value 00709 */ 00710 BOOL 00711 APIENTRY 00712 NtUserUnloadKeyboardLayout( 00713 HKL hKl) 00714 { 00715 PKL pKl; 00716 BOOL bRet = FALSE; 00717 00718 UserEnterExclusive(); 00719 00720 pKl = UserHklToKbl(hKl); 00721 if (pKl) 00722 bRet = UserUnloadKbl(pKl); 00723 else 00724 ERR("Invalid HKL %x!\n", hKl); 00725 00726 UserLeave(); 00727 return bRet; 00728 } 00729 00730 /* EOF */ Generated on Sun May 27 2012 04:38:32 for ReactOS by
1.7.6.1
|