Author: rharabien Date: Wed Oct 19 20:03:50 2011 New Revision: 54203
URL: http://svn.reactos.org/svn/reactos?rev=54203&view=rev Log: [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
Modified: trunk/reactos/base/system/winlogon/winlogon.c trunk/reactos/base/system/winlogon/winlogon.h trunk/reactos/boot/bootdata/hivesys_i386.inf trunk/reactos/subsystems/win32/win32k/include/input.h trunk/reactos/subsystems/win32/win32k/main/dllmain.c trunk/reactos/subsystems/win32/win32k/ntuser/input.c trunk/reactos/subsystems/win32/win32k/ntuser/kbdlayout.c trunk/reactos/subsystems/win32/win32k/ntuser/keyboard.c
Modified: trunk/reactos/base/system/winlogon/winlogon.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/winlogon/winlog... ============================================================================== --- trunk/reactos/base/system/winlogon/winlogon.c [iso-8859-1] (original) +++ trunk/reactos/base/system/winlogon/winlogon.c [iso-8859-1] Wed Oct 19 20:03:50 2011 @@ -267,6 +267,65 @@ }
+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 @@ } 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");
Modified: trunk/reactos/base/system/winlogon/winlogon.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/winlogon/winlog... ============================================================================== --- trunk/reactos/base/system/winlogon/winlogon.h [iso-8859-1] (original) +++ trunk/reactos/base/system/winlogon/winlogon.h [iso-8859-1] Wed Oct 19 20:03:50 2011 @@ -29,6 +29,7 @@ #define USE_GETLASTINPUTINFO
#define WIN32_NO_STATUS +#include <stdio.h> #include <windows.h> #include <userenv.h> #include <winwlx.h>
Modified: trunk/reactos/boot/bootdata/hivesys_i386.inf URL: http://svn.reactos.org/svn/reactos/trunk/reactos/boot/bootdata/hivesys_i386.... ============================================================================== --- trunk/reactos/boot/bootdata/hivesys_i386.inf [iso-8859-1] (original) +++ trunk/reactos/boot/bootdata/hivesys_i386.inf [iso-8859-1] Wed Oct 19 20:03:50 2011 @@ -423,6 +423,7 @@ 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\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
Modified: trunk/reactos/subsystems/win32/win32k/include/input.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/inc... ============================================================================== --- trunk/reactos/subsystems/win32/win32k/include/input.h [iso-8859-1] (original) +++ trunk/reactos/subsystems/win32/win32k/include/input.h [iso-8859-1] Wed Oct 19 20:03:50 2011 @@ -1,31 +1,54 @@ #pragma once
#include <ndk/kbd.h> + +typedef struct tagKBDNLSLAYER +{ + 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 _KL +typedef struct tagKL { - 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. + 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
Modified: trunk/reactos/subsystems/win32/win32k/main/dllmain.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/mai... ============================================================================== --- trunk/reactos/subsystems/win32/win32k/main/dllmain.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/win32/win32k/main/dllmain.c [iso-8859-1] Wed Oct 19 20:03:50 2011 @@ -286,6 +286,8 @@ } 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 @@ IntBlockInput(ptiCurrent, FALSE); MsqDestroyMessageQueue(ptiCurrent->MessageQueue); IntCleanupThreadCallbacks(ptiCurrent); + if (ptiCurrent->KeyboardLayout) + UserDereferenceObject(ptiCurrent->KeyboardLayout);
/* cleanup user object references stack */ psle = PopEntryList(&ptiCurrent->ReferencesList);
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/input.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/ntu... ============================================================================== --- trunk/reactos/subsystems/win32/win32k/ntuser/input.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/win32/win32k/ntuser/input.c [iso-8859-1] Wed Oct 19 20:03:50 2011 @@ -328,12 +328,6 @@ return STATUS_UNSUCCESSFUL; } KeInitializeTimer(MasterTimer); - - /* Initialize the default keyboard layout */ - if (!UserInitDefaultKeyboardLayout()) - { - ERR("Failed to initialize default keyboard layout!\n"); - }
return STATUS_SUCCESS; }
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/kbdlayout.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/ntu... ============================================================================== --- trunk/reactos/subsystems/win32/win32k/ntuser/kbdlayout.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/win32/win32k/ntuser/kbdlayout.c [iso-8859-1] Wed Oct 19 20:03:50 2011 @@ -11,66 +11,46 @@ #include <win32k.h> DBG_DEFAULT_CHANNEL(UserKbdLayout);
-PKL gpklFirst = NULL; // Keyboard layout list. - -typedef PVOID (*PFNKBDLAYERDESCRIPTOR)(VOID); +PKL gspklBaseLayout = NULL; +PKBDFILE gpkfList = NULL; + +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); + PFN_KBDLAYERDESCRIPTOR pfnKbdLayerDescriptor; + + /* Load keyboard layout DLL */ + TRACE("Loading Keyboard DLL %ws\n", pwszLayoutPath); + *phModule = EngLoadImage(pwszLayoutPath); + if (!(*phModule)) + { + ERR("Failed to load dll %ws\n", pwszLayoutPath); 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 */ - 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); + 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 @@ 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 @@ return TRUE; }
+/* + * UserLoadKbdFile + * + * Loads keyboard layout DLL and creates KBDFILE object + */ +static PKBDFILE +UserLoadKbdFile(PUNICODE_STRING pwszKLID) +{ + 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\"; + + /* Create keyboard layout file object */ + pkf = UserCreateObject(gHandleTable, NULL, NULL, otKBDfile, sizeof(KBDFILE)); + if (!pkf) + { + ERR("Failed to create object!\n"); + return NULL; + } + + /* Set keyboard layout name */ + swprintf(pkf->awchKF, L"%wZ", pwszKLID); + + /* Open layout registry key */ + RtlStringCbCatW(wszLayoutRegKey, sizeof(wszLayoutRegKey), pkf->awchKF); + Status = RegOpenKey(wszLayoutRegKey, &hKey); + if (!NT_SUCCESS(Status)) + { + ERR("Failed to open keyboard layouts registry key %ws (%lx)\n", wszLayoutRegKey, Status); + goto cleanup; + } + + /* 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 (!NT_SUCCESS(Status)) + { + ERR("Can't get layout filename for %wZ (%lx)\n", pwszKLID, Status); + goto cleanup; + } + + /* Load keyboard file now */ + if (!UserLoadKbdDll(wszLayoutPath, &pkf->hBase, &pkf->pKbdTbl)) + { + ERR("Failed to load %ws dll!\n", wszLayoutPath); + goto cleanup; + } + + /* 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; +} + +/* + * UserLoadKbdLayout + * + * Loads keyboard layout and creates KL object + */ static PKL -UserLoadDllAndCreateKbl(DWORD LocaleId) -{ - PKL pNewKbl; - ULONG hKl; - LANGID langid; - - pNewKbl = ExAllocatePoolWithTag(PagedPool, sizeof(KL), USERTAG_KBDLAYOUT); - - if (!pNewKbl) - { - ERR("Can't allocate memory!\n"); +UserLoadKbdLayout(PUNICODE_STRING pwszKLID, HKL hKL) +{ + PKL pKl; + + /* Create keyboard layout object */ + pKl = UserCreateObject(gHandleTable, NULL, NULL, otKBDlayout, sizeof(KL)); + if (!pKl) + { + ERR("Failed to create object!\n"); return NULL; }
- swprintf(pNewKbl->Name, L"%08lx", LocaleId); - - if (!UserLoadKbdDll(pNewKbl->Name, &pNewKbl->hModule, &pNewKbl->KBTables)) - { - ERR("Failed to load %x dll!\n", LocaleId); - ExFreePoolWithTag(pNewKbl, USERTAG_KBDLAYOUT); + pKl->hkl = hKL; + pKl->spkf = UserLoadKbdFile(pwszKLID); + + /* Dereference keyboard layout */ + UserDereferenceObject(pKl); + + /* If we failed, remove KL object */ + if (!pKl->spkf) + { + ERR("UserLoadKbdFile(%wZ) failed!\n", pwszKLID); + UserDeleteObject(pKl->head.h, otKBDlayout); return NULL; }
- /* 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; - - if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN) - hKl |= 0xe001 << 16; /* FIXME */ - else hKl |= hKl << 16; - - pNewKbl->hkl = (HKL)(ULONG_PTR) hKl; - pNewKbl->klid = LocaleId; - pNewKbl->Flags = 0; - pNewKbl->RefCount = 0; - - return pNewKbl; -} - + 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 -UserInitDefaultKeyboardLayout() -{ - LCID LocaleId; - NTSTATUS Status; - - /* Load keyboard layout for default locale */ - Status = ZwQueryDefaultLocale(FALSE, &LocaleId); - if (NT_SUCCESS(Status)) - { - TRACE("DefaultLocale = %08lx\n", LocaleId); - gpklFirst = UserLoadDllAndCreateKbl(LocaleId); - } - else - ERR("Could not get default locale (%08lx).\n", Status); - - if (!NT_SUCCESS(Status) || !gpklFirst) - { - /* If failed load US keyboard layout */ - ERR("Trying to load US Keyboard Layout.\n"); - LocaleId = 0x409; - - if (!(gpklFirst = UserLoadDllAndCreateKbl(LocaleId))) - { - ERR("Failed to load any Keyboard Layout\n"); +UserUnloadKbl(PKL pKl) +{ + /* According to msdn, UnloadKeyboardLayout can fail + if the keyboard layout identifier was preloaded. */ + if (pKl == gspklBaseLayout) + { + if (pKl->pklNext == pKl->pklPrev) + { + /* There is only one layout */ return FALSE; } - } - - /* Add layout to the list */ - gpklFirst->Flags |= KBL_PRELOAD; - InitializeListHead(&gpklFirst->List); - + + /* Set next layout as default */ + gspklBaseLayout = pKl->pklNext; + } + + 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]; - - /* 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); - - /* 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; + PKL pKl = gspklBaseLayout; + + if (!pKl) + return NULL; + + /* Return not unloaded layout */ do { - if (pKbl->klid == LayoutLocaleId) - return pKbl; - - pKbl = CONTAINING_RECORD(pKbl->List.Flink, KL, List); - } while (pKbl != gpklFirst); - - /* 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; -} - + if (!(pKl->dwKL_Flags & KLF_UNLOAD)) + return pKl; + + pKl = pKl->pklPrev; /* Confirmed on Win2k */ + } while(pKl != gspklBaseLayout); + + /* 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; - - pKbl = CONTAINING_RECORD(pKbl->List.Flink, KL, List); - } while (pKbl != gpklFirst); + if (pKl->hkl == hKl) + return pKl; + + 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; - } - - Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)dwThreadId, &Thread); + pKl = pti->KeyboardLayout; + return pKl ? pKl->hkl : NULL; + } + + 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 @@
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 @@ 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 @@ } _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 (pklCur->klid == dwKLID) - { - pKbl = pklCur; - pKbl->Flags &= ~KBL_UNLOAD; - break; - } - - pklCur = CONTAINING_RECORD(pKbl->List.Flink, KL, List); - } while (pklCur != gpklFirst); - - //It wasn't, so load it. - if (!pKbl) - { - pKbl = UserLoadDllAndCreateKbl(dwKLID); - - if (!pKbl) - { + /* If hklUnload is specified, unload it and load new layput as default */ + if (hklUnload && hklUnload != (HKL)hkl) + { + pKl = UserHklToKbl(hklUnload); + if (pKl) + UserUnloadKbl(pKl); + } + + /* Let's see if layout was already loaded. */ + pKl = UserHklToKbl((HKL)hkl); + if (!pKl) + { + /* It wasn't, so load it. */ + pKl = UserLoadKbdLayout(&ustrSafeKLID, (HKL)hkl); + if (!pKl) goto cleanup; - } - - InsertTailList(&gpklFirst->List, &pKbl->List); - } - - if (Flags & KLF_REORDER) gpklFirst = pKbl; - + + 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; + } + } + + /* 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); - } - - hklRet = pKbl->hkl; - - //FIXME: KLF_NOTELLSHELL - // KLF_REPLACELANG - // KLF_SUBSTITUTE_OK + co_UserActivateKbl(PsGetCurrentThreadWin32Thread(), pKl, Flags); + + /* Send shell message */ + if (!(Flags & KLF_NOTELLSHELL)) + co_IntShellHookNotify(HSHELL_LANGUAGE, (LPARAM)hkl); + + /* 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; + /* hKl can have special value HKL_NEXT or HKL_PREV */ + if (hKl == (HKL)HKL_NEXT) + { + /* Get next keyboard layout starting with current */ + if (pti->KeyboardLayout) + pKl = pti->KeyboardLayout->pklNext; + } + else if (hKl == (HKL)HKL_PREV) + { + /* 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; }
- if (hKl == (HKL)HKL_NEXT) - { - pKbl = CONTAINING_RECORD(pti->KeyboardLayout->List.Flink, KL, List); - } - 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; - } - } - else - { - ERR("Invalid HKL %x!\n", hKl); + 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;
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/keyboard.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/ntu... ============================================================================== --- trunk/reactos/subsystems/win32/win32k/ntuser/keyboard.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/win32/win32k/ntuser/keyboard.c [iso-8859-1] Wed Oct 19 20:03:50 2011 @@ -891,7 +891,7 @@ 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 @@ { pFocusThread = pFocusQueue->Thread; if (pFocusThread && pFocusThread->Tcb.Win32Thread) - pKbl = ((PTHREADINFO)pFocusThread->Tcb.Win32Thread)->KeyboardLayout; - } - - if (!pKbl) - pKbl = W32kGetDefaultKeyLayout(); - if (!pKbl) + pKl = ((PTHREADINFO)pFocusThread->Tcb.Win32Thread)->KeyboardLayout; + } + + 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 @@ 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 @@ { pFocusThread = pFocusQueue->Thread; if (pFocusThread && pFocusThread->Tcb.Win32Thread) - pKbl = ((PTHREADINFO)pFocusThread->Tcb.Win32Thread)->KeyboardLayout; - } - - if (!pKbl) - pKbl = W32kGetDefaultKeyLayout(); - if (!pKbl) + pKl = ((PTHREADINFO)pFocusThread->Tcb.Win32Thread)->KeyboardLayout; + } + + 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 @@ }
pti = pWnd->head.pti; - pKbdTbl = pti->KeyboardLayout->KBTables; + pKbdTbl = pti->KeyboardLayout->spkf->pKbdTbl; if (!pKbdTbl) return FALSE;
@@ -1207,15 +1207,15 @@
pti = PsGetCurrentThreadWin32Thread(); if (pti && pti->KeyboardLayout) - pKbdTbl = pti->KeyboardLayout->KBTables; + pKbdTbl = pti->KeyboardLayout->spkf->pKbdTbl; } else { - PKL pKbl; - - pKbl = UserHklToKbl(dwhkl); - if (pKbl) - pKbdTbl = pKbl->KBTables; + PKL pKl; + + pKl = UserHklToKbl(dwhkl); + if (pKl) + pKbdTbl = pKl->spkf->pKbdTbl; }
if (pKbdTbl) @@ -1246,7 +1246,7 @@ 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 @@ UserEnterExclusive(); // Note: we modify wchDead static variable
if (dwhkl) - pKbl = UserHklToKbl(dwhkl); - - if (!pKbl) + pKl = UserHklToKbl(dwhkl); + + if (!pKl) { pti = PsGetCurrentThreadWin32Thread(); - pKbl = pti->KeyboardLayout; + pKl = pti->KeyboardLayout; }
iRet = IntToUnicodeEx(wVirtKey, @@ -1302,7 +1302,7 @@ 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 @@
/* 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 @@ 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 @@ { // Use given keyboard layout if (dwhkl) - pKbl = UserHklToKbl(dwhkl); + pKl = UserHklToKbl(dwhkl); } else { // Use thread keyboard layout - pKbl = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->KeyboardLayout; - } - - if (!pKbl) + pKl = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->KeyboardLayout; + } + + 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++)