mirror of
https://github.com/reactos/reactos.git
synced 2025-08-07 19:53:14 +00:00
[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:
parent
f00c31f3ff
commit
db62557f8c
8 changed files with 526 additions and 365 deletions
|
@ -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");
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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++)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue