[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
DisplayStatusMessage(
IN PWLSESSION Session,
@ -390,6 +449,14 @@ WinMain(
}
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())
{
ERR("WL: Could not start services.exe\n");

View file

@ -29,6 +29,7 @@
#define USE_GETLASTINPUTINFO
#define WIN32_NO_STATUS
#include <stdio.h>
#include <windows.h>
#include <userenv.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 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 Id",0x00000000,"0001"
HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layouts\0000041c","Layout File",0x00000000,"kbdal.dll"
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 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 Id",0x00000000,"0001"
; Keyboard layouts
HKLM,"SYSTEM\CurrentControlSet\Control\Keyboard Layout",,0x00000012

View file

@ -1,31 +1,54 @@
#pragma once
#include <ndk/kbd.h>
typedef struct _KL
typedef struct tagKBDNLSLAYER
{
LIST_ENTRY List;
DWORD Flags;
WCHAR Name[KL_NAMELENGTH]; // used w GetKeyboardLayoutName same as wszKLID.
struct _KBDTABLES *KBTables; // KBDTABLES in ndk/kbd.h
HANDLE hModule;
ULONG RefCount;
HKL hkl;
DWORD klid; // Low word - language id. High word - device id.
USHORT OEMIdentifier;
USHORT LayoutInformation;
UINT NumOfVkToF;
struct _VK_TO_FUNCTION_TABLE *pVkToF;
INT NumOfMouseVKey;
PUSHORT pusMouseVKey;
} KBDNLSLAYER, *PKBDNLSLAYER;
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;
typedef struct _ATTACHINFO
{
struct _ATTACHINFO* paiNext;
struct _ATTACHINFO *paiNext;
PTHREADINFO pti1;
PTHREADINFO pti2;
} ATTACHINFO, *PATTACHINFO;
extern PATTACHINFO gpai;
#define KBL_UNLOAD 1
#define KBL_PRELOAD 2
#define KBL_RESET 4
/* Keyboard layout undocumented flags */
#define KLF_UNLOAD 0x20000000
/* Key States */
#define KS_DOWN_BIT 0x80

View file

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

View file

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

View file

@ -11,66 +11,46 @@
#include <win32k.h>
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 ******************************************************/
/*
* UserLoadKbdDll
*
* Loads keyboard layout DLL and gets address to KbdTables
*/
static BOOL
UserLoadKbdDll(CONST WCHAR *wszKLID,
UserLoadKbdDll(WCHAR *pwszLayoutPath,
HANDLE *phModule,
PKBDTABLES *pKbdTables)
{
NTSTATUS Status;
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;
}
PFN_KBDLAYERDESCRIPTOR pfnKbdLayerDescriptor;
/* Load keyboard layout DLL */
TRACE("Loading Keyboard DLL %ws\n", wszLayoutPath);
*phModule = EngLoadImage(wszLayoutPath);
TRACE("Loading Keyboard DLL %ws\n", pwszLayoutPath);
*phModule = EngLoadImage(pwszLayoutPath);
if (!(*phModule))
{
ERR("Failed to load dll %ws\n", wszLayoutPath);
ERR("Failed to load dll %ws\n", pwszLayoutPath);
return FALSE;
}
/* Find KbdLayerDescriptor function and get layout tables */
TRACE("Loaded %ws\n", wszLayoutPath);
TRACE("Loaded %ws\n", pwszLayoutPath);
pfnKbdLayerDescriptor = EngFindImageProcAddress(*phModule, "KbdLayerDescriptor");
/* FIXME: Windows reads file instead of executing!
It's not safe to kbdlayout DLL in kernel mode! */
if (pfnKbdLayerDescriptor)
*pKbdTables = pfnKbdLayerDescriptor();
else
ERR("Error: %ws has no KbdLayerDescriptor()\n", wszLayoutPath);
ERR("Error: %ws has no KbdLayerDescriptor()\n", pwszLayoutPath);
if (!pfnKbdLayerDescriptor || !*pKbdTables)
{
@ -79,7 +59,7 @@ UserLoadKbdDll(CONST WCHAR *wszKLID,
return FALSE;
}
#if 0 // Dump keyboard layout
#if 0 /* Dump keyboard layout */
{
unsigned i;
PVK_TO_BIT pVkToBit = (*pKbdTables)->pCharModifiers->pVkToBit;
@ -134,300 +114,333 @@ UserLoadKbdDll(CONST WCHAR *wszKLID,
return TRUE;
}
static PKL
UserLoadDllAndCreateKbl(DWORD LocaleId)
/*
* UserLoadKbdFile
*
* Loads keyboard layout DLL and creates KBDFILE object
*/
static PKBDFILE
UserLoadKbdFile(PUNICODE_STRING pwszKLID)
{
PKL pNewKbl;
ULONG hKl;
LANGID langid;
PKBDFILE pkf, pRet = NULL;
NTSTATUS Status;
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);
if (!pNewKbl)
/* Create keyboard layout file object */
pkf = UserCreateObject(gHandleTable, NULL, NULL, otKBDfile, sizeof(KBDFILE));
if (!pkf)
{
ERR("Can't allocate memory!\n");
ERR("Failed to create object!\n");
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);
ExFreePoolWithTag(pNewKbl, USERTAG_KBDLAYOUT);
return NULL;
ERR("Failed to open keyboard layouts registry key %ws (%lx)\n", wszLayoutRegKey, Status);
goto cleanup;
}
/* Microsoft Office expects this value to be something specific
* for Japanese and Korean Windows with an IME the value is 0xe001
* We should probably check to see if an IME exists and if so then
* set this word properly.
*/
langid = PRIMARYLANGID(LANGIDFROMLCID(LocaleId));
hKl = LocaleId;
/* Read filename of layout DLL */
cbSize = sizeof(wszLayoutPath) - wcslen(wszLayoutPath)*sizeof(WCHAR);
Status = RegQueryValue(hKey,
L"Layout File",
REG_SZ,
wszLayoutPath + wcslen(wszLayoutPath),
&cbSize);
if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
hKl |= 0xe001 << 16; /* FIXME */
else hKl |= hKl << 16;
if (!NT_SUCCESS(Status))
{
ERR("Can't get layout filename for %wZ (%lx)\n", pwszKLID, Status);
goto cleanup;
}
pNewKbl->hkl = (HKL)(ULONG_PTR) hKl;
pNewKbl->klid = LocaleId;
pNewKbl->Flags = 0;
pNewKbl->RefCount = 0;
/* Load keyboard file now */
if (!UserLoadKbdDll(wszLayoutPath, &pkf->hBase, &pkf->pKbdTbl))
{
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;
NTSTATUS Status;
PKL pKl;
/* Load keyboard layout for default locale */
Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
if (NT_SUCCESS(Status))
/* Create keyboard layout object */
pKl = UserCreateObject(gHandleTable, NULL, NULL, otKBDlayout, sizeof(KL));
if (!pKl)
{
TRACE("DefaultLocale = %08lx\n", LocaleId);
gpklFirst = UserLoadDllAndCreateKbl(LocaleId);
ERR("Failed to create object!\n");
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("Trying to load US Keyboard Layout.\n");
LocaleId = 0x409;
ERR("UserLoadKbdFile(%wZ) failed!\n", pwszKLID);
UserDeleteObject(pKl->head.h, otKBDlayout);
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;
}
/* Set next layout as default */
gspklBaseLayout = pKl->pklNext;
}
/* Add layout to the list */
gpklFirst->Flags |= KBL_PRELOAD;
InitializeListHead(&gpklFirst->List);
if (pKl->head.cLockObj > 1)
{
/* 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;
}
/*
* W32kGetDefaultKeyLayout
*
* Returns default layout for new threads
*/
PKL
W32kGetDefaultKeyLayout(VOID)
{
CONST WCHAR wszDefaultUserPath[] = L"\\REGISTRY\\USER\\.DEFAULT";
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];
PKL pKl = gspklBaseLayout;
/* Try to get default alayout from HKCU\Keyboard Layout\Preload first */
Status = RtlFormatCurrentUserKeyPath(&CurrentUserPath);
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);
if (!pKl)
return NULL;
/* Free CurrentUserPath - we dont need it anymore */
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;
/* Return not unloaded layout */
do
{
if (pKbl->klid == LayoutLocaleId)
return pKbl;
if (!(pKl->dwKL_Flags & KLF_UNLOAD))
return pKl;
pKbl = CONTAINING_RECORD(pKbl->List.Flink, KL, List);
} while (pKbl != gpklFirst);
pKl = pKl->pklPrev; /* Confirmed on Win2k */
} while(pKl != gspklBaseLayout);
/* Load the keyboard layout */
TRACE("Loading new default keyboard layout.\n");
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;
/* We have not found proper KL */
return NULL;
}
/*
* UserHklToKbl
*
* Gets KL object from hkl value
*/
PKL
UserHklToKbl(HKL hKl)
{
PKL pKbl = gpklFirst;
PKL pKl = gspklBaseLayout;
if (!gspklBaseLayout)
return NULL;
do
{
if (pKbl->hkl == hKl)
return pKbl;
if (pKl->hkl == hKl)
return pKl;
pKbl = CONTAINING_RECORD(pKbl->List.Flink, KL, List);
} while (pKbl != gpklFirst);
pKl = pKl->pklNext;
} while (pKl != gspklBaseLayout);
return NULL;
}
BOOL
UserUnloadKbl(PKL pKbl)
{
/* According to msdn, UnloadKeyboardLayout can fail
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;
}
/*
* co_UserActivateKbl
*
* Activates given layout in specified thread
*/
static PKL
co_UserActivateKbl(PTHREADINFO pti, PKL pKbl, UINT Flags)
co_UserActivateKbl(PTHREADINFO pti, PKL pKl, UINT Flags)
{
PKL pklPrev;
pklPrev = pti->KeyboardLayout;
pklPrev->RefCount--;
pti->KeyboardLayout = pKbl;
pKbl->RefCount++;
if (pklPrev)
UserDereferenceObject(pklPrev);
pti->KeyboardLayout = pKl;
UserReferenceObject(pKl);
if (Flags & KLF_SETFORPROCESS)
{
//FIXME
}
if (pklPrev->Flags & KBL_UNLOAD && pklPrev->RefCount == 0)
{
UserUnloadKbl(pklPrev);
}
// Send WM_INPUTLANGCHANGE to thread's focus window
co_IntSendMessage(pti->MessageQueue->FocusWindow,
WM_INPUTLANGCHANGE,
0, // FIXME: put charset here (what is this?)
(LPARAM)pKbl->hkl); //klid
(WPARAM)pKl->iBaseCharset, // FIXME: how to set it?
(LPARAM)pKl->hkl); //hkl
return pklPrev;
}
/* EXPORTS *******************************************************************/
/*
* UserGetKeyboardLayout
*
* Returns hkl of given thread keyboard layout
*/
HKL FASTCALL
UserGetKeyboardLayout(
DWORD dwThreadId)
{
NTSTATUS Status;
PETHREAD Thread;
PETHREAD pThread;
PTHREADINFO pti;
HKL Ret;
PKL pKl;
HKL hKl;
if (!dwThreadId)
{
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))
{
EngSetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
pti = PsGetThreadWin32Thread(Thread);
Ret = pti->KeyboardLayout->hkl;
ObDereferenceObject(Thread);
return Ret;
pti = PsGetThreadWin32Thread(pThread);
pKl = pti->KeyboardLayout;
hKl = pKl ? pKl->hkl : NULL;;
ObDereferenceObject(pThread);
return hKl;
}
/*
* NtUserGetKeyboardLayoutList
*
* Returns list of loaded keyboard layouts in system
*/
UINT
APIENTRY
NtUserGetKeyboardLayoutList(
INT nBuff,
HKL* pHklBuff)
HKL *pHklBuff)
{
UINT uRet = 0;
PKL pKbl;
UserEnterShared();
pKbl = gpklFirst;
PKL pKl;
if (!pHklBuff)
nBuff = 0;
UserEnterShared();
if (!gspklBaseLayout)
return 0;
pKl = gspklBaseLayout;
if (nBuff == 0)
{
do
{
uRet++;
pKbl = CONTAINING_RECORD(pKbl->List.Flink, KL, List);
} while (pKbl != gpklFirst);
pKl = pKl->pklNext;
} while (pKl != gspklBaseLayout);
}
else
{
@ -437,16 +450,12 @@ NtUserGetKeyboardLayoutList(
while (uRet < nBuff)
{
if (!(pKbl->Flags & KBL_UNLOAD))
{
pHklBuff[uRet] = pKbl->hkl;
uRet++;
pKbl = CONTAINING_RECORD(pKbl->List.Flink, KL, List);
if (pKbl == gpklFirst)
break;
}
pHklBuff[uRet] = pKl->hkl;
uRet++;
pKl = pKl->pklNext;
if (pKl == gspklBaseLayout)
break;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
@ -460,23 +469,32 @@ NtUserGetKeyboardLayoutList(
return uRet;
}
/*
* NtUserGetKeyboardLayoutName
*
* Returns KLID of current thread keyboard layout
*/
BOOL
APIENTRY
NtUserGetKeyboardLayoutName(
LPWSTR lpszName)
LPWSTR pwszName)
{
BOOL bRet = FALSE;
PKL pKbl;
PKL pKl;
PTHREADINFO pti;
UserEnterShared();
pti = PsGetCurrentThreadWin32Thread();
pKl = pti->KeyboardLayout;
if (!pKl)
goto cleanup;
_SEH2_TRY
{
ProbeForWrite(lpszName, KL_NAMELENGTH*sizeof(WCHAR), 1);
pti = PsGetCurrentThreadWin32Thread();
pKbl = pti->KeyboardLayout;
RtlCopyMemory(lpszName, pKbl->Name, KL_NAMELENGTH*sizeof(WCHAR));
ProbeForWrite(pwszName, KL_NAMELENGTH*sizeof(WCHAR), 1);
wcscpy(pwszName, pKl->spkf->awchKF);
bRet = TRUE;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
@ -485,155 +503,207 @@ NtUserGetKeyboardLayoutName(
}
_SEH2_END;
cleanup:
UserLeave();
return bRet;
}
/*
* NtUserLoadKeyboardLayoutEx
*
* Loads keyboard layout with given locale id
*/
HKL
APIENTRY
NtUserLoadKeyboardLayoutEx(
IN HANDLE Handle,
IN DWORD offTable,
IN PUNICODE_STRING puszKeyboardName,
IN HKL hKL,
IN PUNICODE_STRING puszKLID,
IN DWORD dwKLID,
IN HANDLE Handle, // hFile (See downloads.securityfocus.com/vulnerabilities/exploits/43774.c)
IN DWORD offTable, // offset to KbdTables
IN PUNICODE_STRING puszKeyboardName, // not used?
IN HKL hklUnload,
IN PUNICODE_STRING pustrKLID,
IN DWORD hkl,
IN UINT Flags)
{
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|
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);
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();
//Let's see if layout was already loaded.
pklCur = gpklFirst;
do
/* If hklUnload is specified, unload it and load new layput as default */
if (hklUnload && hklUnload != (HKL)hkl)
{
if (pklCur->klid == dwKLID)
{
pKbl = pklCur;
pKbl->Flags &= ~KBL_UNLOAD;
break;
}
pKl = UserHklToKbl(hklUnload);
if (pKl)
UserUnloadKbl(pKl);
}
pklCur = CONTAINING_RECORD(pKbl->List.Flink, KL, List);
} while (pklCur != gpklFirst);
//It wasn't, so load it.
if (!pKbl)
/* Let's see if layout was already loaded. */
pKl = UserHklToKbl((HKL)hkl);
if (!pKl)
{
pKbl = UserLoadDllAndCreateKbl(dwKLID);
if (!pKbl)
{
/* It wasn't, so load it. */
pKl = UserLoadKbdLayout(&ustrSafeKLID, (HKL)hkl);
if (!pKl)
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)
{
co_UserActivateKbl(PsGetCurrentThreadWin32Thread(), pKbl, Flags);
}
co_UserActivateKbl(PsGetCurrentThreadWin32Thread(), pKl, Flags);
hklRet = pKbl->hkl;
/* Send shell message */
if (!(Flags & KLF_NOTELLSHELL))
co_IntShellHookNotify(HSHELL_LANGUAGE, (LPARAM)hkl);
//FIXME: KLF_NOTELLSHELL
// KLF_REPLACELANG
// KLF_SUBSTITUTE_OK
/* Return hkl on success */
hklRet = (HKL)hkl;
/* FIXME: KLF_REPLACELANG
KLF_REORDER */
cleanup:
UserLeave();
return hklRet;
}
/*
* NtUserActivateKeyboardLayout
*
* Activates specified layout for thread or process
*/
HKL
APIENTRY
NtUserActivateKeyboardLayout(
HKL hKl,
ULONG Flags)
{
PKL pKbl;
HKL hklRet = NULL;
PKL pKl = NULL;
HKL hkl = NULL;
PTHREADINFO pti;
UserEnterExclusive();
pti = PsGetCurrentThreadWin32Thread();
if (pti->KeyboardLayout->hkl == hKl)
{
hklRet = hKl;
goto cleanup;
}
/* hKl can have special value HKL_NEXT or HKL_PREV */
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)
{
pKbl = CONTAINING_RECORD(pti->KeyboardLayout->List.Blink, KL, List);
}
else pKbl = UserHklToKbl(hKl);
//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;
}
/* Get previous keyboard layout starting with current */
if (pti->KeyboardLayout)
pKl = pti->KeyboardLayout->pklNext;
}
else
pKl = UserHklToKbl(hKl);
if (!pKl)
{
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:
UserLeave();
return hklRet;
return hkl;
}
/*
* NtUserUnloadKeyboardLayout
*
* Unloads keyboard layout with specified hkl value
*/
BOOL
APIENTRY
NtUserUnloadKeyboardLayout(
HKL hKl)
{
PKL pKbl;
PKL pKl;
BOOL bRet = FALSE;
UserEnterExclusive();
pKbl = UserHklToKbl(hKl);
if (pKbl)
{
bRet = UserUnloadKbl(pKbl);
}
pKl = UserHklToKbl(hKl);
if (pKl)
bRet = UserUnloadKbl(pKl);
else
{
ERR("Invalid HKL %x!\n", hKl);
}
UserLeave();
return bRet;

View file

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