[WIN32K|USER32]

- Make keyboard layouts code more compatible
- Layouts and kbd files are user objects
- Preloaded layouts are added by Winlogon, not win32k
- Support Keyboard Layout substitutes in registry

svn path=/trunk/; revision=54203
This commit is contained in:
Rafal Harabien 2011-10-19 20:03:50 +00:00
parent f00c31f3ff
commit db62557f8c
8 changed files with 526 additions and 365 deletions

View file

@ -267,6 +267,65 @@ WaitForLsass(VOID)
} }
static BOOL
InitKeyboardLayouts()
{
WCHAR wszKeyName[12], wszKLID[10];
DWORD dwSize = sizeof(wszKLID), dwType, i;
HKEY hKey;
UINT Flags;
BOOL bRet = FALSE;
/* Open registry key with preloaded layouts */
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
{
ERR("RegOpenKeyExW failed!\n");
return FALSE;
}
i = 1;
while(TRUE)
{
/* Read values with integer names only */
swprintf(wszKeyName, L"%d", i);
if (RegQueryValueExW(hKey, wszKeyName, NULL, &dwType, (LPBYTE)wszKLID, &dwSize) != ERROR_SUCCESS)
{
/* If we loaded at least one layout and there is no more
registry values return TRUE */
if (i > 1)
bRet = TRUE;
break;
}
/* Only REG_SZ values are valid */
if (dwType != REG_SZ)
{
ERR("Wrong type!\n");
break;
}
/* Load keyboard layout with given locale id */
Flags = KLF_SUBSTITUTE_OK;
if (i > 1)
Flags |= KLF_NOTELLSHELL|KLF_REPLACELANG;
else // First layout
Flags |= KLF_ACTIVATE; // |0x40000000
if (!LoadKeyboardLayoutW(wszKLID, Flags))
{
ERR("LoadKeyboardLayoutW failed!\n");
break;
}
/* Move to the next entry */
++i;
}
/* Close the key now */
RegCloseKey(hKey);
return bRet;
}
BOOL BOOL
DisplayStatusMessage( DisplayStatusMessage(
IN PWLSESSION Session, IN PWLSESSION Session,
@ -390,6 +449,14 @@ WinMain(
} }
LockWorkstation(WLSession); LockWorkstation(WLSession);
/* Load default keyboard layouts */
if (!InitKeyboardLayouts())
{
ERR("WL: Could not preload keyboard layouts\n");
NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
ExitProcess(1);
}
if (!StartServicesManager()) if (!StartServicesManager())
{ {
ERR("WL: Could not start services.exe\n"); ERR("WL: Could not start services.exe\n");

View file

@ -29,6 +29,7 @@
#define USE_GETLASTINPUTINFO #define USE_GETLASTINPUTINFO
#define WIN32_NO_STATUS #define WIN32_NO_STATUS
#include <stdio.h>
#include <windows.h> #include <windows.h>
#include <userenv.h> #include <userenv.h>
#include <winwlx.h> #include <winwlx.h>

View file

@ -423,6 +423,7 @@ HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000410","Layout Displa
HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000411","Layout File",0x00000000,"kbdja.dll" HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000411","Layout File",0x00000000,"kbdja.dll"
HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000411","Layout Text",0x00000000,"Japanese" HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000411","Layout Text",0x00000000,"Japanese"
HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000411","Layout Display Name",0x00000000,"@%SystemRoot%\system32\input.dll,-5061" HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000411","Layout Display Name",0x00000000,"@%SystemRoot%\system32\input.dll,-5061"
HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000411","Layout Id",0x00000000,"0001"
HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\0000041c","Layout File",0x00000000,"kbdal.dll" HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\0000041c","Layout File",0x00000000,"kbdal.dll"
HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\0000041c","Layout Text",0x00000000,"Albanian" HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\0000041c","Layout Text",0x00000000,"Albanian"
@ -625,6 +626,7 @@ HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\0000081a","Layout Displa
HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000412","Layout File",0x00000000,"kbdko.dll" HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000412","Layout File",0x00000000,"kbdko.dll"
HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000412","Layout Text",0x00000000,"Korean" HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000412","Layout Text",0x00000000,"Korean"
HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000412","Layout Display Name",0x00000000,"@%SystemRoot%\system32\input.dll,-5063" HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000412","Layout Display Name",0x00000000,"@%SystemRoot%\system32\input.dll,-5063"
HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000412","Layout Id",0x00000000,"0001"
; Keyboard layouts ; Keyboard layouts
HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layout",,0x00000012 HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layout",,0x00000012

View file

@ -2,30 +2,53 @@
#include <ndk/kbd.h> #include <ndk/kbd.h>
typedef struct _KL typedef struct tagKBDNLSLAYER
{ {
LIST_ENTRY List; USHORT OEMIdentifier;
DWORD Flags; USHORT LayoutInformation;
WCHAR Name[KL_NAMELENGTH]; // used w GetKeyboardLayoutName same as wszKLID. UINT NumOfVkToF;
struct _KBDTABLES *KBTables; // KBDTABLES in ndk/kbd.h struct _VK_TO_FUNCTION_TABLE *pVkToF;
HANDLE hModule; INT NumOfMouseVKey;
ULONG RefCount; PUSHORT pusMouseVKey;
HKL hkl; } KBDNLSLAYER, *PKBDNLSLAYER;
DWORD klid; // Low word - language id. High word - device id.
typedef struct tagKBDFILE
{
HEAD head;
struct tagKBDFILE *pkfNext;
WCHAR awchKF[20];
HANDLE hBase;
struct _KBDTABLES *pKbdTbl;
ULONG Size;
PKBDNLSLAYER pKbdNlsTbl;
} KBDFILE, *PKBDFILE;
typedef struct tagKL
{
HEAD head;
struct tagKL *pklNext;
struct tagKL *pklPrev;
DWORD dwKL_Flags;
HKL hkl;
PKBDFILE spkf;
DWORD dwFontSigs;
UINT iBaseCharset;
USHORT CodePage;
WCHAR wchDiacritic;
//PIMEINFOEX piiex;
} KL, *PKL; } KL, *PKL;
typedef struct _ATTACHINFO typedef struct _ATTACHINFO
{ {
struct _ATTACHINFO* paiNext; struct _ATTACHINFO *paiNext;
PTHREADINFO pti1; PTHREADINFO pti1;
PTHREADINFO pti2; PTHREADINFO pti2;
} ATTACHINFO, *PATTACHINFO; } ATTACHINFO, *PATTACHINFO;
extern PATTACHINFO gpai; extern PATTACHINFO gpai;
#define KBL_UNLOAD 1 /* Keyboard layout undocumented flags */
#define KBL_PRELOAD 2 #define KLF_UNLOAD 0x20000000
#define KBL_RESET 4
/* Key States */ /* Key States */
#define KS_DOWN_BIT 0x80 #define KS_DOWN_BIT 0x80

View file

@ -286,6 +286,8 @@ Win32kThreadCallback(struct _ETHREAD *Thread,
} }
ptiCurrent->MessageQueue = MsqCreateMessageQueue(Thread); ptiCurrent->MessageQueue = MsqCreateMessageQueue(Thread);
ptiCurrent->KeyboardLayout = W32kGetDefaultKeyLayout(); ptiCurrent->KeyboardLayout = W32kGetDefaultKeyLayout();
if (ptiCurrent->KeyboardLayout)
UserReferenceObject(ptiCurrent->KeyboardLayout);
ptiCurrent->pEThread = Thread; ptiCurrent->pEThread = Thread;
/* HAAAAAAAACK! This should go to Win32kProcessCallback */ /* HAAAAAAAACK! This should go to Win32kProcessCallback */
@ -421,6 +423,8 @@ Win32kThreadCallback(struct _ETHREAD *Thread,
IntBlockInput(ptiCurrent, FALSE); IntBlockInput(ptiCurrent, FALSE);
MsqDestroyMessageQueue(ptiCurrent->MessageQueue); MsqDestroyMessageQueue(ptiCurrent->MessageQueue);
IntCleanupThreadCallbacks(ptiCurrent); IntCleanupThreadCallbacks(ptiCurrent);
if (ptiCurrent->KeyboardLayout)
UserDereferenceObject(ptiCurrent->KeyboardLayout);
/* cleanup user object references stack */ /* cleanup user object references stack */
psle = PopEntryList(&ptiCurrent->ReferencesList); psle = PopEntryList(&ptiCurrent->ReferencesList);

View file

@ -329,12 +329,6 @@ InitInputImpl(VOID)
} }
KeInitializeTimer(MasterTimer); KeInitializeTimer(MasterTimer);
/* Initialize the default keyboard layout */
if (!UserInitDefaultKeyboardLayout())
{
ERR("Failed to initialize default keyboard layout!\n");
}
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }

View file

@ -11,66 +11,46 @@
#include <win32k.h> #include <win32k.h>
DBG_DEFAULT_CHANNEL(UserKbdLayout); DBG_DEFAULT_CHANNEL(UserKbdLayout);
PKL gpklFirst = NULL; // Keyboard layout list. PKL gspklBaseLayout = NULL;
PKBDFILE gpkfList = NULL;
typedef PVOID (*PFNKBDLAYERDESCRIPTOR)(VOID); typedef PVOID (*PFN_KBDLAYERDESCRIPTOR)(VOID);
/* PRIVATE FUNCTIONS ******************************************************/ /* PRIVATE FUNCTIONS ******************************************************/
/*
* UserLoadKbdDll
*
* Loads keyboard layout DLL and gets address to KbdTables
*/
static BOOL static BOOL
UserLoadKbdDll(CONST WCHAR *wszKLID, UserLoadKbdDll(WCHAR *pwszLayoutPath,
HANDLE *phModule, HANDLE *phModule,
PKBDTABLES *pKbdTables) PKBDTABLES *pKbdTables)
{ {
NTSTATUS Status; PFN_KBDLAYERDESCRIPTOR pfnKbdLayerDescriptor;
HKEY hKey;
ULONG cbSize;
PFNKBDLAYERDESCRIPTOR pfnKbdLayerDescriptor;
WCHAR wszLayoutRegKey[256] = L"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\"
L"Control\\Keyboard Layouts\\";
WCHAR wszLayoutPath[MAX_PATH] = L"\\SystemRoot\\System32\\";
/* Open layout registry key */
RtlStringCbCatW(wszLayoutRegKey, sizeof(wszLayoutRegKey), wszKLID);
Status = RegOpenKey(wszLayoutRegKey, &hKey);
if (!NT_SUCCESS(Status))
{
ERR("Failed to open keyboard layouts registry key %ws (%lx)\n", wszKLID, Status);
return FALSE;
}
/* Read filename of layout DLL and close the key */
cbSize = sizeof(wszLayoutPath) - (wcslen(wszLayoutPath) + 1)*sizeof(WCHAR);
Status = RegQueryValue(hKey,
L"Layout File",
REG_SZ,
wszLayoutPath + wcslen(wszLayoutPath),
&cbSize);
ZwClose(hKey);
if (!NT_SUCCESS(Status))
{
TRACE("Can't get layout filename for %ws (%lx)\n", wszKLID, Status);
return FALSE;
}
/* Load keyboard layout DLL */ /* Load keyboard layout DLL */
TRACE("Loading Keyboard DLL %ws\n", wszLayoutPath); TRACE("Loading Keyboard DLL %ws\n", pwszLayoutPath);
*phModule = EngLoadImage(wszLayoutPath); *phModule = EngLoadImage(pwszLayoutPath);
if (!(*phModule)) if (!(*phModule))
{ {
ERR("Failed to load dll %ws\n", wszLayoutPath); ERR("Failed to load dll %ws\n", pwszLayoutPath);
return FALSE; return FALSE;
} }
/* Find KbdLayerDescriptor function and get layout tables */ /* Find KbdLayerDescriptor function and get layout tables */
TRACE("Loaded %ws\n", wszLayoutPath); TRACE("Loaded %ws\n", pwszLayoutPath);
pfnKbdLayerDescriptor = EngFindImageProcAddress(*phModule, "KbdLayerDescriptor"); pfnKbdLayerDescriptor = EngFindImageProcAddress(*phModule, "KbdLayerDescriptor");
/* FIXME: Windows reads file instead of executing!
It's not safe to kbdlayout DLL in kernel mode! */
if (pfnKbdLayerDescriptor) if (pfnKbdLayerDescriptor)
*pKbdTables = pfnKbdLayerDescriptor(); *pKbdTables = pfnKbdLayerDescriptor();
else else
ERR("Error: %ws has no KbdLayerDescriptor()\n", wszLayoutPath); ERR("Error: %ws has no KbdLayerDescriptor()\n", pwszLayoutPath);
if (!pfnKbdLayerDescriptor || !*pKbdTables) if (!pfnKbdLayerDescriptor || !*pKbdTables)
{ {
@ -79,7 +59,7 @@ UserLoadKbdDll(CONST WCHAR *wszKLID,
return FALSE; return FALSE;
} }
#if 0 // Dump keyboard layout #if 0 /* Dump keyboard layout */
{ {
unsigned i; unsigned i;
PVK_TO_BIT pVkToBit = (*pKbdTables)->pCharModifiers->pVkToBit; PVK_TO_BIT pVkToBit = (*pKbdTables)->pCharModifiers->pVkToBit;
@ -134,300 +114,333 @@ UserLoadKbdDll(CONST WCHAR *wszKLID,
return TRUE; return TRUE;
} }
static PKL /*
UserLoadDllAndCreateKbl(DWORD LocaleId) * UserLoadKbdFile
*
* Loads keyboard layout DLL and creates KBDFILE object
*/
static PKBDFILE
UserLoadKbdFile(PUNICODE_STRING pwszKLID)
{ {
PKL pNewKbl; PKBDFILE pkf, pRet = NULL;
ULONG hKl; NTSTATUS Status;
LANGID langid; ULONG cbSize;
HKEY hKey = NULL;
WCHAR wszLayoutPath[MAX_PATH] = L"\\SystemRoot\\System32\\";
WCHAR wszLayoutRegKey[256] = L"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\"
L"Control\\Keyboard Layouts\\";
pNewKbl = ExAllocatePoolWithTag(PagedPool, sizeof(KL), USERTAG_KBDLAYOUT); /* Create keyboard layout file object */
pkf = UserCreateObject(gHandleTable, NULL, NULL, otKBDfile, sizeof(KBDFILE));
if (!pNewKbl) if (!pkf)
{ {
ERR("Can't allocate memory!\n"); ERR("Failed to create object!\n");
return NULL; return NULL;
} }
swprintf(pNewKbl->Name, L"%08lx", LocaleId); /* Set keyboard layout name */
swprintf(pkf->awchKF, L"%wZ", pwszKLID);
if (!UserLoadKbdDll(pNewKbl->Name, &pNewKbl->hModule, &pNewKbl->KBTables)) /* Open layout registry key */
RtlStringCbCatW(wszLayoutRegKey, sizeof(wszLayoutRegKey), pkf->awchKF);
Status = RegOpenKey(wszLayoutRegKey, &hKey);
if (!NT_SUCCESS(Status))
{ {
ERR("Failed to load %x dll!\n", LocaleId); ERR("Failed to open keyboard layouts registry key %ws (%lx)\n", wszLayoutRegKey, Status);
ExFreePoolWithTag(pNewKbl, USERTAG_KBDLAYOUT); goto cleanup;
return NULL;
} }
/* Microsoft Office expects this value to be something specific /* Read filename of layout DLL */
* for Japanese and Korean Windows with an IME the value is 0xe001 cbSize = sizeof(wszLayoutPath) - wcslen(wszLayoutPath)*sizeof(WCHAR);
* We should probably check to see if an IME exists and if so then Status = RegQueryValue(hKey,
* set this word properly. L"Layout File",
*/ REG_SZ,
langid = PRIMARYLANGID(LANGIDFROMLCID(LocaleId)); wszLayoutPath + wcslen(wszLayoutPath),
hKl = LocaleId; &cbSize);
if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN) if (!NT_SUCCESS(Status))
hKl |= 0xe001 << 16; /* FIXME */ {
else hKl |= hKl << 16; ERR("Can't get layout filename for %wZ (%lx)\n", pwszKLID, Status);
goto cleanup;
}
pNewKbl->hkl = (HKL)(ULONG_PTR) hKl; /* Load keyboard file now */
pNewKbl->klid = LocaleId; if (!UserLoadKbdDll(wszLayoutPath, &pkf->hBase, &pkf->pKbdTbl))
pNewKbl->Flags = 0; {
pNewKbl->RefCount = 0; ERR("Failed to load %ws dll!\n", wszLayoutPath);
goto cleanup;
}
return pNewKbl; /* Update next field */
pkf->pkfNext = gpkfList;
gpkfList = pkf;
/* Return keyboard file */
pRet = pkf;
cleanup:
if (hKey)
ZwClose(hKey);
if (pkf)
UserDereferenceObject(pkf); // we dont need ptr anymore
if (!pRet)
{
/* We have failed - destroy created object */
if (pkf)
UserDeleteObject(pkf->head.h, otKBDfile);
}
return pRet;
} }
BOOL /*
UserInitDefaultKeyboardLayout() * UserLoadKbdLayout
*
* Loads keyboard layout and creates KL object
*/
static PKL
UserLoadKbdLayout(PUNICODE_STRING pwszKLID, HKL hKL)
{ {
LCID LocaleId; PKL pKl;
NTSTATUS Status;
/* Load keyboard layout for default locale */ /* Create keyboard layout object */
Status = ZwQueryDefaultLocale(FALSE, &LocaleId); pKl = UserCreateObject(gHandleTable, NULL, NULL, otKBDlayout, sizeof(KL));
if (NT_SUCCESS(Status)) if (!pKl)
{ {
TRACE("DefaultLocale = %08lx\n", LocaleId); ERR("Failed to create object!\n");
gpklFirst = UserLoadDllAndCreateKbl(LocaleId); return NULL;
} }
else
ERR("Could not get default locale (%08lx).\n", Status);
if (!NT_SUCCESS(Status) || !gpklFirst) pKl->hkl = hKL;
pKl->spkf = UserLoadKbdFile(pwszKLID);
/* Dereference keyboard layout */
UserDereferenceObject(pKl);
/* If we failed, remove KL object */
if (!pKl->spkf)
{ {
/* If failed load US keyboard layout */ ERR("UserLoadKbdFile(%wZ) failed!\n", pwszKLID);
ERR("Trying to load US Keyboard Layout.\n"); UserDeleteObject(pKl->head.h, otKBDlayout);
LocaleId = 0x409; return NULL;
}
if (!(gpklFirst = UserLoadDllAndCreateKbl(LocaleId))) return pKl;
}
/*
* UnloadKbdFile
*
* Destroys specified Keyboard File object
*/
static
VOID
UnloadKbdFile(PKBDFILE pkf)
{
PKBDFILE *ppkfLink = &gpkfList;
/* Find previous object */
while (*ppkfLink)
{
if (*ppkfLink == pkf)
break;
ppkfLink = &(*ppkfLink)->pkfNext;
}
if (*ppkfLink == pkf)
*ppkfLink = pkf->pkfNext;
EngUnloadImage(pkf->hBase);
UserDeleteObject(pkf->head.h, otKBDfile);
}
/*
* UserUnloadKbl
*
* Unloads specified Keyboard Layout if possible
*/
BOOL
UserUnloadKbl(PKL pKl)
{
/* According to msdn, UnloadKeyboardLayout can fail
if the keyboard layout identifier was preloaded. */
if (pKl == gspklBaseLayout)
{
if (pKl->pklNext == pKl->pklPrev)
{ {
ERR("Failed to load any Keyboard Layout\n"); /* There is only one layout */
return FALSE; return FALSE;
} }
/* Set next layout as default */
gspklBaseLayout = pKl->pklNext;
} }
/* Add layout to the list */ if (pKl->head.cLockObj > 1)
gpklFirst->Flags |= KBL_PRELOAD; {
InitializeListHead(&gpklFirst->List); /* Layout is used by other threads */
pKl->dwKL_Flags |= KLF_UNLOAD;
return FALSE;
}
/* Unload the layout */
pKl->pklPrev->pklNext = pKl->pklNext;
pKl->pklNext->pklPrev = pKl->pklPrev;
UnloadKbdFile(pKl->spkf);
UserDeleteObject(pKl->head.h, otKBDlayout);
return TRUE; return TRUE;
} }
/*
* W32kGetDefaultKeyLayout
*
* Returns default layout for new threads
*/
PKL PKL
W32kGetDefaultKeyLayout(VOID) W32kGetDefaultKeyLayout(VOID)
{ {
CONST WCHAR wszDefaultUserPath[] = L"\\REGISTRY\\USER\\.DEFAULT"; PKL pKl = gspklBaseLayout;
CONST WCHAR wszKeyboardLayoutPath[] = L"\\Keyboard Layout\\Preload";
WCHAR wszKbdLayoutKey[256], *pwsz;
size_t cbRemaining;
HKEY hKey;
ULONG cbValue;
LCID LayoutLocaleId = 0;
NTSTATUS Status;
PKL pKbl;
UNICODE_STRING CurrentUserPath;
WCHAR wszBuffer[MAX_PATH];
/* Try to get default alayout from HKCU\Keyboard Layout\Preload first */ if (!pKl)
Status = RtlFormatCurrentUserKeyPath(&CurrentUserPath); return NULL;
if (NT_SUCCESS(Status))
{
/* FIXME: We're called very early, so HKEY_CURRENT_USER might not be
available yet. Check this first. */
RtlStringCbCopyNExW(wszKbdLayoutKey, sizeof(wszKbdLayoutKey),
CurrentUserPath.Buffer, CurrentUserPath.Length,
&pwsz, &cbRemaining, 0);
RtlStringCbCopyW(pwsz, cbRemaining, wszKeyboardLayoutPath);
Status = RegOpenKey(wszKbdLayoutKey, &hKey);
/* Free CurrentUserPath - we dont need it anymore */ /* Return not unloaded layout */
RtlFreeUnicodeString(&CurrentUserPath);
}
/* If failed try HKU\.DEFAULT\Keyboard Layout\Preload */
if (!NT_SUCCESS(Status))
{
RtlStringCbCopyNExW(wszKbdLayoutKey, sizeof(wszKbdLayoutKey),
wszDefaultUserPath, sizeof(wszDefaultUserPath),
&pwsz, &cbRemaining, 0);
RtlStringCbCopyW(pwsz, cbRemaining, wszKeyboardLayoutPath);
Status = RegOpenKey(wszKbdLayoutKey, &hKey);
}
if (NT_SUCCESS(Status))
{
/* Return the first keyboard layout listed there */
cbValue = sizeof(wszBuffer);
Status = RegQueryValue(hKey, L"1", REG_SZ, wszBuffer, &cbValue);
if (NT_SUCCESS(Status))
LayoutLocaleId = (LCID)wcstol(wszBuffer, NULL, 16);
else
ERR("RegQueryValue failed (%08lx)\n", Status);
/* Close the key */
ZwClose(hKey);
}
else
ERR("Failed to open keyboard layout preload key (%08lx)\n", Status);
/* If we failed loading settings from registry use US layout */
if (!LayoutLocaleId)
{
ERR("Assuming default locale for the keyboard layout (0x409 - US)\n");
LayoutLocaleId = 0x409;
}
/* Check if layout is already loaded */
pKbl = gpklFirst;
do do
{ {
if (pKbl->klid == LayoutLocaleId) if (!(pKl->dwKL_Flags & KLF_UNLOAD))
return pKbl; return pKl;
pKbl = CONTAINING_RECORD(pKbl->List.Flink, KL, List); pKl = pKl->pklPrev; /* Confirmed on Win2k */
} while (pKbl != gpklFirst); } while(pKl != gspklBaseLayout);
/* Load the keyboard layout */ /* We have not found proper KL */
TRACE("Loading new default keyboard layout.\n"); return NULL;
pKbl = UserLoadDllAndCreateKbl(LayoutLocaleId);
if (!pKbl)
{
ERR("Failed to load %x!!! Returning any available KL.\n", LayoutLocaleId);
return gpklFirst;
}
/* Add loaded layout to the list */
InsertTailList(&gpklFirst->List, &pKbl->List);
return pKbl;
} }
/*
* UserHklToKbl
*
* Gets KL object from hkl value
*/
PKL PKL
UserHklToKbl(HKL hKl) UserHklToKbl(HKL hKl)
{ {
PKL pKbl = gpklFirst; PKL pKl = gspklBaseLayout;
if (!gspklBaseLayout)
return NULL;
do do
{ {
if (pKbl->hkl == hKl) if (pKl->hkl == hKl)
return pKbl; return pKl;
pKbl = CONTAINING_RECORD(pKbl->List.Flink, KL, List); pKl = pKl->pklNext;
} while (pKbl != gpklFirst); } while (pKl != gspklBaseLayout);
return NULL; return NULL;
} }
BOOL /*
UserUnloadKbl(PKL pKbl) * co_UserActivateKbl
{ *
/* According to msdn, UnloadKeyboardLayout can fail * Activates given layout in specified thread
if the keyboard layout identifier was preloaded. */ */
if (pKbl->Flags & KBL_PRELOAD)
{
ERR("Attempted to unload preloaded keyboard layout.\n");
return FALSE;
}
if (pKbl->RefCount > 0)
{
/* Layout is used by other threads.
Mark it as unloaded and don't do anything else. */
pKbl->Flags |= KBL_UNLOAD;
}
else
{
//Unload the layout
EngUnloadImage(pKbl->hModule);
RemoveEntryList(&pKbl->List);
ExFreePoolWithTag(pKbl, USERTAG_KBDLAYOUT);
}
return TRUE;
}
static PKL static PKL
co_UserActivateKbl(PTHREADINFO pti, PKL pKbl, UINT Flags) co_UserActivateKbl(PTHREADINFO pti, PKL pKl, UINT Flags)
{ {
PKL pklPrev; PKL pklPrev;
pklPrev = pti->KeyboardLayout; pklPrev = pti->KeyboardLayout;
pklPrev->RefCount--; if (pklPrev)
pti->KeyboardLayout = pKbl; UserDereferenceObject(pklPrev);
pKbl->RefCount++;
pti->KeyboardLayout = pKl;
UserReferenceObject(pKl);
if (Flags & KLF_SETFORPROCESS) if (Flags & KLF_SETFORPROCESS)
{ {
//FIXME //FIXME
}
if (pklPrev->Flags & KBL_UNLOAD && pklPrev->RefCount == 0)
{
UserUnloadKbl(pklPrev);
} }
// Send WM_INPUTLANGCHANGE to thread's focus window // Send WM_INPUTLANGCHANGE to thread's focus window
co_IntSendMessage(pti->MessageQueue->FocusWindow, co_IntSendMessage(pti->MessageQueue->FocusWindow,
WM_INPUTLANGCHANGE, WM_INPUTLANGCHANGE,
0, // FIXME: put charset here (what is this?) (WPARAM)pKl->iBaseCharset, // FIXME: how to set it?
(LPARAM)pKbl->hkl); //klid (LPARAM)pKl->hkl); //hkl
return pklPrev; return pklPrev;
} }
/* EXPORTS *******************************************************************/ /* EXPORTS *******************************************************************/
/*
* UserGetKeyboardLayout
*
* Returns hkl of given thread keyboard layout
*/
HKL FASTCALL HKL FASTCALL
UserGetKeyboardLayout( UserGetKeyboardLayout(
DWORD dwThreadId) DWORD dwThreadId)
{ {
NTSTATUS Status; NTSTATUS Status;
PETHREAD Thread; PETHREAD pThread;
PTHREADINFO pti; PTHREADINFO pti;
HKL Ret; PKL pKl;
HKL hKl;
if (!dwThreadId) if (!dwThreadId)
{ {
pti = PsGetCurrentThreadWin32Thread(); pti = PsGetCurrentThreadWin32Thread();
return pti->KeyboardLayout->hkl; pKl = pti->KeyboardLayout;
return pKl ? pKl->hkl : NULL;
} }
Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)dwThreadId, &Thread); Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)dwThreadId, &pThread);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
EngSetLastError(ERROR_INVALID_PARAMETER); EngSetLastError(ERROR_INVALID_PARAMETER);
return NULL; return NULL;
} }
pti = PsGetThreadWin32Thread(Thread); pti = PsGetThreadWin32Thread(pThread);
Ret = pti->KeyboardLayout->hkl; pKl = pti->KeyboardLayout;
ObDereferenceObject(Thread); hKl = pKl ? pKl->hkl : NULL;;
return Ret; ObDereferenceObject(pThread);
return hKl;
} }
/*
* NtUserGetKeyboardLayoutList
*
* Returns list of loaded keyboard layouts in system
*/
UINT UINT
APIENTRY APIENTRY
NtUserGetKeyboardLayoutList( NtUserGetKeyboardLayoutList(
INT nBuff, INT nBuff,
HKL* pHklBuff) HKL *pHklBuff)
{ {
UINT uRet = 0; UINT uRet = 0;
PKL pKbl; PKL pKl;
UserEnterShared();
pKbl = gpklFirst;
if (!pHklBuff) if (!pHklBuff)
nBuff = 0; nBuff = 0;
UserEnterShared();
if (!gspklBaseLayout)
return 0;
pKl = gspklBaseLayout;
if (nBuff == 0) if (nBuff == 0)
{ {
do do
{ {
uRet++; uRet++;
pKbl = CONTAINING_RECORD(pKbl->List.Flink, KL, List); pKl = pKl->pklNext;
} while (pKbl != gpklFirst); } while (pKl != gspklBaseLayout);
} }
else else
{ {
@ -437,16 +450,12 @@ NtUserGetKeyboardLayoutList(
while (uRet < nBuff) while (uRet < nBuff)
{ {
if (!(pKbl->Flags & KBL_UNLOAD)) pHklBuff[uRet] = pKl->hkl;
{ uRet++;
pHklBuff[uRet] = pKbl->hkl; pKl = pKl->pklNext;
uRet++; if (pKl == gspklBaseLayout)
pKbl = CONTAINING_RECORD(pKbl->List.Flink, KL, List); break;
if (pKbl == gpklFirst)
break;
}
} }
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{ {
@ -460,23 +469,32 @@ NtUserGetKeyboardLayoutList(
return uRet; return uRet;
} }
/*
* NtUserGetKeyboardLayoutName
*
* Returns KLID of current thread keyboard layout
*/
BOOL BOOL
APIENTRY APIENTRY
NtUserGetKeyboardLayoutName( NtUserGetKeyboardLayoutName(
LPWSTR lpszName) LPWSTR pwszName)
{ {
BOOL bRet = FALSE; BOOL bRet = FALSE;
PKL pKbl; PKL pKl;
PTHREADINFO pti; PTHREADINFO pti;
UserEnterShared(); UserEnterShared();
pti = PsGetCurrentThreadWin32Thread();
pKl = pti->KeyboardLayout;
if (!pKl)
goto cleanup;
_SEH2_TRY _SEH2_TRY
{ {
ProbeForWrite(lpszName, KL_NAMELENGTH*sizeof(WCHAR), 1); ProbeForWrite(pwszName, KL_NAMELENGTH*sizeof(WCHAR), 1);
pti = PsGetCurrentThreadWin32Thread(); wcscpy(pwszName, pKl->spkf->awchKF);
pKbl = pti->KeyboardLayout;
RtlCopyMemory(lpszName, pKbl->Name, KL_NAMELENGTH*sizeof(WCHAR));
bRet = TRUE; bRet = TRUE;
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
@ -485,155 +503,207 @@ NtUserGetKeyboardLayoutName(
} }
_SEH2_END; _SEH2_END;
cleanup:
UserLeave(); UserLeave();
return bRet; return bRet;
} }
/*
* NtUserLoadKeyboardLayoutEx
*
* Loads keyboard layout with given locale id
*/
HKL HKL
APIENTRY APIENTRY
NtUserLoadKeyboardLayoutEx( NtUserLoadKeyboardLayoutEx(
IN HANDLE Handle, IN HANDLE Handle, // hFile (See downloads.securityfocus.com/vulnerabilities/exploits/43774.c)
IN DWORD offTable, IN DWORD offTable, // offset to KbdTables
IN PUNICODE_STRING puszKeyboardName, IN PUNICODE_STRING puszKeyboardName, // not used?
IN HKL hKL, IN HKL hklUnload,
IN PUNICODE_STRING puszKLID, IN PUNICODE_STRING pustrKLID,
IN DWORD dwKLID, IN DWORD hkl,
IN UINT Flags) IN UINT Flags)
{ {
HKL hklRet = NULL; HKL hklRet = NULL;
PKL pKbl = NULL, pklCur; PKL pKl = NULL, pklLast;
WCHAR Buffer[9];
UNICODE_STRING ustrSafeKLID;
if (Flags & ~(KLF_ACTIVATE|KLF_NOTELLSHELL|KLF_REORDER|KLF_REPLACELANG| if (Flags & ~(KLF_ACTIVATE|KLF_NOTELLSHELL|KLF_REORDER|KLF_REPLACELANG|
KLF_SUBSTITUTE_OK|KLF_SETFORPROCESS|KLF_UNLOADPREVIOUS)) KLF_SUBSTITUTE_OK|KLF_SETFORPROCESS|KLF_UNLOADPREVIOUS|
KLF_RESET|KLF_SETFORPROCESS|KLF_SHIFTLOCK))
{ {
ERR("Invalid flags: %x\n", Flags); ERR("Invalid flags: %x\n", Flags);
EngSetLastError(ERROR_INVALID_FLAGS); EngSetLastError(ERROR_INVALID_FLAGS);
return 0; return NULL;
} }
/* FIXME: it seems KLF_RESET is only supported for WINLOGON */
RtlInitEmptyUnicodeString(&ustrSafeKLID, Buffer, sizeof(Buffer));
_SEH2_TRY
{
ProbeForRead(pustrKLID, sizeof(*pustrKLID), 1);
ProbeForRead(pustrKLID->Buffer, sizeof(pustrKLID->Length), 1);
RtlCopyUnicodeString(&ustrSafeKLID, pustrKLID);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastNtError(_SEH2_GetExceptionCode());
_SEH2_YIELD(return NULL);
}
_SEH2_END;
UserEnterExclusive(); UserEnterExclusive();
//Let's see if layout was already loaded. /* If hklUnload is specified, unload it and load new layput as default */
pklCur = gpklFirst; if (hklUnload && hklUnload != (HKL)hkl)
do
{ {
if (pklCur->klid == dwKLID) pKl = UserHklToKbl(hklUnload);
{ if (pKl)
pKbl = pklCur; UserUnloadKbl(pKl);
pKbl->Flags &= ~KBL_UNLOAD; }
break;
}
pklCur = CONTAINING_RECORD(pKbl->List.Flink, KL, List); /* Let's see if layout was already loaded. */
} while (pklCur != gpklFirst); pKl = UserHklToKbl((HKL)hkl);
if (!pKl)
//It wasn't, so load it.
if (!pKbl)
{ {
pKbl = UserLoadDllAndCreateKbl(dwKLID); /* It wasn't, so load it. */
pKl = UserLoadKbdLayout(&ustrSafeKLID, (HKL)hkl);
if (!pKbl) if (!pKl)
{
goto cleanup; goto cleanup;
if (gspklBaseLayout)
{
/* Find last not unloaded layout */
pklLast = gspklBaseLayout->pklPrev;
while (pklLast != gspklBaseLayout && pklLast->dwKL_Flags & KLF_UNLOAD)
pklLast = pklLast->pklPrev;
/* Add new layout to the list */
pKl->pklNext = pklLast->pklNext;
pKl->pklPrev = pklLast;
pKl->pklNext->pklPrev = pKl;
pKl->pklPrev->pklNext = pKl;
}
else
{
/* This is the first layout */
pKl->pklNext = pKl;
pKl->pklPrev = pKl;
gspklBaseLayout = pKl;
} }
InsertTailList(&gpklFirst->List, &pKbl->List);
} }
if (Flags & KLF_REORDER) gpklFirst = pKbl; /* If this layout was prepared to unload, undo it */
pKl->dwKL_Flags &= ~KLF_UNLOAD;
/* Loaded keyboard layout became the default */
gspklBaseLayout = pKl;
/* Activate this layout in current thread */
if (Flags & KLF_ACTIVATE) if (Flags & KLF_ACTIVATE)
{ co_UserActivateKbl(PsGetCurrentThreadWin32Thread(), pKl, Flags);
co_UserActivateKbl(PsGetCurrentThreadWin32Thread(), pKbl, Flags);
}
hklRet = pKbl->hkl; /* Send shell message */
if (!(Flags & KLF_NOTELLSHELL))
co_IntShellHookNotify(HSHELL_LANGUAGE, (LPARAM)hkl);
//FIXME: KLF_NOTELLSHELL /* Return hkl on success */
// KLF_REPLACELANG hklRet = (HKL)hkl;
// KLF_SUBSTITUTE_OK
/* FIXME: KLF_REPLACELANG
KLF_REORDER */
cleanup: cleanup:
UserLeave(); UserLeave();
return hklRet; return hklRet;
} }
/*
* NtUserActivateKeyboardLayout
*
* Activates specified layout for thread or process
*/
HKL HKL
APIENTRY APIENTRY
NtUserActivateKeyboardLayout( NtUserActivateKeyboardLayout(
HKL hKl, HKL hKl,
ULONG Flags) ULONG Flags)
{ {
PKL pKbl; PKL pKl = NULL;
HKL hklRet = NULL; HKL hkl = NULL;
PTHREADINFO pti; PTHREADINFO pti;
UserEnterExclusive(); UserEnterExclusive();
pti = PsGetCurrentThreadWin32Thread(); pti = PsGetCurrentThreadWin32Thread();
if (pti->KeyboardLayout->hkl == hKl) /* hKl can have special value HKL_NEXT or HKL_PREV */
{
hklRet = hKl;
goto cleanup;
}
if (hKl == (HKL)HKL_NEXT) if (hKl == (HKL)HKL_NEXT)
{ {
pKbl = CONTAINING_RECORD(pti->KeyboardLayout->List.Flink, KL, List); /* Get next keyboard layout starting with current */
if (pti->KeyboardLayout)
pKl = pti->KeyboardLayout->pklNext;
} }
else if (hKl == (HKL)HKL_PREV) else if (hKl == (HKL)HKL_PREV)
{ {
pKbl = CONTAINING_RECORD(pti->KeyboardLayout->List.Blink, KL, List); /* Get previous keyboard layout starting with current */
} if (pti->KeyboardLayout)
else pKbl = UserHklToKbl(hKl); pKl = pti->KeyboardLayout->pklNext;
//FIXME: KLF_RESET, KLF_SHIFTLOCK
if (pKbl)
{
if (Flags & KLF_REORDER)
gpklFirst = pKbl;
if (pKbl == pti->KeyboardLayout)
{
hklRet = pKbl->hkl;
}
else
{
pKbl = co_UserActivateKbl(pti, pKbl, Flags);
hklRet = pKbl->hkl;
}
} }
else else
pKl = UserHklToKbl(hKl);
if (!pKl)
{ {
ERR("Invalid HKL %x!\n", hKl); ERR("Invalid HKL %x!\n", hKl);
goto cleanup;
}
hkl = pKl->hkl;
/* FIXME: KLF_RESET
KLF_SHIFTLOCK */
if (Flags & KLF_REORDER)
gspklBaseLayout = pKl;
if (pKl != pti->KeyboardLayout)
{
/* Activate layout for current thread */
pKl = co_UserActivateKbl(pti, pKl, Flags);
/* Send shell message */
if (!(Flags & KLF_NOTELLSHELL))
co_IntShellHookNotify(HSHELL_LANGUAGE, (LPARAM)hkl);
} }
cleanup: cleanup:
UserLeave(); UserLeave();
return hklRet; return hkl;
} }
/*
* NtUserUnloadKeyboardLayout
*
* Unloads keyboard layout with specified hkl value
*/
BOOL BOOL
APIENTRY APIENTRY
NtUserUnloadKeyboardLayout( NtUserUnloadKeyboardLayout(
HKL hKl) HKL hKl)
{ {
PKL pKbl; PKL pKl;
BOOL bRet = FALSE; BOOL bRet = FALSE;
UserEnterExclusive(); UserEnterExclusive();
pKbl = UserHklToKbl(hKl); pKl = UserHklToKbl(hKl);
if (pKbl) if (pKl)
{ bRet = UserUnloadKbl(pKl);
bRet = UserUnloadKbl(pKbl);
}
else else
{
ERR("Invalid HKL %x!\n", hKl); ERR("Invalid HKL %x!\n", hKl);
}
UserLeave(); UserLeave();
return bRet; return bRet;

View file

@ -891,7 +891,7 @@ BOOL NTAPI
UserSendKeyboardInput(KEYBDINPUT *pKbdInput, BOOL bInjected) UserSendKeyboardInput(KEYBDINPUT *pKbdInput, BOOL bInjected)
{ {
WORD wScanCode, wVk; WORD wScanCode, wVk;
PKL pKbl = NULL; PKL pKl = NULL;
PKBDTABLES pKbdTbl; PKBDTABLES pKbdTbl;
PUSER_MESSAGE_QUEUE pFocusQueue; PUSER_MESSAGE_QUEUE pFocusQueue;
struct _ETHREAD *pFocusThread; struct _ETHREAD *pFocusThread;
@ -906,18 +906,18 @@ UserSendKeyboardInput(KEYBDINPUT *pKbdInput, BOOL bInjected)
{ {
pFocusThread = pFocusQueue->Thread; pFocusThread = pFocusQueue->Thread;
if (pFocusThread && pFocusThread->Tcb.Win32Thread) if (pFocusThread && pFocusThread->Tcb.Win32Thread)
pKbl = ((PTHREADINFO)pFocusThread->Tcb.Win32Thread)->KeyboardLayout; pKl = ((PTHREADINFO)pFocusThread->Tcb.Win32Thread)->KeyboardLayout;
} }
if (!pKbl) if (!pKl)
pKbl = W32kGetDefaultKeyLayout(); pKl = W32kGetDefaultKeyLayout();
if (!pKbl) if (!pKl)
{ {
ERR("No keyboard layout!\n"); ERR("No keyboard layout!\n");
return FALSE; return FALSE;
} }
pKbdTbl = pKbl->KBTables; pKbdTbl = pKl->spkf->pKbdTbl;
/* Note: wScan field is always used */ /* Note: wScan field is always used */
wScanCode = pKbdInput->wScan; wScanCode = pKbdInput->wScan;
@ -973,7 +973,7 @@ UserProcessKeyboardInput(
PKEYBOARD_INPUT_DATA pKbdInputData) PKEYBOARD_INPUT_DATA pKbdInputData)
{ {
WORD wScanCode, wVk; WORD wScanCode, wVk;
PKL pKbl = NULL; PKL pKl = NULL;
PKBDTABLES pKbdTbl; PKBDTABLES pKbdTbl;
PUSER_MESSAGE_QUEUE pFocusQueue; PUSER_MESSAGE_QUEUE pFocusQueue;
struct _ETHREAD *pFocusThread; struct _ETHREAD *pFocusThread;
@ -992,15 +992,15 @@ UserProcessKeyboardInput(
{ {
pFocusThread = pFocusQueue->Thread; pFocusThread = pFocusQueue->Thread;
if (pFocusThread && pFocusThread->Tcb.Win32Thread) if (pFocusThread && pFocusThread->Tcb.Win32Thread)
pKbl = ((PTHREADINFO)pFocusThread->Tcb.Win32Thread)->KeyboardLayout; pKl = ((PTHREADINFO)pFocusThread->Tcb.Win32Thread)->KeyboardLayout;
} }
if (!pKbl) if (!pKl)
pKbl = W32kGetDefaultKeyLayout(); pKl = W32kGetDefaultKeyLayout();
if (!pKbl) if (!pKl)
return; return;
pKbdTbl = pKbl->KBTables; pKbdTbl = pKl->spkf->pKbdTbl;
/* Convert scan code to virtual key. /* Convert scan code to virtual key.
Note: we could call UserSendKeyboardInput using scan code, Note: we could call UserSendKeyboardInput using scan code,
@ -1068,7 +1068,7 @@ IntTranslateKbdMessage(LPMSG lpMsg,
} }
pti = pWnd->head.pti; pti = pWnd->head.pti;
pKbdTbl = pti->KeyboardLayout->KBTables; pKbdTbl = pti->KeyboardLayout->spkf->pKbdTbl;
if (!pKbdTbl) if (!pKbdTbl)
return FALSE; return FALSE;
@ -1207,15 +1207,15 @@ NtUserMapVirtualKeyEx(UINT uCode, UINT uType, DWORD keyboardId, HKL dwhkl)
pti = PsGetCurrentThreadWin32Thread(); pti = PsGetCurrentThreadWin32Thread();
if (pti && pti->KeyboardLayout) if (pti && pti->KeyboardLayout)
pKbdTbl = pti->KeyboardLayout->KBTables; pKbdTbl = pti->KeyboardLayout->spkf->pKbdTbl;
} }
else else
{ {
PKL pKbl; PKL pKl;
pKbl = UserHklToKbl(dwhkl); pKl = UserHklToKbl(dwhkl);
if (pKbl) if (pKl)
pKbdTbl = pKbl->KBTables; pKbdTbl = pKl->spkf->pKbdTbl;
} }
if (pKbdTbl) if (pKbdTbl)
@ -1246,7 +1246,7 @@ NtUserToUnicodeEx(
BYTE afKeyState[256 * 2 / 8] = {0}; BYTE afKeyState[256 * 2 / 8] = {0};
PWCHAR pwszBuff = NULL; PWCHAR pwszBuff = NULL;
INT i, iRet = 0; INT i, iRet = 0;
PKL pKbl = NULL; PKL pKl = NULL;
TRACE("Enter NtUserSetKeyboardState\n"); TRACE("Enter NtUserSetKeyboardState\n");
@ -1288,12 +1288,12 @@ NtUserToUnicodeEx(
UserEnterExclusive(); // Note: we modify wchDead static variable UserEnterExclusive(); // Note: we modify wchDead static variable
if (dwhkl) if (dwhkl)
pKbl = UserHklToKbl(dwhkl); pKl = UserHklToKbl(dwhkl);
if (!pKbl) if (!pKl)
{ {
pti = PsGetCurrentThreadWin32Thread(); pti = PsGetCurrentThreadWin32Thread();
pKbl = pti->KeyboardLayout; pKl = pti->KeyboardLayout;
} }
iRet = IntToUnicodeEx(wVirtKey, iRet = IntToUnicodeEx(wVirtKey,
@ -1302,7 +1302,7 @@ NtUserToUnicodeEx(
pwszBuff, pwszBuff,
cchBuff, cchBuff,
wFlags, wFlags,
pKbl ? pKbl->KBTables : NULL); pKl ? pKl->spkf->pKbdTbl : NULL);
MmCopyToCaller(pwszBuffUnsafe, pwszBuff, cchBuff * sizeof(WCHAR)); MmCopyToCaller(pwszBuffUnsafe, pwszBuff, cchBuff * sizeof(WCHAR));
ExFreePoolWithTag(pwszBuff, TAG_STRING); ExFreePoolWithTag(pwszBuff, TAG_STRING);
@ -1336,7 +1336,7 @@ NtUserGetKeyNameText(LONG lParam, LPWSTR lpString, int cchSize)
/* Get current keyboard layout */ /* Get current keyboard layout */
pti = PsGetCurrentThreadWin32Thread(); pti = PsGetCurrentThreadWin32Thread();
pKbdTbl = pti ? pti->KeyboardLayout->KBTables : 0; pKbdTbl = pti ? pti->KeyboardLayout->spkf->pKbdTbl : 0;
if (!pKbdTbl || cchSize < 1) if (!pKbdTbl || cchSize < 1)
{ {
@ -1451,7 +1451,7 @@ NtUserVkKeyScanEx(
PKBDTABLES pKbdTbl; PKBDTABLES pKbdTbl;
PVK_TO_WCHAR_TABLE pVkToWchTbl; PVK_TO_WCHAR_TABLE pVkToWchTbl;
PVK_TO_WCHARS10 pVkToWch; PVK_TO_WCHARS10 pVkToWch;
PKL pKbl = NULL; PKL pKl = NULL;
DWORD i, dwModBits = 0, dwModNumber = 0, Ret = (DWORD)-1; DWORD i, dwModBits = 0, dwModNumber = 0, Ret = (DWORD)-1;
TRACE("NtUserVkKeyScanEx() wch %d, KbdLayout 0x%p\n", wch, dwhkl); TRACE("NtUserVkKeyScanEx() wch %d, KbdLayout 0x%p\n", wch, dwhkl);
@ -1461,18 +1461,18 @@ NtUserVkKeyScanEx(
{ {
// Use given keyboard layout // Use given keyboard layout
if (dwhkl) if (dwhkl)
pKbl = UserHklToKbl(dwhkl); pKl = UserHklToKbl(dwhkl);
} }
else else
{ {
// Use thread keyboard layout // Use thread keyboard layout
pKbl = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->KeyboardLayout; pKl = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->KeyboardLayout;
} }
if (!pKbl) if (!pKl)
goto Exit; goto Exit;
pKbdTbl = pKbl->KBTables; pKbdTbl = pKl->spkf->pKbdTbl;
// Interate through all VkToWchar tables while pVkToWchars is not NULL // Interate through all VkToWchar tables while pVkToWchars is not NULL
for (i = 0; pKbdTbl->pVkToWcharTable[i].pVkToWchars; i++) for (i = 0; pKbdTbl->pVkToWcharTable[i].pVkToWchars; i++)