ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

kbdlayout.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.