- Remove ReadRegistryValue in kbdlayout.c as we already implement RegQueryValue for reading from registry in W32k. This function additionally checks value type.
- Rename KBL to KL based on Techwiki
- HKCU\Keyboard Layout\Preload value is REG_SZ (not REG_EXPAND_SZ)
- NtUserLoadKeyboardLayoutEx should set last error if flags are invalid
- Minor keyboard layout code cleanup

svn path=/trunk/; revision=54163
This commit is contained in:
Rafal Harabien 2011-10-16 15:39:07 +00:00
parent a8c53e6e1a
commit 49793fea10
5 changed files with 285 additions and 371 deletions

View file

@ -8,7 +8,7 @@ HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
[AddReg] [AddReg]
; Default locale for the keyboard layout ; Default locale for the keyboard layout
HKU,".DEFAULT\Keyboard Layout\Preload","1",0x00020000,"00000409" HKU,".DEFAULT\Keyboard Layout\Preload","1",0x00000000,"00000409"
; Cdfs (ISO96660) filesystem driver ; Cdfs (ISO96660) filesystem driver
HKLM,"SYSTEM\CurrentControlSet\Services\Cdfs","Start",0x00010001,0x00000000 HKLM,"SYSTEM\CurrentControlSet\Services\Cdfs","Start",0x00010001,0x00000000

View file

@ -2,7 +2,7 @@
#include <ndk/kbd.h> #include <ndk/kbd.h>
typedef struct _KBL typedef struct _KL
{ {
LIST_ENTRY List; LIST_ENTRY List;
DWORD Flags; DWORD Flags;
@ -12,7 +12,7 @@ typedef struct _KBL
ULONG RefCount; ULONG RefCount;
HKL hkl; HKL hkl;
DWORD klid; // Low word - language id. High word - device id. DWORD klid; // Low word - language id. High word - device id.
} KBL, *PKBL; } KL, *PKL;
typedef struct _ATTACHINFO typedef struct _ATTACHINFO
{ {
@ -39,14 +39,14 @@ extern PATTACHINFO gpai;
INIT_FUNCTION NTSTATUS NTAPI InitInputImpl(VOID); INIT_FUNCTION NTSTATUS NTAPI InitInputImpl(VOID);
INIT_FUNCTION NTSTATUS NTAPI InitKeyboardImpl(VOID); INIT_FUNCTION NTSTATUS NTAPI InitKeyboardImpl(VOID);
VOID NTAPI UserInitKeyboard(HANDLE hKeyboardDevice); VOID NTAPI UserInitKeyboard(HANDLE hKeyboardDevice);
PKBL W32kGetDefaultKeyLayout(VOID); PKL W32kGetDefaultKeyLayout(VOID);
VOID NTAPI UserProcessKeyboardInput(PKEYBOARD_INPUT_DATA pKeyInput); VOID NTAPI UserProcessKeyboardInput(PKEYBOARD_INPUT_DATA pKeyInput);
BOOL NTAPI UserSendKeyboardInput(KEYBDINPUT *pKbdInput, BOOL bInjected); BOOL NTAPI UserSendKeyboardInput(KEYBDINPUT *pKbdInput, BOOL bInjected);
VOID NTAPI UserProcessMouseInput(PMOUSE_INPUT_DATA Data, ULONG InputCount); VOID NTAPI UserProcessMouseInput(PMOUSE_INPUT_DATA Data, ULONG InputCount);
BOOL FASTCALL IntBlockInput(PTHREADINFO W32Thread, BOOL BlockIt); BOOL FASTCALL IntBlockInput(PTHREADINFO W32Thread, BOOL BlockIt);
BOOL FASTCALL IntMouseInput(MOUSEINPUT *mi, BOOL Injected); BOOL FASTCALL IntMouseInput(MOUSEINPUT *mi, BOOL Injected);
BOOL UserInitDefaultKeyboardLayout(VOID); BOOL UserInitDefaultKeyboardLayout(VOID);
PKBL UserHklToKbl(HKL hKl); PKL UserHklToKbl(HKL hKl);
VOID NTAPI KeyboardThreadMain(PVOID StartContext); VOID NTAPI KeyboardThreadMain(PVOID StartContext);
DWORD NTAPI CreateSystemThreads(UINT Type); DWORD NTAPI CreateSystemThreads(UINT Type);
BOOL FASTCALL UserAttachThreadInput(PTHREADINFO,PTHREADINFO,BOOL); BOOL FASTCALL UserAttachThreadInput(PTHREADINFO,PTHREADINFO,BOOL);

View file

@ -69,7 +69,7 @@ typedef struct _THREADINFO
PTL ptl; PTL ptl;
PPROCESSINFO ppi; PPROCESSINFO ppi;
struct _USER_MESSAGE_QUEUE* MessageQueue; struct _USER_MESSAGE_QUEUE* MessageQueue;
struct _KBL* KeyboardLayout; struct _KL* KeyboardLayout;
PCLIENTTHREADINFO pcti; PCLIENTTHREADINFO pcti;
struct _DESKTOP* rpdesk; struct _DESKTOP* rpdesk;
PDESKTOPINFO pDeskInfo; PDESKTOPINFO pDeskInfo;
@ -188,7 +188,7 @@ typedef struct _PROCESSINFO
LIST_ENTRY PrivateFontListHead; LIST_ENTRY PrivateFontListHead;
FAST_MUTEX DriverObjListLock; FAST_MUTEX DriverObjListLock;
LIST_ENTRY DriverObjListHead; LIST_ENTRY DriverObjListHead;
struct _KBL* KeyboardLayout; // THREADINFO only struct _KL* KeyboardLayout; // THREADINFO only
W32HEAP_USER_MAPPING HeapMappings; W32HEAP_USER_MAPPING HeapMappings;
struct _GDI_POOL *pPoolDcAttr; struct _GDI_POOL *pPoolDcAttr;
struct _GDI_POOL *pPoolBrushAttr; struct _GDI_POOL *pPoolBrushAttr;

View file

@ -5,164 +5,74 @@
* PURPOSE: Keyboard layout management * PURPOSE: Keyboard layout management
* COPYRIGHT: Copyright 2007 Saveliy Tretiakov * COPYRIGHT: Copyright 2007 Saveliy Tretiakov
* Copyright 2008 Colin Finck * Copyright 2008 Colin Finck
* Copyright 2011 Rafal Harabien
*/ */
#include <win32k.h> #include <win32k.h>
DBG_DEFAULT_CHANNEL(UserKbdLayout); DBG_DEFAULT_CHANNEL(UserKbdLayout);
PKBL KBLList = NULL; // Keyboard layout list. PKL gpklFirst = NULL; // Keyboard layout list.
typedef PVOID (*KbdLayerDescriptor)(VOID); typedef PVOID (*PFNKBDLAYERDESCRIPTOR)(VOID);
/* PRIVATE FUNCTIONS ******************************************************/ /* PRIVATE FUNCTIONS ******************************************************/
static BOOL
/* UserLoadKbdDll(CONST WCHAR *wszKLID,
* Utility function to read a value from the registry more easily.
*
* IN PUNICODE_STRING KeyName -> Name of key to open
* IN PUNICODE_STRING ValueName -> Name of value to open
* OUT PUNICODE_STRING ReturnedValue -> String contained in registry
*
* Returns NTSTATUS
*/
static NTSTATUS APIENTRY ReadRegistryValue( PUNICODE_STRING KeyName,
PUNICODE_STRING ValueName,
PUNICODE_STRING ReturnedValue )
{
NTSTATUS Status;
HANDLE KeyHandle;
OBJECT_ATTRIBUTES KeyAttributes;
PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo;
ULONG Length = 0;
ULONG ResLength = 0;
PWCHAR ReturnBuffer;
InitializeObjectAttributes(&KeyAttributes, KeyName, OBJ_CASE_INSENSITIVE,
NULL, NULL);
Status = ZwOpenKey(&KeyHandle, KEY_READ, &KeyAttributes);
if (!NT_SUCCESS(Status))
{
return Status;
}
Status = ZwQueryValueKey(KeyHandle, ValueName, KeyValuePartialInformation,
0,
0,
&ResLength);
if (Status != STATUS_BUFFER_TOO_SMALL)
{
NtClose(KeyHandle);
return Status;
}
ResLength += sizeof(*KeyValuePartialInfo);
KeyValuePartialInfo =
ExAllocatePoolWithTag(PagedPool, ResLength, TAG_STRING);
Length = ResLength;
if (!KeyValuePartialInfo)
{
NtClose(KeyHandle);
return STATUS_NO_MEMORY;
}
Status = ZwQueryValueKey(KeyHandle,
ValueName,
KeyValuePartialInformation,
(PVOID)KeyValuePartialInfo,
Length,
&ResLength);
if (!NT_SUCCESS(Status))
{
NtClose(KeyHandle);
ExFreePoolWithTag(KeyValuePartialInfo, TAG_STRING);
return Status;
}
/* At this point, KeyValuePartialInfo->Data contains the key data */
ReturnBuffer = ExAllocatePoolWithTag(PagedPool,
KeyValuePartialInfo->DataLength,
TAG_STRING);
if (!ReturnBuffer)
{
NtClose(KeyHandle);
ExFreePoolWithTag(KeyValuePartialInfo, TAG_STRING);
return STATUS_NO_MEMORY;
}
RtlCopyMemory(ReturnBuffer,
KeyValuePartialInfo->Data,
KeyValuePartialInfo->DataLength);
RtlInitUnicodeString(ReturnedValue, ReturnBuffer);
ExFreePoolWithTag(KeyValuePartialInfo, TAG_STRING);
NtClose(KeyHandle);
return Status;
}
static BOOL UserLoadKbdDll(WCHAR *wsKLID,
HANDLE *phModule, HANDLE *phModule,
PKBDTABLES *pKbdTables) PKBDTABLES *pKbdTables)
{ {
NTSTATUS Status; NTSTATUS Status;
KbdLayerDescriptor layerDescGetFn; HKEY hKey;
ANSI_STRING kbdProcedureName; ULONG cbSize;
UNICODE_STRING LayoutKeyName; PFNKBDLAYERDESCRIPTOR pfnKbdLayerDescriptor;
UNICODE_STRING LayoutValueName; WCHAR wszLayoutRegKey[256] = L"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet\\"
UNICODE_STRING LayoutFile; L"Control\\Keyboard Layouts\\";
UNICODE_STRING FullLayoutPath; WCHAR wszLayoutPath[MAX_PATH] = L"\\SystemRoot\\System32\\";
UNICODE_STRING klid;
WCHAR LayoutPathBuffer[MAX_PATH] = L"\\SystemRoot\\System32\\";
WCHAR KeyNameBuffer[MAX_PATH] = L"\\REGISTRY\\Machine\\SYSTEM\\"
L"CurrentControlSet\\Control\\Keyboard Layouts\\";
RtlInitUnicodeString(&klid, wsKLID);
RtlInitUnicodeString(&LayoutValueName, L"Layout File");
RtlInitUnicodeString(&LayoutKeyName, KeyNameBuffer);
LayoutKeyName.MaximumLength = sizeof(KeyNameBuffer);
RtlAppendUnicodeStringToString(&LayoutKeyName, &klid);
Status = ReadRegistryValue(&LayoutKeyName, &LayoutValueName, &LayoutFile);
/* Open layout registry key */
RtlStringCbCatW(wszLayoutRegKey, sizeof(wszLayoutRegKey), wszKLID);
Status = RegOpenKey(wszLayoutRegKey, &hKey);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
TRACE("Can't get layout filename for %wZ. (%08lx)\n", klid, Status); ERR("Failed to open keyboard layouts registry key %ws (%lx)\n", wszKLID, Status);
return FALSE; return FALSE;
} }
TRACE("Read registry and got %wZ\n", &LayoutFile); /* Read filename of layout DLL and close the key */
RtlInitUnicodeString(&FullLayoutPath, LayoutPathBuffer); cbSize = sizeof(wszLayoutPath) - (wcslen(wszLayoutPath) + 1)*sizeof(WCHAR);
FullLayoutPath.MaximumLength = sizeof(LayoutPathBuffer); Status = RegQueryValue(hKey,
RtlAppendUnicodeStringToString(&FullLayoutPath, &LayoutFile); L"Layout File",
TRACE("Loading Keyboard DLL %wZ\n", &FullLayoutPath); REG_SZ,
ExFreePoolWithTag(LayoutFile.Buffer, TAG_STRING); wszLayoutPath + wcslen(wszLayoutPath),
&cbSize);
*phModule = EngLoadImage(FullLayoutPath.Buffer); ZwClose(hKey);
if (!NT_SUCCESS(Status))
if (*phModule)
{ {
TRACE("Loaded %wZ\n", &FullLayoutPath); TRACE("Can't get layout filename for %ws (%lx)\n", wszKLID, Status);
return FALSE;
RtlInitAnsiString( &kbdProcedureName, "KbdLayerDescriptor" );
layerDescGetFn = EngFindImageProcAddress(*phModule, "KbdLayerDescriptor");
if (layerDescGetFn)
{
*pKbdTables = layerDescGetFn();
} }
/* Load keyboard layout DLL */
TRACE("Loading Keyboard DLL %ws\n", wszLayoutPath);
*phModule = EngLoadImage(wszLayoutPath);
if (!(*phModule))
{
ERR("Failed to load dll %ws\n", wszLayoutPath);
return FALSE;
}
/* Find KbdLayerDescriptor function and get layout tables */
TRACE("Loaded %ws\n", wszLayoutPath);
pfnKbdLayerDescriptor = EngFindImageProcAddress(*phModule, "KbdLayerDescriptor");
if (pfnKbdLayerDescriptor)
*pKbdTables = pfnKbdLayerDescriptor();
else else
{ ERR("Error: %ws has no KbdLayerDescriptor()\n", wszLayoutPath);
ERR("Error: %wZ has no KbdLayerDescriptor()\n", &FullLayoutPath);
}
if (!layerDescGetFn || !*pKbdTables) if (!pfnKbdLayerDescriptor || !*pKbdTables)
{ {
ERR("Failed to load the keyboard layout.\n"); ERR("Failed to load the keyboard layout.\n");
EngUnloadImage(*phModule); EngUnloadImage(*phModule);
@ -217,39 +127,34 @@ static BOOL UserLoadKbdDll(WCHAR *wsKLID,
++pVscVk; ++pVscVk;
} }
DbgPrint("}\n"); DbgPrint("}\n");
}
DbgBreakPoint(); DbgBreakPoint();
}
#endif #endif
}
else
{
ERR("Failed to load dll %wZ\n", &FullLayoutPath);
return FALSE;
}
return TRUE; return TRUE;
} }
static PKBL UserLoadDllAndCreateKbl(DWORD LocaleId) static PKL
UserLoadDllAndCreateKbl(DWORD LocaleId)
{ {
PKBL NewKbl; PKL pNewKbl;
ULONG hKl; ULONG hKl;
LANGID langid; LANGID langid;
NewKbl = ExAllocatePoolWithTag(PagedPool, sizeof(KBL), USERTAG_KBDLAYOUT); pNewKbl = ExAllocatePoolWithTag(PagedPool, sizeof(KL), USERTAG_KBDLAYOUT);
if (!NewKbl) if (!pNewKbl)
{ {
ERR("%s: Can't allocate memory!\n", __FUNCTION__); ERR("Can't allocate memory!\n");
return NULL; return NULL;
} }
swprintf(NewKbl->Name, L"%08lx", LocaleId); swprintf(pNewKbl->Name, L"%08lx", LocaleId);
if (!UserLoadKbdDll(NewKbl->Name, &NewKbl->hModule, &NewKbl->KBTables)) if (!UserLoadKbdDll(pNewKbl->Name, &pNewKbl->hModule, &pNewKbl->KBTables))
{ {
TRACE("%s: failed to load %x dll!\n", __FUNCTION__, LocaleId); ERR("Failed to load %x dll!\n", LocaleId);
ExFreePoolWithTag(NewKbl, USERTAG_KBDLAYOUT); ExFreePoolWithTag(pNewKbl, USERTAG_KBDLAYOUT);
return NULL; return NULL;
} }
@ -265,158 +170,155 @@ static PKBL UserLoadDllAndCreateKbl(DWORD LocaleId)
hKl |= 0xe001 << 16; /* FIXME */ hKl |= 0xe001 << 16; /* FIXME */
else hKl |= hKl << 16; else hKl |= hKl << 16;
NewKbl->hkl = (HKL)(ULONG_PTR) hKl; pNewKbl->hkl = (HKL)(ULONG_PTR) hKl;
NewKbl->klid = LocaleId; pNewKbl->klid = LocaleId;
NewKbl->Flags = 0; pNewKbl->Flags = 0;
NewKbl->RefCount = 0; pNewKbl->RefCount = 0;
return NewKbl; return pNewKbl;
} }
BOOL UserInitDefaultKeyboardLayout() BOOL
UserInitDefaultKeyboardLayout()
{ {
LCID LocaleId; LCID LocaleId;
NTSTATUS Status; NTSTATUS Status;
/* Load keyboard layout for default locale */
Status = ZwQueryDefaultLocale(FALSE, &LocaleId); Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
if (!NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{
ERR("Could not get default locale (%08lx).\n", Status);
}
else
{ {
TRACE("DefaultLocale = %08lx\n", LocaleId); TRACE("DefaultLocale = %08lx\n", LocaleId);
gpklFirst = UserLoadDllAndCreateKbl(LocaleId);
} }
else
ERR("Could not get default locale (%08lx).\n", Status);
if (!NT_SUCCESS(Status) || !(KBLList = UserLoadDllAndCreateKbl(LocaleId))) if (!NT_SUCCESS(Status) || !gpklFirst)
{ {
/* If failed load US keyboard layout */
ERR("Trying to load US Keyboard Layout.\n"); ERR("Trying to load US Keyboard Layout.\n");
LocaleId = 0x409; LocaleId = 0x409;
if (!(KBLList = UserLoadDllAndCreateKbl(LocaleId))) if (!(gpklFirst = UserLoadDllAndCreateKbl(LocaleId)))
{ {
ERR("Failed to load any Keyboard Layout\n"); ERR("Failed to load any Keyboard Layout\n");
return FALSE; return FALSE;
} }
} }
KBLList->Flags |= KBL_PRELOAD; /* Add layout to the list */
gpklFirst->Flags |= KBL_PRELOAD;
InitializeListHead(&gpklFirst->List);
InitializeListHead(&KBLList->List);
return TRUE; return TRUE;
} }
PKBL W32kGetDefaultKeyLayout(VOID) PKL
W32kGetDefaultKeyLayout(VOID)
{ {
const WCHAR szKeyboardLayoutPath[] = L"\\Keyboard Layout\\Preload"; CONST WCHAR wszDefaultUserPath[] = L"\\REGISTRY\\USER\\.DEFAULT";
const WCHAR szDefaultUserPath[] = L"\\REGISTRY\\USER\\.DEFAULT"; CONST WCHAR wszKeyboardLayoutPath[] = L"\\Keyboard Layout\\Preload";
WCHAR wszKbdLayoutKey[256], *pwsz;
HANDLE KeyHandle; size_t cbRemaining;
HKEY hKey;
ULONG cbValue;
LCID LayoutLocaleId = 0; LCID LayoutLocaleId = 0;
NTSTATUS Status; NTSTATUS Status;
OBJECT_ATTRIBUTES KeyAttributes; PKL pKbl;
PKBL pKbl;
UNICODE_STRING CurrentUserPath; UNICODE_STRING CurrentUserPath;
UNICODE_STRING FullKeyboardLayoutPath;
UNICODE_STRING LayoutValueName;
UNICODE_STRING LayoutLocaleIdString;
WCHAR wszBuffer[MAX_PATH]; WCHAR wszBuffer[MAX_PATH];
// Get the path to HKEY_CURRENT_USER /* Try to get default alayout from HKCU\Keyboard Layout\Preload first */
Status = RtlFormatCurrentUserKeyPath(&CurrentUserPath); Status = RtlFormatCurrentUserKeyPath(&CurrentUserPath);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
FullKeyboardLayoutPath.Buffer = wszBuffer; /* FIXME: We're called very early, so HKEY_CURRENT_USER might not be
FullKeyboardLayoutPath.MaximumLength = sizeof(wszBuffer); available yet. Check this first. */
RtlStringCbCopyNExW(wszKbdLayoutKey, sizeof(wszKbdLayoutKey),
CurrentUserPath.Buffer, CurrentUserPath.Length,
&pwsz, &cbRemaining, 0);
RtlStringCbCopyW(pwsz, cbRemaining, wszKeyboardLayoutPath);
Status = RegOpenKey(wszKbdLayoutKey, &hKey);
// FIXME: Is this 100% correct? /* Free CurrentUserPath - we dont need it anymore */
// We're called very early, so HKEY_CURRENT_USER might not be available yet. Check this first.
InitializeObjectAttributes(&KeyAttributes, &CurrentUserPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwOpenKey(&KeyHandle, KEY_READ, &KeyAttributes);
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
{
// It is not available, so read it from HKEY_USERS\.DEFAULT
FullKeyboardLayoutPath.Length = sizeof(szDefaultUserPath) - sizeof(UNICODE_NULL);
RtlCopyMemory(wszBuffer, szDefaultUserPath, sizeof(szDefaultUserPath));
}
else
{
// The path is available
ZwClose(KeyHandle);
RtlCopyUnicodeString(&FullKeyboardLayoutPath, &CurrentUserPath);
}
// Free CurrentUserPath - we dont need it anymore
RtlFreeUnicodeString(&CurrentUserPath); RtlFreeUnicodeString(&CurrentUserPath);
}
Status = RtlAppendUnicodeToString(&FullKeyboardLayoutPath, szKeyboardLayoutPath); /* 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)) if (NT_SUCCESS(Status))
{ {
// Return the first keyboard layout listed there /* Return the first keyboard layout listed there */
RtlInitUnicodeString(&LayoutValueName, L"1"); cbValue = sizeof(wszBuffer);
Status = RegQueryValue(hKey, L"1", REG_SZ, wszBuffer, &cbValue);
Status = ReadRegistryValue(&FullKeyboardLayoutPath, &LayoutValueName, &LayoutLocaleIdString);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ LayoutLocaleId = (LCID)wcstol(wszBuffer, NULL, 16);
RtlUnicodeStringToInteger(&LayoutLocaleIdString, 16, &LayoutLocaleId);
ExFreePoolWithTag(LayoutLocaleIdString.Buffer, TAG_STRING);
}
else else
ERR("ReadRegistryValue failed! (%08lx).\n", Status); ERR("RegQueryValue failed (%08lx)\n", Status);
}
else
ERR("RtlAppendUnicodeToString failed! (%08lx)\n", Status);
}
else
ERR("RtlFormatCurrentUserKeyPath 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) if (!LayoutLocaleId)
{ {
ERR("Assuming default locale for the keyboard layout (0x409 - US)\n"); ERR("Assuming default locale for the keyboard layout (0x409 - US)\n");
LayoutLocaleId = 0x409; LayoutLocaleId = 0x409;
} }
pKbl = KBLList; /* Check if layout is already loaded */
pKbl = gpklFirst;
do do
{ {
if (pKbl->klid == LayoutLocaleId) if (pKbl->klid == LayoutLocaleId)
{
return pKbl; return pKbl;
}
pKbl = (PKBL) pKbl->List.Flink; pKbl = CONTAINING_RECORD(pKbl->List.Flink, KL, List);
} while (pKbl != KBLList); } while (pKbl != gpklFirst);
/* Load the keyboard layout */
TRACE("Loading new default keyboard layout.\n"); TRACE("Loading new default keyboard layout.\n");
pKbl = UserLoadDllAndCreateKbl(LayoutLocaleId); pKbl = UserLoadDllAndCreateKbl(LayoutLocaleId);
if (!pKbl) if (!pKbl)
{ {
TRACE("Failed to load %x!!! Returning any availableKL.\n", LayoutLocaleId); ERR("Failed to load %x!!! Returning any available KL.\n", LayoutLocaleId);
return KBLList; return gpklFirst;
} }
InsertTailList(&KBLList->List, &pKbl->List); /* Add loaded layout to the list */
InsertTailList(&gpklFirst->List, &pKbl->List);
return pKbl; return pKbl;
} }
PKBL UserHklToKbl(HKL hKl) PKL
UserHklToKbl(HKL hKl)
{ {
PKBL pKbl = KBLList; PKL pKbl = gpklFirst;
do do
{ {
if (pKbl->hkl == hKl) return pKbl; if (pKbl->hkl == hKl)
pKbl = (PKBL) pKbl->List.Flink; return pKbl;
} while (pKbl != KBLList);
pKbl = CONTAINING_RECORD(pKbl->List.Flink, KL, List);
} while (pKbl != gpklFirst);
return NULL; return NULL;
} }
BOOL UserUnloadKbl(PKBL pKbl) BOOL
UserUnloadKbl(PKL pKbl)
{ {
/* According to msdn, UnloadKeyboardLayout can fail /* According to msdn, UnloadKeyboardLayout can fail
if the keyboard layout identifier was preloaded. */ if the keyboard layout identifier was preloaded. */
@ -444,13 +346,14 @@ BOOL UserUnloadKbl(PKBL pKbl)
return TRUE; return TRUE;
} }
static PKBL co_UserActivateKbl(PTHREADINFO w32Thread, PKBL pKbl, UINT Flags) static PKL
co_UserActivateKbl(PTHREADINFO pti, PKL pKbl, UINT Flags)
{ {
PKBL Prev; PKL pklPrev;
Prev = w32Thread->KeyboardLayout; pklPrev = pti->KeyboardLayout;
Prev->RefCount--; pklPrev->RefCount--;
w32Thread->KeyboardLayout = pKbl; pti->KeyboardLayout = pKbl;
pKbl->RefCount++; pKbl->RefCount++;
if (Flags & KLF_SETFORPROCESS) if (Flags & KLF_SETFORPROCESS)
@ -459,18 +362,18 @@ static PKBL co_UserActivateKbl(PTHREADINFO w32Thread, PKBL pKbl, UINT Flags)
} }
if (Prev->Flags & KBL_UNLOAD && Prev->RefCount == 0) if (pklPrev->Flags & KBL_UNLOAD && pklPrev->RefCount == 0)
{ {
UserUnloadKbl(Prev); UserUnloadKbl(pklPrev);
} }
// Send WM_INPUTLANGCHANGE to thread's focus window // Send WM_INPUTLANGCHANGE to thread's focus window
co_IntSendMessage(w32Thread->MessageQueue->FocusWindow, co_IntSendMessage(pti->MessageQueue->FocusWindow,
WM_INPUTLANGCHANGE, WM_INPUTLANGCHANGE,
0, // FIXME: put charset here (what is this?) 0, // FIXME: put charset here (what is this?)
(LPARAM)pKbl->hkl); //klid (LPARAM)pKbl->hkl); //klid
return Prev; return pklPrev;
} }
/* EXPORTS *******************************************************************/ /* EXPORTS *******************************************************************/
@ -481,13 +384,13 @@ UserGetKeyboardLayout(
{ {
NTSTATUS Status; NTSTATUS Status;
PETHREAD Thread; PETHREAD Thread;
PTHREADINFO W32Thread; PTHREADINFO pti;
HKL Ret; HKL Ret;
if (!dwThreadId) if (!dwThreadId)
{ {
W32Thread = PsGetCurrentThreadWin32Thread(); pti = PsGetCurrentThreadWin32Thread();
return W32Thread->KeyboardLayout->hkl; return pti->KeyboardLayout->hkl;
} }
Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)dwThreadId, &Thread); Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)dwThreadId, &Thread);
@ -497,8 +400,8 @@ UserGetKeyboardLayout(
return NULL; return NULL;
} }
W32Thread = PsGetThreadWin32Thread(Thread); pti = PsGetThreadWin32Thread(Thread);
Ret = W32Thread->KeyboardLayout->hkl; Ret = pti->KeyboardLayout->hkl;
ObDereferenceObject(Thread); ObDereferenceObject(Thread);
return Ret; return Ret;
} }
@ -506,37 +409,41 @@ UserGetKeyboardLayout(
UINT UINT
APIENTRY APIENTRY
NtUserGetKeyboardLayoutList( NtUserGetKeyboardLayoutList(
INT nItems, INT nBuff,
HKL* pHklBuff) HKL* pHklBuff)
{ {
UINT Ret = 0; UINT uRet = 0;
PKBL pKbl; PKL pKbl;
UserEnterShared(); UserEnterShared();
pKbl = KBLList; pKbl = gpklFirst;
if (nItems == 0) if (!pHklBuff)
nBuff = 0;
if (nBuff == 0)
{ {
do do
{ {
Ret++; uRet++;
pKbl = (PKBL) pKbl->List.Flink; pKbl = CONTAINING_RECORD(pKbl->List.Flink, KL, List);
} while (pKbl != KBLList); } while (pKbl != gpklFirst);
} }
else else
{ {
_SEH2_TRY _SEH2_TRY
{ {
ProbeForWrite(pHklBuff, nItems*sizeof(HKL), 4); ProbeForWrite(pHklBuff, nBuff*sizeof(HKL), 4);
while (Ret < nItems) while (uRet < nBuff)
{ {
if (!(pKbl->Flags & KBL_UNLOAD)) if (!(pKbl->Flags & KBL_UNLOAD))
{ {
pHklBuff[Ret] = pKbl->hkl; pHklBuff[uRet] = pKbl->hkl;
Ret++; uRet++;
pKbl = (PKBL) pKbl->List.Flink; pKbl = CONTAINING_RECORD(pKbl->List.Flink, KL, List);
if (pKbl == KBLList) break; if (pKbl == gpklFirst)
break;
} }
} }
@ -544,13 +451,13 @@ NtUserGetKeyboardLayoutList(
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{ {
SetLastNtError(_SEH2_GetExceptionCode()); SetLastNtError(_SEH2_GetExceptionCode());
Ret = 0; uRet = 0;
} }
_SEH2_END; _SEH2_END;
} }
UserLeave(); UserLeave();
return Ret; return uRet;
} }
BOOL BOOL
@ -558,8 +465,8 @@ APIENTRY
NtUserGetKeyboardLayoutName( NtUserGetKeyboardLayoutName(
LPWSTR lpszName) LPWSTR lpszName)
{ {
BOOL ret = FALSE; BOOL bRet = FALSE;
PKBL pKbl; PKL pKbl;
PTHREADINFO pti; PTHREADINFO pti;
UserEnterShared(); UserEnterShared();
@ -570,20 +477,18 @@ NtUserGetKeyboardLayoutName(
pti = PsGetCurrentThreadWin32Thread(); pti = PsGetCurrentThreadWin32Thread();
pKbl = pti->KeyboardLayout; pKbl = pti->KeyboardLayout;
RtlCopyMemory(lpszName, pKbl->Name, KL_NAMELENGTH*sizeof(WCHAR)); RtlCopyMemory(lpszName, pKbl->Name, KL_NAMELENGTH*sizeof(WCHAR));
ret = TRUE; bRet = TRUE;
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{ {
SetLastNtError(_SEH2_GetExceptionCode()); SetLastNtError(_SEH2_GetExceptionCode());
ret = FALSE;
} }
_SEH2_END; _SEH2_END;
UserLeave(); UserLeave();
return ret; return bRet;
} }
HKL HKL
APIENTRY APIENTRY
NtUserLoadKeyboardLayoutEx( NtUserLoadKeyboardLayoutEx(
@ -595,24 +500,32 @@ NtUserLoadKeyboardLayoutEx(
IN DWORD dwKLID, IN DWORD dwKLID,
IN UINT Flags) IN UINT Flags)
{ {
HKL Ret = NULL; HKL hklRet = NULL;
PKBL pKbl = NULL, Cur; PKL pKbl = NULL, pklCur;
if (Flags & ~(KLF_ACTIVATE|KLF_NOTELLSHELL|KLF_REORDER|KLF_REPLACELANG|
KLF_SUBSTITUTE_OK|KLF_SETFORPROCESS|KLF_UNLOADPREVIOUS))
{
ERR("Invalid flags: %x\n", Flags);
EngSetLastError(ERROR_INVALID_FLAGS);
return 0;
}
UserEnterExclusive(); UserEnterExclusive();
//Let's see if layout was already loaded. //Let's see if layout was already loaded.
Cur = KBLList; pklCur = gpklFirst;
do do
{ {
if (Cur->klid == dwKLID) if (pklCur->klid == dwKLID)
{ {
pKbl = Cur; pKbl = pklCur;
pKbl->Flags &= ~KBL_UNLOAD; pKbl->Flags &= ~KBL_UNLOAD;
break; break;
} }
Cur = (PKBL) Cur->List.Flink; pklCur = CONTAINING_RECORD(pKbl->List.Flink, KL, List);
} while (Cur != KBLList); } while (pklCur != gpklFirst);
//It wasn't, so load it. //It wasn't, so load it.
if (!pKbl) if (!pKbl)
@ -621,28 +534,28 @@ NtUserLoadKeyboardLayoutEx(
if (!pKbl) if (!pKbl)
{ {
goto the_end; goto cleanup;
} }
InsertTailList(&KBLList->List, &pKbl->List); InsertTailList(&gpklFirst->List, &pKbl->List);
} }
if (Flags & KLF_REORDER) KBLList = pKbl; if (Flags & KLF_REORDER) gpklFirst = pKbl;
if (Flags & KLF_ACTIVATE) if (Flags & KLF_ACTIVATE)
{ {
co_UserActivateKbl(PsGetCurrentThreadWin32Thread(), pKbl, Flags); co_UserActivateKbl(PsGetCurrentThreadWin32Thread(), pKbl, Flags);
} }
Ret = pKbl->hkl; hklRet = pKbl->hkl;
//FIXME: KLF_NOTELLSHELL //FIXME: KLF_NOTELLSHELL
// KLF_REPLACELANG // KLF_REPLACELANG
// KLF_SUBSTITUTE_OK // KLF_SUBSTITUTE_OK
the_end: cleanup:
UserLeave(); UserLeave();
return Ret; return hklRet;
} }
HKL HKL
@ -651,27 +564,27 @@ NtUserActivateKeyboardLayout(
HKL hKl, HKL hKl,
ULONG Flags) ULONG Flags)
{ {
PKBL pKbl; PKL pKbl;
HKL Ret = NULL; HKL hklRet = NULL;
PTHREADINFO pWThread; PTHREADINFO pti;
UserEnterExclusive(); UserEnterExclusive();
pWThread = PsGetCurrentThreadWin32Thread(); pti = PsGetCurrentThreadWin32Thread();
if (pWThread->KeyboardLayout->hkl == hKl) if (pti->KeyboardLayout->hkl == hKl)
{ {
Ret = hKl; hklRet = hKl;
goto the_end; goto cleanup;
} }
if (hKl == (HKL)HKL_NEXT) if (hKl == (HKL)HKL_NEXT)
{ {
pKbl = (PKBL)pWThread->KeyboardLayout->List.Flink; pKbl = CONTAINING_RECORD(pti->KeyboardLayout->List.Flink, KL, List);
} }
else if (hKl == (HKL)HKL_PREV) else if (hKl == (HKL)HKL_PREV)
{ {
pKbl = (PKBL)pWThread->KeyboardLayout->List.Blink; pKbl = CONTAINING_RECORD(pti->KeyboardLayout->List.Blink, KL, List);
} }
else pKbl = UserHklToKbl(hKl); else pKbl = UserHklToKbl(hKl);
@ -680,16 +593,16 @@ NtUserActivateKeyboardLayout(
if (pKbl) if (pKbl)
{ {
if (Flags & KLF_REORDER) if (Flags & KLF_REORDER)
KBLList = pKbl; gpklFirst = pKbl;
if (pKbl == pWThread->KeyboardLayout) if (pKbl == pti->KeyboardLayout)
{ {
Ret = pKbl->hkl; hklRet = pKbl->hkl;
} }
else else
{ {
pKbl = co_UserActivateKbl(pWThread, pKbl, Flags); pKbl = co_UserActivateKbl(pti, pKbl, Flags);
Ret = pKbl->hkl; hklRet = pKbl->hkl;
} }
} }
else else
@ -697,9 +610,9 @@ NtUserActivateKeyboardLayout(
ERR("Invalid HKL %x!\n", hKl); ERR("Invalid HKL %x!\n", hKl);
} }
the_end: cleanup:
UserLeave(); UserLeave();
return Ret; return hklRet;
} }
BOOL BOOL
@ -707,14 +620,15 @@ APIENTRY
NtUserUnloadKeyboardLayout( NtUserUnloadKeyboardLayout(
HKL hKl) HKL hKl)
{ {
PKBL pKbl; PKL pKbl;
BOOL Ret = FALSE; BOOL bRet = FALSE;
UserEnterExclusive(); UserEnterExclusive();
if ((pKbl = UserHklToKbl(hKl))) pKbl = UserHklToKbl(hKl);
if (pKbl)
{ {
Ret = UserUnloadKbl(pKbl); bRet = UserUnloadKbl(pKbl);
} }
else else
{ {
@ -722,7 +636,7 @@ NtUserUnloadKeyboardLayout(
} }
UserLeave(); UserLeave();
return Ret; return bRet;
} }
/* EOF */ /* EOF */

View file

@ -891,7 +891,7 @@ BOOL NTAPI
UserSendKeyboardInput(KEYBDINPUT *pKbdInput, BOOL bInjected) UserSendKeyboardInput(KEYBDINPUT *pKbdInput, BOOL bInjected)
{ {
WORD wScanCode, wVk; WORD wScanCode, wVk;
PKBL pKbl = NULL; PKL pKbl = NULL;
PKBDTABLES pKbdTbl; PKBDTABLES pKbdTbl;
PUSER_MESSAGE_QUEUE pFocusQueue; PUSER_MESSAGE_QUEUE pFocusQueue;
struct _ETHREAD *pFocusThread; struct _ETHREAD *pFocusThread;
@ -973,7 +973,7 @@ UserProcessKeyboardInput(
PKEYBOARD_INPUT_DATA pKbdInputData) PKEYBOARD_INPUT_DATA pKbdInputData)
{ {
WORD wScanCode, wVk; WORD wScanCode, wVk;
PKBL pKbl = NULL; PKL pKbl = NULL;
PKBDTABLES pKbdTbl; PKBDTABLES pKbdTbl;
PUSER_MESSAGE_QUEUE pFocusQueue; PUSER_MESSAGE_QUEUE pFocusQueue;
struct _ETHREAD *pFocusThread; struct _ETHREAD *pFocusThread;
@ -1211,7 +1211,7 @@ NtUserMapVirtualKeyEx(UINT uCode, UINT uType, DWORD keyboardId, HKL dwhkl)
} }
else else
{ {
PKBL pKbl; PKL pKbl;
pKbl = UserHklToKbl(dwhkl); pKbl = UserHklToKbl(dwhkl);
if (pKbl) if (pKbl)
@ -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;
PKBL pKbl = NULL; PKL pKbl = NULL;
TRACE("Enter NtUserSetKeyboardState\n"); TRACE("Enter NtUserSetKeyboardState\n");
@ -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;
PKBL pKbl = NULL; PKL pKbl = 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);