https://git.reactos.org/?p=reactos.git;a=commitdiff;h=596f04be6b1710bb255b3…
commit 596f04be6b1710bb255b346bc9bc7153c7d6eb0c
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Fri Sep 16 08:09:37 2022 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Fri Sep 16 08:09:37 2022 +0900
[USER32][INPUT] Support various keyboard layouts (#4666)
- Fix IntLoadKeyboardLayout function to return the correct HKL value.
- Modify LAYOUT_LIST_NODE structure to add more information.
- Fix LayoutList_GetByHkl function to choose the IME HKLs correctly.
- Ignore DELETED entries correctly.
- Improve UI/UX.
CORE-11700, CORE-13244, CORE-18364
---
dll/cpl/input/add_dialog.c | 4 +-
dll/cpl/input/input.h | 13 ++
dll/cpl/input/input_list.c | 438 +++++++++++++++++++++---------------
dll/cpl/input/input_list.h | 24 +-
dll/cpl/input/layout_list.c | 198 ++++++++++------
dll/cpl/input/layout_list.h | 9 +-
dll/cpl/input/settings_page.c | 202 ++++++-----------
win32ss/user/user32/windows/input.c | 58 +++--
8 files changed, 536 insertions(+), 410 deletions(-)
diff --git a/dll/cpl/input/add_dialog.c b/dll/cpl/input/add_dialog.c
index 5156b190834..96567cf8d8a 100644
--- a/dll/cpl/input/add_dialog.c
+++ b/dll/cpl/input/add_dialog.c
@@ -93,7 +93,7 @@ OnInitAddDialog(HWND hwndDlg)
iItemIndex = ComboBox_AddString(hwndLayoutCombo, pCurrentLayout->pszName);
ComboBox_SetItemData(hwndLayoutCombo, iItemIndex, pCurrentLayout);
- if (pCurrentLayout->dwId == dwDefaultLayoutId)
+ if (pCurrentLayout->dwKLID == dwDefaultLayoutId)
{
ComboBox_SetCurSel(hwndLayoutCombo, iItemIndex);
}
@@ -159,7 +159,7 @@ OnCommandAddDialog(HWND hwndDlg, WPARAM wParam)
pCurrentLayout =
(LAYOUT_LIST_NODE*)ComboBox_GetItemData(hwndLayoutCombo, iIndex);
- if (pCurrentLayout != NULL && pCurrentLayout->dwId ==
dwLayoutId)
+ if (pCurrentLayout != NULL && pCurrentLayout->dwKLID
== dwLayoutId)
{
ComboBox_SetCurSel(hwndLayoutCombo, iIndex);
break;
diff --git a/dll/cpl/input/input.h b/dll/cpl/input/input.h
index f7ab1f47141..4f06ea66ac6 100644
--- a/dll/cpl/input/input.h
+++ b/dll/cpl/input/input.h
@@ -81,4 +81,17 @@ DWORDfromString(const WCHAR *pszString)
return wcstoul(pszString, &pszEnd, 16);
}
+#define IME_MASK (0xE0000000UL)
+#define SUBST_MASK (0xD0000000UL)
+#define SPECIAL_MASK (0xF0000000UL)
+
+#define IS_IME_HKL(hKL) ((((ULONG_PTR)(hKL)) & 0xF0000000) == IME_MASK)
+#define IS_SPECIAL_HKL(hKL) ((((ULONG_PTR)(hKL)) & 0xF0000000) ==
SPECIAL_MASK)
+#define SPECIALIDFROMHKL(hKL) ((WORD)(HIWORD(hKL) & 0x0FFF))
+
+#define IS_IME_KLID(dwKLID) ((((ULONG)(dwKLID)) & 0xF0000000) == IME_MASK)
+#define IS_SUBST_KLID(dwKLID) ((((ULONG)(dwKLID)) & 0xF0000000) == SUBST_MASK)
+
+VOID GetSystemLibraryPath(LPWSTR pszPath, INT cchPath, LPCWSTR pszFileName);
+
#endif /* _INPUT_H */
diff --git a/dll/cpl/input/input_list.c b/dll/cpl/input/input_list.c
index e0a409f5a72..97fe16a13b6 100644
--- a/dll/cpl/input/input_list.c
+++ b/dll/cpl/input/input_list.c
@@ -23,9 +23,7 @@ BOOL UpdateRegistryForFontSubstitutes(MUI_SUBFONT *pSubstitutes)
static const WCHAR pszKey[] =
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes";
- hKey = NULL;
- RegOpenKeyExW(HKEY_LOCAL_MACHINE, pszKey, 0, KEY_ALL_ACCESS, &hKey);
- if (hKey == NULL)
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, pszKey, 0, KEY_ALL_ACCESS, &hKey) !=
ERROR_SUCCESS)
return FALSE;
/* Overwrite only */
@@ -37,10 +35,16 @@ BOOL UpdateRegistryForFontSubstitutes(MUI_SUBFONT *pSubstitutes)
}
RegCloseKey(hKey);
-
return TRUE;
}
+VOID GetSystemLibraryPath(LPWSTR pszPath, INT cchPath, LPCWSTR pszFileName)
+{
+ WCHAR szSysDir[MAX_PATH];
+ GetSystemDirectoryW(szSysDir, ARRAYSIZE(szSysDir));
+ StringCchPrintfW(pszPath, cchPath, L"%s\\%s", szSysDir, pszFileName);
+}
+
BOOL
InputList_SetFontSubstitutes(LCID dwLocaleId)
{
@@ -135,29 +139,28 @@ InputList_AppendNode(VOID)
INPUT_LIST_NODE *pCurrent;
INPUT_LIST_NODE *pNew;
- pCurrent = _InputList;
-
pNew = (INPUT_LIST_NODE*)malloc(sizeof(INPUT_LIST_NODE));
if (pNew == NULL)
return NULL;
ZeroMemory(pNew, sizeof(INPUT_LIST_NODE));
- if (pCurrent == NULL)
+ if (_InputList == NULL) /* Empty? */
{
_InputList = pNew;
+ return pNew;
}
- else
- {
- while (pCurrent->pNext != NULL)
- {
- pCurrent = pCurrent->pNext;
- }
- pNew->pPrev = pCurrent;
- pCurrent->pNext = pNew;
+ /* Find last node */
+ for (pCurrent = _InputList; pCurrent->pNext; pCurrent = pCurrent->pNext)
+ {
+ ;
}
+ /* Add to the end */
+ pCurrent->pNext = pNew;
+ pNew->pPrev = pCurrent;
+
return pNew;
}
@@ -193,20 +196,17 @@ VOID
InputList_Destroy(VOID)
{
INPUT_LIST_NODE *pCurrent;
+ INPUT_LIST_NODE *pNext;
if (_InputList == NULL)
return;
- pCurrent = _InputList;
-
- while (pCurrent != NULL)
+ for (pCurrent = _InputList; pCurrent; pCurrent = pNext)
{
- INPUT_LIST_NODE *pNext = pCurrent->pNext;
+ pNext = pCurrent->pNext;
free(pCurrent->pszIndicator);
free(pCurrent);
-
- pCurrent = pNext;
}
_InputList = NULL;
@@ -214,11 +214,12 @@ InputList_Destroy(VOID)
static BOOL
-InputList_PrepareUserRegistry(VOID)
+InputList_PrepareUserRegistry(PHKEY phPreloadKey, PHKEY phSubstKey)
{
BOOL bResult = FALSE;
- HKEY hTempKey = NULL;
- HKEY hKey = NULL;
+ HKEY hKey;
+
+ *phPreloadKey = *phSubstKey = NULL;
if (RegOpenKeyExW(HKEY_CURRENT_USER,
L"Keyboard Layout",
@@ -232,101 +233,143 @@ InputList_PrepareUserRegistry(VOID)
RegCloseKey(hKey);
}
- if (RegCreateKeyW(HKEY_CURRENT_USER, L"Keyboard Layout", &hKey) !=
ERROR_SUCCESS)
+ if (RegCreateKeyW(HKEY_CURRENT_USER, L"Keyboard Layout", &hKey) ==
ERROR_SUCCESS &&
+ RegCreateKeyW(hKey, L"Preload", phPreloadKey) == ERROR_SUCCESS
&&
+ RegCreateKeyW(hKey, L"Substitutes", phSubstKey) == ERROR_SUCCESS)
{
- goto Cleanup;
+ bResult = TRUE;
}
- if (RegCreateKeyW(hKey, L"Preload", &hTempKey) != ERROR_SUCCESS)
- {
- goto Cleanup;
- }
+ if (hKey)
+ RegCloseKey(hKey);
- RegCloseKey(hTempKey);
+ return bResult;
+}
- if (RegCreateKeyW(hKey, L"Substitutes", &hTempKey) != ERROR_SUCCESS)
+static BOOL
+InputList_FindPreloadKLID(HKEY hPreloadKey, DWORD dwKLID)
+{
+ DWORD dwNumber, dwType, cbValue;
+ WCHAR szNumber[16], szValue[KL_NAMELENGTH], szKLID[KL_NAMELENGTH];
+
+ StringCchPrintfW(szKLID, ARRAYSIZE(szKLID), L"%08x", dwKLID);
+
+ for (dwNumber = 1; dwNumber <= 1000; ++dwNumber)
{
- goto Cleanup;
- }
+ StringCchPrintfW(szNumber, ARRAYSIZE(szNumber), L"%u", dwNumber);
- RegCloseKey(hTempKey);
+ cbValue = ARRAYSIZE(szValue) * sizeof(WCHAR);
+ if (RegQueryValueExW(hPreloadKey, szNumber, NULL, &dwType,
+ (LPBYTE)szValue, &cbValue) != ERROR_SUCCESS)
+ {
+ break;
+ }
- bResult = TRUE;
+ if (dwType != REG_SZ)
+ continue;
-Cleanup:
- if (hTempKey != NULL)
- RegCloseKey(hTempKey);
- if (hKey != NULL)
- RegCloseKey(hKey);
+ szValue[ARRAYSIZE(szValue) - 1] = 0;
+ if (_wcsicmp(szKLID, szValue) == 0)
+ return TRUE;
+ }
- return bResult;
+ return FALSE;
}
-
-static VOID
-InputList_AddInputMethodToUserRegistry(DWORD dwIndex, INPUT_LIST_NODE *pNode)
+static BOOL
+InputList_WriteSubst(HKEY hSubstKey, DWORD dwPhysicalKLID, DWORD dwLogicalKLID)
{
- WCHAR szMethodIndex[MAX_PATH];
- WCHAR szPreload[MAX_PATH];
- BOOL bIsImeMethod = FALSE;
- HKEY hKey;
+ DWORD cbValue;
+ WCHAR szLogicalKLID[KL_NAMELENGTH], szPhysicalKLID[KL_NAMELENGTH];
- StringCchPrintfW(szMethodIndex, ARRAYSIZE(szMethodIndex), L"%lu",
dwIndex);
+ StringCchPrintfW(szLogicalKLID, ARRAYSIZE(szLogicalKLID), L"%08x",
dwLogicalKLID);
+ StringCchPrintfW(szPhysicalKLID, ARRAYSIZE(szPhysicalKLID), L"%08x",
dwPhysicalKLID);
- /* Check is IME method */
- if ((HIWORD(pNode->pLayout->dwId) & 0xF000) == 0xE000)
- {
- StringCchPrintfW(szPreload, ARRAYSIZE(szPreload), L"%08X",
pNode->pLayout->dwId);
- bIsImeMethod = TRUE;
- }
- else
- {
- StringCchPrintfW(szPreload, ARRAYSIZE(szPreload), L"%08X",
pNode->pLocale->dwId);
- }
+ cbValue = (wcslen(szPhysicalKLID) + 1) * sizeof(WCHAR);
+ return RegSetValueExW(hSubstKey, szLogicalKLID, 0, REG_SZ, (LPBYTE)szPhysicalKLID,
+ cbValue) == ERROR_SUCCESS;
+}
- if (RegOpenKeyExW(HKEY_CURRENT_USER,
- L"Keyboard Layout\\Preload",
- 0,
- KEY_SET_VALUE,
- &hKey) == ERROR_SUCCESS)
+static DWORD
+InputList_DoSubst(HKEY hPreloadKey, HKEY hSubstKey,
+ DWORD dwPhysicalKLID, DWORD dwLogicalKLID)
+{
+ DWORD iTrial;
+ BOOL bSubstNeeded = (dwPhysicalKLID != dwLogicalKLID) || (HIWORD(dwPhysicalKLID) !=
0);
+
+ for (iTrial = 1; iTrial <= 1000; ++iTrial)
{
- RegSetValueExW(hKey,
- szMethodIndex,
- 0,
- REG_SZ,
- (LPBYTE)szPreload,
- (wcslen(szPreload) + 1) * sizeof(WCHAR));
+ if (!InputList_FindPreloadKLID(hPreloadKey, dwLogicalKLID)) /* Not found? */
+ {
+ if (bSubstNeeded)
+ {
+ /* Write now */
+ InputList_WriteSubst(hSubstKey, dwPhysicalKLID, dwLogicalKLID);
+ }
+ return dwLogicalKLID;
+ }
- RegCloseKey(hKey);
- }
+ bSubstNeeded = TRUE;
- if (pNode->pLocale->dwId != pNode->pLayout->dwId && bIsImeMethod
== FALSE)
- {
- if (RegOpenKeyExW(HKEY_CURRENT_USER,
- L"Keyboard Layout\\Substitutes",
- 0,
- KEY_SET_VALUE,
- &hKey) == ERROR_SUCCESS)
+ /* Calculate the next logical KLID */
+ if (!IS_SUBST_KLID(dwLogicalKLID))
+ {
+ dwLogicalKLID |= SUBST_MASK;
+ }
+ else
{
- WCHAR szSubstitutes[MAX_PATH];
+ WORD wLow = LOWORD(dwLogicalKLID);
+ WORD wHigh = HIWORD(dwLogicalKLID);
+ dwLogicalKLID = MAKELONG(wLow, wHigh + 1);
+ }
+ }
- StringCchPrintfW(szSubstitutes, ARRAYSIZE(szSubstitutes), L"%08X",
pNode->pLayout->dwId);
+ return 0;
+}
- RegSetValueExW(hKey,
- szPreload,
- 0,
- REG_SZ,
- (LPBYTE)szSubstitutes,
- (wcslen(szSubstitutes) + 1) * sizeof(WCHAR));
+static VOID
+InputList_AddInputMethodToUserRegistry(
+ HKEY hPreloadKey,
+ HKEY hSubstKey,
+ DWORD dwNumber,
+ INPUT_LIST_NODE *pNode)
+{
+ WCHAR szNumber[32], szLogicalKLID[KL_NAMELENGTH];
+ DWORD dwPhysicalKLID, dwLogicalKLID, cbValue;
+ HKL hKL = pNode->hkl;
- RegCloseKey(hKey);
- }
+ if (IS_IME_HKL(hKL)) /* IME? */
+ {
+ /* Do not substitute the IME KLID */
+ dwLogicalKLID = dwPhysicalKLID = HandleToUlong(hKL);
+ }
+ else
+ {
+ /* Substitute the KLID if necessary */
+ dwPhysicalKLID = pNode->pLayout->dwKLID;
+ dwLogicalKLID = pNode->pLocale->dwId;
+ dwLogicalKLID = InputList_DoSubst(hPreloadKey, hSubstKey, dwPhysicalKLID,
dwLogicalKLID);
}
+ /* Write the Preload value (number |--> logical KLID) */
+ StringCchPrintfW(szNumber, ARRAYSIZE(szNumber), L"%lu", dwNumber);
+ StringCchPrintfW(szLogicalKLID, ARRAYSIZE(szLogicalKLID), L"%08x",
dwLogicalKLID);
+ cbValue = (wcslen(szLogicalKLID) + 1) * sizeof(WCHAR);
+ RegSetValueExW(hPreloadKey,
+ szNumber,
+ 0,
+ REG_SZ,
+ (LPBYTE)szLogicalKLID,
+ cbValue);
+
if ((pNode->wFlags & INPUT_LIST_NODE_FLAG_ADDED) ||
(pNode->wFlags & INPUT_LIST_NODE_FLAG_EDITED))
{
- pNode->hkl = LoadKeyboardLayoutW(szPreload, KLF_SUBSTITUTE_OK |
KLF_NOTELLSHELL);
+ UINT uFlags = KLF_SUBSTITUTE_OK | KLF_NOTELLSHELL;
+ if (pNode->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT)
+ uFlags |= KLF_REPLACELANG;
+
+ pNode->hkl = LoadKeyboardLayoutW(szLogicalKLID, uFlags);
}
}
@@ -338,19 +381,30 @@ BOOL
InputList_Process(VOID)
{
INPUT_LIST_NODE *pCurrent;
- DWORD dwIndex;
+ DWORD dwNumber;
BOOL bRet = FALSE;
+ HKEY hPreloadKey, hSubstKey;
- /* Process deleted and edited input methods */
+ if (!InputList_PrepareUserRegistry(&hPreloadKey, &hSubstKey))
+ {
+ if (hPreloadKey)
+ RegCloseKey(hPreloadKey);
+ if (hSubstKey)
+ RegCloseKey(hSubstKey);
+ return FALSE;
+ }
+
+ /* Process DELETED and EDITED entries */
for (pCurrent = _InputList; pCurrent != NULL; pCurrent = pCurrent->pNext)
{
if ((pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DELETED) ||
(pCurrent->wFlags & INPUT_LIST_NODE_FLAG_EDITED))
{
+ /* Only unload the DELETED and EDITED entries */
if (UnloadKeyboardLayout(pCurrent->hkl))
{
- /* Only unload the edited input method, but does not delete it from the
list */
- if (!(pCurrent->wFlags & INPUT_LIST_NODE_FLAG_EDITED))
+ /* But the EDITED entries are used later */
+ if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DELETED)
{
InputList_RemoveNode(pCurrent);
}
@@ -358,27 +412,44 @@ InputList_Process(VOID)
}
}
- InputList_PrepareUserRegistry();
-
- /* Find default input method */
+ /* Add the DEFAULT entry and set font substitutes */
for (pCurrent = _InputList; pCurrent != NULL; pCurrent = pCurrent->pNext)
{
+ if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DELETED)
+ continue;
+
if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT)
{
bRet = InputList_SetFontSubstitutes(pCurrent->pLocale->dwId);
- InputList_AddInputMethodToUserRegistry(1, pCurrent);
+ InputList_AddInputMethodToUserRegistry(hPreloadKey, hSubstKey, 1, pCurrent);
break;
}
}
- if (SystemParametersInfoW(SPI_SETDEFAULTINPUTLANG,
- 0,
- (LPVOID)((LPDWORD)&pCurrent->hkl),
- 0))
+ /* Add entries except DEFAULT to registry */
+ dwNumber = 2;
+ for (pCurrent = _InputList; pCurrent != NULL; pCurrent = pCurrent->pNext)
{
- DWORD dwRecipients;
+ if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DELETED)
+ continue;
+ if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT)
+ continue;
- dwRecipients = BSM_ALLCOMPONENTS;
+ InputList_AddInputMethodToUserRegistry(hPreloadKey, hSubstKey, dwNumber,
pCurrent);
+
+ ++dwNumber;
+ }
+
+ /* Remove ADDED and EDITED flags */
+ for (pCurrent = _InputList; pCurrent != NULL; pCurrent = pCurrent->pNext)
+ {
+ pCurrent->wFlags &= ~(INPUT_LIST_NODE_FLAG_ADDED |
INPUT_LIST_NODE_FLAG_EDITED);
+ }
+
+ /* Change the default keyboard language */
+ if (SystemParametersInfoW(SPI_SETDEFAULTINPUTLANG, 0, &pCurrent->hkl, 0))
+ {
+ DWORD dwRecipients = BSM_ALLCOMPONENTS | BSM_ALLDESKTOPS;
BroadcastSystemMessageW(BSF_POSTMESSAGE,
&dwRecipients,
@@ -387,19 +458,18 @@ InputList_Process(VOID)
(LPARAM)pCurrent->hkl);
}
- /* Add methods to registry */
- dwIndex = 2;
-
+ /* Retry to delete (in case of failure to delete the default keyboard) */
for (pCurrent = _InputList; pCurrent != NULL; pCurrent = pCurrent->pNext)
{
- if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT)
- continue;
-
- InputList_AddInputMethodToUserRegistry(dwIndex, pCurrent);
-
- dwIndex++;
+ if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DELETED)
+ {
+ UnloadKeyboardLayout(pCurrent->hkl);
+ InputList_RemoveNode(pCurrent);
+ }
}
+ RegCloseKey(hPreloadKey);
+ RegCloseKey(hSubstKey);
return bRet;
}
@@ -408,7 +478,7 @@ BOOL
InputList_Add(LOCALE_LIST_NODE *pLocale, LAYOUT_LIST_NODE *pLayout)
{
WCHAR szIndicator[MAX_STR_LEN];
- INPUT_LIST_NODE *pInput;
+ INPUT_LIST_NODE *pInput = NULL;
if (pLocale == NULL || pLayout == NULL)
{
@@ -417,16 +487,17 @@ InputList_Add(LOCALE_LIST_NODE *pLocale, LAYOUT_LIST_NODE *pLayout)
for (pInput = _InputList; pInput != NULL; pInput = pInput->pNext)
{
+ if (pInput->wFlags & INPUT_LIST_NODE_FLAG_DELETED)
+ continue;
+
if (pInput->pLocale == pLocale && pInput->pLayout == pLayout)
{
- return FALSE;
+ return FALSE; /* Already exists */
}
}
pInput = InputList_AppendNode();
-
pInput->wFlags = INPUT_LIST_NODE_FLAG_ADDED;
-
pInput->pLocale = pLocale;
pInput->pLayout = pLayout;
@@ -469,6 +540,29 @@ InputList_SetDefault(INPUT_LIST_NODE *pNode)
}
}
+INPUT_LIST_NODE *
+InputList_FindNextDefault(INPUT_LIST_NODE *pNode)
+{
+ INPUT_LIST_NODE *pCurrent;
+
+ for (pCurrent = pNode->pNext; pCurrent; pCurrent = pCurrent->pNext)
+ {
+ if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DELETED)
+ continue;
+
+ return pCurrent;
+ }
+
+ for (pCurrent = pNode->pPrev; pCurrent; pCurrent = pCurrent->pPrev)
+ {
+ if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DELETED)
+ continue;
+
+ return pCurrent;
+ }
+
+ return NULL;
+}
/*
* It marks the input method for deletion, but does not delete it directly.
@@ -492,22 +586,19 @@ InputList_Remove(INPUT_LIST_NODE *pNode)
}
else
{
- pNode->wFlags = INPUT_LIST_NODE_FLAG_DELETED;
+ pNode->wFlags |= INPUT_LIST_NODE_FLAG_DELETED;
}
if (pNode->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT)
{
- if (pNode->pNext != NULL)
- {
- pNode->pNext->wFlags |= INPUT_LIST_NODE_FLAG_DEFAULT;
- }
- else if (pNode->pPrev != NULL)
- {
- pNode->pPrev->wFlags |= INPUT_LIST_NODE_FLAG_DEFAULT;
- }
+ INPUT_LIST_NODE *pCurrent = InputList_FindNextDefault(pNode);
+ if (pCurrent)
+ pCurrent->wFlags |= INPUT_LIST_NODE_FLAG_DEFAULT;
+
+ pNode->wFlags &= ~INPUT_LIST_NODE_FLAG_DEFAULT;
}
- if (bRemoveNode != FALSE)
+ if (bRemoveNode)
{
InputList_RemoveNode(pNode);
}
@@ -517,67 +608,58 @@ InputList_Remove(INPUT_LIST_NODE *pNode)
VOID
InputList_Create(VOID)
{
- INT iLayoutCount;
- HKL *pLayoutList;
+ INT iLayoutCount, iIndex;
+ WCHAR szIndicator[MAX_STR_LEN];
+ INPUT_LIST_NODE *pInput;
+ HKL *pLayoutList, hklDefault;
+
+ SystemParametersInfoW(SPI_GETDEFAULTINPUTLANG, 0, &hklDefault, 0);
iLayoutCount = GetKeyboardLayoutList(0, NULL);
pLayoutList = (HKL*) malloc(iLayoutCount * sizeof(HKL));
- if (pLayoutList != NULL)
+ if (!pLayoutList || GetKeyboardLayoutList(iLayoutCount, pLayoutList) <= 0)
{
- if (GetKeyboardLayoutList(iLayoutCount, pLayoutList) > 0)
+ free(pLayoutList);
+ return;
+ }
+
+ for (iIndex = 0; iIndex < iLayoutCount; ++iIndex)
+ {
+ HKL hKL = pLayoutList[iIndex];
+ LOCALE_LIST_NODE *pLocale = LocaleList_GetByHkl(hKL);
+ LAYOUT_LIST_NODE *pLayout = LayoutList_GetByHkl(hKL);
+ if (!pLocale || !pLayout)
+ continue;
+
+ pInput = InputList_AppendNode();
+ pInput->pLocale = pLocale;
+ pInput->pLayout = pLayout;
+ pInput->hkl = hKL;
+
+ if (pInput->hkl == hklDefault) /* Default HKL? */
{
- INT iIndex;
+ pInput->wFlags |= INPUT_LIST_NODE_FLAG_DEFAULT;
+ hklDefault = NULL; /* No more default item */
+ }
- for (iIndex = 0; iIndex < iLayoutCount; iIndex++)
+ /* Get abbrev language name */
+ szIndicator[0] = 0;
+ if (GetLocaleInfoW(LOWORD(pInput->pLocale->dwId),
+ LOCALE_SABBREVLANGNAME | LOCALE_NOUSEROVERRIDE,
+ szIndicator,
+ ARRAYSIZE(szIndicator)))
+ {
+ size_t len = wcslen(szIndicator);
+ if (len > 0)
{
- LOCALE_LIST_NODE *pLocale = LocaleList_GetByHkl(pLayoutList[iIndex]);
- LAYOUT_LIST_NODE *pLayout = LayoutList_GetByHkl(pLayoutList[iIndex]);
-
- if (pLocale != NULL && pLayout != NULL)
- {
- WCHAR szIndicator[MAX_STR_LEN] = { 0 };
- INPUT_LIST_NODE *pInput;
- HKL hklDefault;
-
- pInput = InputList_AppendNode();
-
- pInput->pLocale = pLocale;
- pInput->pLayout = pLayout;
- pInput->hkl = pLayoutList[iIndex];
-
- if (SystemParametersInfoW(SPI_GETDEFAULTINPUTLANG,
- 0,
- (LPVOID)((LPDWORD)&hklDefault),
- 0) == FALSE)
- {
- hklDefault = GetKeyboardLayout(0);
- }
-
- if (pInput->hkl == hklDefault)
- {
- pInput->wFlags |= INPUT_LIST_NODE_FLAG_DEFAULT;
- }
-
- if (GetLocaleInfoW(LOWORD(pInput->pLocale->dwId),
- LOCALE_SABBREVLANGNAME | LOCALE_NOUSEROVERRIDE,
- szIndicator,
- ARRAYSIZE(szIndicator)))
- {
- size_t len = wcslen(szIndicator);
-
- if (len > 0)
- {
- szIndicator[len - 1] = 0;
- pInput->pszIndicator = _wcsdup(szIndicator);
- }
- }
- }
+ szIndicator[len - 1] = 0;
+ pInput->pszIndicator = _wcsdup(szIndicator);
}
}
-
- free(pLayoutList);
}
+
+ free(pLayoutList);
}
diff --git a/dll/cpl/input/input_list.h b/dll/cpl/input/input_list.h
index e578cc70423..5c947dbaae2 100644
--- a/dll/cpl/input/input_list.h
+++ b/dll/cpl/input/input_list.h
@@ -4,12 +4,30 @@
#include "locale_list.h"
#include "layout_list.h"
-
+/*
+ * INPUT_LIST_NODE_FLAG_EDITED
+ * --- The modification flag. Since previous time, this entry is modified.
+ */
#define INPUT_LIST_NODE_FLAG_EDITED 0x0001
+
+/*
+ * INPUT_LIST_NODE_FLAG_ADDED
+ * --- The addition flag. Since previous time, this entry is newly added.
+ */
#define INPUT_LIST_NODE_FLAG_ADDED 0x0002
+
+/*
+ * INPUT_LIST_NODE_FLAG_DELETED
+ * --- The deletion flag.
+ * The application should ignore the entry with this flag if necessary.
+ */
#define INPUT_LIST_NODE_FLAG_DELETED 0x0004
-#define INPUT_LIST_NODE_FLAG_DEFAULT 0x0008
+/*
+ * INPUT_LIST_NODE_FLAG_DEFAULT
+ * --- The default flag. The entry with this flag should be single in the list.
+ */
+#define INPUT_LIST_NODE_FLAG_DEFAULT 0x0008
typedef struct _INPUT_LIST_NODE
{
@@ -20,7 +38,7 @@ typedef struct _INPUT_LIST_NODE
HKL hkl; /* Only for loaded input methods */
- WCHAR *pszIndicator;
+ LPWSTR pszIndicator;
struct _INPUT_LIST_NODE *pPrev;
struct _INPUT_LIST_NODE *pNext;
diff --git a/dll/cpl/input/layout_list.c b/dll/cpl/input/layout_list.c
index 7a06ea77f70..9d6622312ee 100644
--- a/dll/cpl/input/layout_list.c
+++ b/dll/cpl/input/layout_list.c
@@ -3,16 +3,16 @@
* FILE: dll/cpl/input/layout_list.c
* PURPOSE: input.dll
* PROGRAMMER: Dmitry Chapyshev (dmitry(a)reactos.org)
+ * Katayama Hirofumi MZ (katayama.hirofumi.mz(a)gmail.com)
*/
#include "layout_list.h"
-
static LAYOUT_LIST_NODE *_LayoutList = NULL;
-
static LAYOUT_LIST_NODE*
-LayoutList_AppendNode(DWORD dwId, DWORD dwSpecialId, const WCHAR *pszName)
+LayoutList_AppendNode(DWORD dwKLID, WORD wSpecialId, LPCWSTR pszFile, LPCWSTR pszName,
+ LPCWSTR pszImeFile)
{
LAYOUT_LIST_NODE *pCurrent;
LAYOUT_LIST_NODE *pNew;
@@ -28,16 +28,22 @@ LayoutList_AppendNode(DWORD dwId, DWORD dwSpecialId, const WCHAR
*pszName)
ZeroMemory(pNew, sizeof(LAYOUT_LIST_NODE));
+ pNew->dwKLID = dwKLID;
+ pNew->wSpecialId = wSpecialId;
+
pNew->pszName = _wcsdup(pszName);
- if (pNew->pszName == NULL)
+ pNew->pszFile = _wcsdup(pszFile);
+ pNew->pszImeFile = _wcsdup(pszImeFile);
+ if (pNew->pszName == NULL || pNew->pszFile == NULL ||
+ (pszImeFile && pNew->pszImeFile == NULL))
{
+ free(pNew->pszName);
+ free(pNew->pszFile);
+ free(pNew->pszImeFile);
free(pNew);
return NULL;
}
- pNew->dwId = dwId;
- pNew->dwSpecialId = dwSpecialId;
-
if (pCurrent == NULL)
{
_LayoutList = pNew;
@@ -61,90 +67,136 @@ VOID
LayoutList_Destroy(VOID)
{
LAYOUT_LIST_NODE *pCurrent;
+ LAYOUT_LIST_NODE *pNext;
if (_LayoutList == NULL)
return;
- pCurrent = _LayoutList;
-
- while (pCurrent != NULL)
+ for (pCurrent = _LayoutList; pCurrent; pCurrent = pNext)
{
- LAYOUT_LIST_NODE *pNext = pCurrent->pNext;
+ pNext = pCurrent->pNext;
free(pCurrent->pszName);
+ free(pCurrent->pszFile);
+ free(pCurrent->pszImeFile);
free(pCurrent);
-
- pCurrent = pNext;
}
_LayoutList = NULL;
}
-static BOOL
-LayoutList_ReadLayout(HKEY hLayoutKey, LPCWSTR szLayoutId, LPCWSTR szSystemDirectory)
+typedef HRESULT (WINAPI *FN_SHLoadRegUIStringW)(HKEY, LPCWSTR, LPWSTR, DWORD);
+
+/* FIXME: Use shlwapi!SHLoadRegUIStringW instead when it is fully implemented */
+HRESULT FakeSHLoadRegUIStringW(HKEY hkey, LPCWSTR value, LPWSTR buf, DWORD size)
{
- WCHAR szBuffer[MAX_PATH], szFilePath[MAX_PATH], szDllPath[MAX_PATH];
- INT iIndex, iLength = 0;
- DWORD dwSize, dwSpecialId, dwLayoutId = DWORDfromString(szLayoutId);
+#if 1
+ PWCHAR pBuffer, pIndex;
+ WCHAR szDllPath[MAX_PATH];
+ DWORD dwSize;
HINSTANCE hDllInst;
+ INT iIndex, iLength;
- dwSize = sizeof(szBuffer);
+ dwSize = size * sizeof(WCHAR);
+ if (RegQueryValueExW(hkey, value, NULL, NULL, (LPBYTE)buf, &dwSize) !=
ERROR_SUCCESS)
+ return E_FAIL;
+
+ if (buf[0] != L'@')
+ return S_OK;
+
+ /* Move to the position after the character "@" */
+ pBuffer = buf + 1;
+
+ /* Get a pointer to the beginning ",-" */
+ pIndex = wcsstr(pBuffer, L",-");
+ if (!pIndex)
+ return E_FAIL;
+
+ /* Convert the number in the string after the ",-" */
+ iIndex = _wtoi(pIndex + 2);
+
+ *pIndex = 0; /* Cut the string */
+
+ if (ExpandEnvironmentStringsW(pBuffer, szDllPath, ARRAYSIZE(szDllPath)) == 0)
+ return E_FAIL;
+
+ hDllInst = LoadLibraryW(szDllPath);
+ if (!hDllInst)
+ return E_FAIL;
+
+ iLength = LoadStringW(hDllInst, iIndex, buf, size);
+ FreeLibrary(hDllInst);
+
+ if (iLength <= 0)
+ return E_FAIL;
+
+ return S_OK;
+#else
+ HRESULT hr = E_FAIL;
+ HINSTANCE hSHLWAPI = LoadLibraryW(L"shlwapi");
+ FN_SHLoadRegUIStringW fn;
+ fn = (FN_SHLoadRegUIStringW)GetProcAddress(hSHLWAPI, (LPCSTR)(INT_PTR)439);
+ if (fn)
+ hr = fn(hkey, value, buf, size);
+ FreeLibrary(hSHLWAPI);
+ return hr;
+#endif
+}
+
+static BOOL
+LayoutList_ReadLayout(HKEY hLayoutKey, LPCWSTR szKLID, LPCWSTR szSystemDirectory)
+{
+ WCHAR szFile[80], szImeFile[80], szBuffer[MAX_PATH], szFilePath[MAX_PATH];
+ DWORD dwSize, dwKLID = DWORDfromString(szKLID);
+ WORD wSpecialId = 0;
+ LPWSTR pszImeFile = NULL;
+
+ dwSize = sizeof(szFile);
if (RegQueryValueExW(hLayoutKey, L"Layout File", NULL, NULL,
- (LPBYTE)szBuffer, &dwSize) != ERROR_SUCCESS)
+ (LPBYTE)szFile, &dwSize) != ERROR_SUCCESS)
{
return FALSE; /* No "Layout File" value */
}
+ if (IS_IME_KLID(dwKLID))
+ {
+ WCHAR szPath[MAX_PATH];
+ dwSize = sizeof(szImeFile);
+ if (RegQueryValueExW(hLayoutKey, L"IME File", NULL, NULL,
+ (LPBYTE)szImeFile, &dwSize) != ERROR_SUCCESS)
+ {
+ return FALSE; /* No "IME File" value */
+ }
+
+ if (wcschr(szImeFile, L'\\') != NULL)
+ return FALSE; /* Invalid character */
+
+ GetSystemLibraryPath(szPath, ARRAYSIZE(szPath), szImeFile);
+ if (GetFileAttributesW(szPath) == INVALID_FILE_ATTRIBUTES)
+ return FALSE; /* Does not exist */
+
+ pszImeFile = szImeFile;
+ }
+
/* Build the "Layout File" full path and check existence */
- StringCchPrintfW(szFilePath, ARRAYSIZE(szFilePath), L"%s\\%s",
szSystemDirectory, szBuffer);
+ StringCchPrintfW(szFilePath, ARRAYSIZE(szFilePath), L"%s\\%s",
szSystemDirectory, szFile);
if (GetFileAttributesW(szFilePath) == INVALID_FILE_ATTRIBUTES)
return FALSE; /* No layout file found */
/* Get the special ID */
- dwSpecialId = 0;
dwSize = sizeof(szBuffer);
if (RegQueryValueExW(hLayoutKey, L"Layout Id", NULL, NULL,
(LPBYTE)szBuffer, &dwSize) == ERROR_SUCCESS)
{
- dwSpecialId = DWORDfromString(szBuffer);
+ wSpecialId = LOWORD(DWORDfromString(szBuffer));
}
/* If there is a valid "Layout Display Name", then use it as the entry name
*/
- dwSize = sizeof(szBuffer);
- if (RegQueryValueExW(hLayoutKey, L"Layout Display Name", NULL, NULL,
- (LPBYTE)szBuffer, &dwSize) == ERROR_SUCCESS &&
szBuffer[0] == L'@')
+ if (FakeSHLoadRegUIStringW(hLayoutKey, L"Layout Display Name",
+ szBuffer, ARRAYSIZE(szBuffer)) == S_OK)
{
- /* FIXME: Use shlwapi!SHLoadRegUIStringW instead if it had fully implemented */
-
- /* Move to the position after the character "@" */
- WCHAR *pBuffer = szBuffer + 1;
-
- /* Get a pointer to the beginning ",-" */
- WCHAR *pIndex = wcsstr(pBuffer, L",-");
-
- if (pIndex)
- {
- /* Convert the number in the string after the ",-" */
- iIndex = _wtoi(pIndex + 2);
-
- *pIndex = 0; /* Cut the string */
-
- if (ExpandEnvironmentStringsW(pBuffer, szDllPath, ARRAYSIZE(szDllPath)) !=
0)
- {
- hDllInst = LoadLibraryW(szDllPath);
- if (hDllInst)
- {
- iLength = LoadStringW(hDllInst, iIndex, szBuffer,
ARRAYSIZE(szBuffer));
- FreeLibrary(hDllInst);
-
- if (iLength > 0)
- {
- LayoutList_AppendNode(dwLayoutId, dwSpecialId, szBuffer);
- return TRUE;
- }
- }
- }
- }
+ LayoutList_AppendNode(dwKLID, wSpecialId, szFile, szBuffer, pszImeFile);
+ return TRUE;
}
/* Otherwise, use "Layout Text" value as the entry name */
@@ -152,7 +204,7 @@ LayoutList_ReadLayout(HKEY hLayoutKey, LPCWSTR szLayoutId, LPCWSTR
szSystemDirec
if (RegQueryValueExW(hLayoutKey, L"Layout Text", NULL, NULL,
(LPBYTE)szBuffer, &dwSize) == ERROR_SUCCESS)
{
- LayoutList_AppendNode(dwLayoutId, dwSpecialId, szBuffer);
+ LayoutList_AppendNode(dwKLID, wSpecialId, szFile, szBuffer, pszImeFile);
return TRUE;
}
@@ -162,7 +214,7 @@ LayoutList_ReadLayout(HKEY hLayoutKey, LPCWSTR szLayoutId, LPCWSTR
szSystemDirec
VOID
LayoutList_Create(VOID)
{
- WCHAR szSystemDirectory[MAX_PATH], szLayoutId[MAX_PATH];
+ WCHAR szSystemDirectory[MAX_PATH], szKLID[KL_NAMELENGTH];
DWORD dwSize, dwIndex;
HKEY hKey, hLayoutKey;
@@ -170,23 +222,23 @@ LayoutList_Create(VOID)
return;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts",
- 0, KEY_ENUMERATE_SUB_KEYS, &hKey) != ERROR_SUCCESS)
+ 0, KEY_READ, &hKey) != ERROR_SUCCESS)
{
return;
}
for (dwIndex = 0; ; ++dwIndex)
{
- dwSize = ARRAYSIZE(szLayoutId);
- if (RegEnumKeyExW(hKey, dwIndex, szLayoutId, &dwSize, NULL, NULL,
+ dwSize = ARRAYSIZE(szKLID);
+ if (RegEnumKeyExW(hKey, dwIndex, szKLID, &dwSize, NULL, NULL,
NULL, NULL) != ERROR_SUCCESS)
{
break;
}
- if (RegOpenKeyExW(hKey, szLayoutId, 0, KEY_QUERY_VALUE, &hLayoutKey) ==
ERROR_SUCCESS)
+ if (RegOpenKeyExW(hKey, szKLID, 0, KEY_QUERY_VALUE, &hLayoutKey) ==
ERROR_SUCCESS)
{
- LayoutList_ReadLayout(hLayoutKey, szLayoutId, szSystemDirectory);
+ LayoutList_ReadLayout(hLayoutKey, szKLID, szSystemDirectory);
RegCloseKey(hLayoutKey);
}
}
@@ -200,13 +252,23 @@ LayoutList_GetByHkl(HKL hkl)
{
LAYOUT_LIST_NODE *pCurrent;
- if ((HIWORD(hkl) & 0xF000) == 0xF000)
+ if (IS_SPECIAL_HKL(hkl))
{
- DWORD dwSpecialId = (HIWORD(hkl) & 0x0FFF);
+ WORD wSpecialId = SPECIALIDFROMHKL(hkl);
for (pCurrent = _LayoutList; pCurrent != NULL; pCurrent = pCurrent->pNext)
{
- if (dwSpecialId == pCurrent->dwSpecialId)
+ if (wSpecialId == pCurrent->wSpecialId)
+ {
+ return pCurrent;
+ }
+ }
+ }
+ else if (IS_IME_HKL(hkl))
+ {
+ for (pCurrent = _LayoutList; pCurrent != NULL; pCurrent = pCurrent->pNext)
+ {
+ if (hkl == UlongToHandle(pCurrent->dwKLID))
{
return pCurrent;
}
@@ -216,7 +278,7 @@ LayoutList_GetByHkl(HKL hkl)
{
for (pCurrent = _LayoutList; pCurrent != NULL; pCurrent = pCurrent->pNext)
{
- if (HIWORD(hkl) == LOWORD(pCurrent->dwId))
+ if (HIWORD(hkl) == LOWORD(pCurrent->dwKLID))
{
return pCurrent;
}
diff --git a/dll/cpl/input/layout_list.h b/dll/cpl/input/layout_list.h
index bbd0a0d0740..630fff7b1c5 100644
--- a/dll/cpl/input/layout_list.h
+++ b/dll/cpl/input/layout_list.h
@@ -4,10 +4,11 @@
typedef struct _LAYOUT_LIST_NODE
{
- WCHAR *pszName;
-
- DWORD dwId;
- DWORD dwSpecialId;
+ DWORD dwKLID; /* The physical KLID */
+ WORD wSpecialId; /* The special ID */
+ LPWSTR pszName; /* The layout text */
+ LPWSTR pszFile; /* The layout file */
+ LPWSTR pszImeFile; /* The IME file */
struct _LAYOUT_LIST_NODE *pPrev;
struct _LAYOUT_LIST_NODE *pNext;
diff --git a/dll/cpl/input/settings_page.c b/dll/cpl/input/settings_page.c
index 7785528dc4f..aeed2ad7e2c 100644
--- a/dll/cpl/input/settings_page.c
+++ b/dll/cpl/input/settings_page.c
@@ -11,7 +11,6 @@
#include "locale_list.h"
#include "input_list.h"
-
static HICON
CreateLayoutIcon(LPWSTR szLayout, BOOL bIsDefault)
{
@@ -112,23 +111,37 @@ CreateLayoutIcon(LPWSTR szLayout, BOOL bIsDefault)
static VOID
-SetControlsState(HWND hwndDlg, BOOL bIsEnabled)
+SetControlsState(HWND hwndDlg)
{
- EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE_BUTTON), bIsEnabled);
- EnableWindow(GetDlgItem(hwndDlg, IDC_PROP_BUTTON), bIsEnabled);
- EnableWindow(GetDlgItem(hwndDlg, IDC_SET_DEFAULT), bIsEnabled);
-}
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
+ INT iSelected = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
+ INT nCount = ListView_GetItemCount(hwndList);
+ BOOL bCanRemove = (iSelected != -1) && (nCount >= 2);
+ BOOL bCanDefault = (iSelected != -1) && (nCount >= 2);
+ BOOL bCanProp = (iSelected != -1);
+
+ LV_ITEM item = { LVIF_PARAM, iSelected };
+ if (ListView_GetItem(hwndList, &item))
+ {
+ INPUT_LIST_NODE *pInput = (INPUT_LIST_NODE*)item.lParam;
+
+ if (pInput && (pInput->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT))
+ {
+ bCanDefault = FALSE;
+ }
+ }
+ EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE_BUTTON), bCanRemove);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PROP_BUTTON), bCanProp);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SET_DEFAULT), bCanDefault);
+}
static VOID
AddToInputListView(HWND hwndList, INPUT_LIST_NODE *pInputNode)
{
- INT ItemIndex = -1;
- INT ImageIndex = -1;
+ INT ItemIndex, ImageIndex = -1;
LV_ITEM item;
- HIMAGELIST hImageList;
-
- hImageList = ListView_GetImageList(hwndList, LVSIL_SMALL);
+ HIMAGELIST hImageList = ListView_GetImageList(hwndList, LVSIL_SMALL);
if (hImageList != NULL)
{
@@ -136,7 +149,6 @@ AddToInputListView(HWND hwndList, INPUT_LIST_NODE *pInputNode)
hLayoutIcon = CreateLayoutIcon(pInputNode->pszIndicator,
(pInputNode->wFlags &
INPUT_LIST_NODE_FLAG_DEFAULT));
-
if (hLayoutIcon != NULL)
{
ImageIndex = ImageList_AddIcon(hImageList, hLayoutIcon);
@@ -145,13 +157,11 @@ AddToInputListView(HWND hwndList, INPUT_LIST_NODE *pInputNode)
}
ZeroMemory(&item, sizeof(item));
-
item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
item.pszText = pInputNode->pLocale->pszName;
- item.iItem = ListView_GetItemCount(hwndList) + 1;
+ item.iItem = ListView_GetItemCount(hwndList);
item.lParam = (LPARAM)pInputNode;
item.iImage = ImageIndex;
-
ItemIndex = ListView_InsertItem(hwndList, &item);
ListView_SetItemText(hwndList, ItemIndex, 1, pInputNode->pLayout->pszName);
@@ -161,52 +171,55 @@ AddToInputListView(HWND hwndList, INPUT_LIST_NODE *pInputNode)
static VOID
UpdateInputListView(HWND hwndList)
{
- INPUT_LIST_NODE *pCurrentInputNode;
- HIMAGELIST hImageList;
+ INPUT_LIST_NODE *pNode;
+ HIMAGELIST hImageList = ListView_GetImageList(hwndList, LVSIL_SMALL);
+ INT iSelected = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
- hImageList = ListView_GetImageList(hwndList, LVSIL_SMALL);
- if (hImageList != NULL)
+ if (hImageList)
{
ImageList_RemoveAll(hImageList);
}
ListView_DeleteAllItems(hwndList);
- for (pCurrentInputNode = InputList_GetFirst();
- pCurrentInputNode != NULL;
- pCurrentInputNode = pCurrentInputNode->pNext)
+ for (pNode = InputList_GetFirst(); pNode != NULL; pNode = pNode->pNext)
{
- if (!(pCurrentInputNode->wFlags & INPUT_LIST_NODE_FLAG_DELETED))
- {
- AddToInputListView(hwndList, pCurrentInputNode);
- }
+ if (pNode->wFlags & INPUT_LIST_NODE_FLAG_DELETED)
+ continue;
+
+ AddToInputListView(hwndList, pNode);
+ }
+
+ if (iSelected != -1)
+ {
+ INT nCount = ListView_GetItemCount(hwndList);
+ LV_ITEM item = { LVIF_STATE };
+ item.state = item.stateMask = LVIS_SELECTED;
+ item.iItem = ((nCount == iSelected) ? nCount - 1 : iSelected);
+ ListView_SetItem(hwndList, &item);
}
+
+ InvalidateRect(hwndList, NULL, TRUE);
}
static VOID
OnInitSettingsPage(HWND hwndDlg)
{
- HWND hwndInputList;
+ HWND hwndInputList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
LayoutList_Create();
LocaleList_Create();
InputList_Create();
- hwndInputList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
-
if (hwndInputList != NULL)
{
WCHAR szBuffer[MAX_STR_LEN];
HIMAGELIST hLayoutImageList;
- LV_COLUMN column;
+ LV_COLUMN column = { LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM };
ListView_SetExtendedListViewStyle(hwndInputList, LVS_EX_FULLROWSELECT);
- ZeroMemory(&column, sizeof(column));
-
- column.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
-
LoadStringW(hApplet, IDS_LANGUAGE, szBuffer, ARRAYSIZE(szBuffer));
column.fmt = LVCFMT_LEFT;
column.iSubItem = 0;
@@ -233,7 +246,7 @@ OnInitSettingsPage(HWND hwndDlg)
UpdateInputListView(hwndInputList);
}
- SetControlsState(hwndDlg, FALSE);
+ SetControlsState(hwndDlg);
}
@@ -259,6 +272,7 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
AddDialogProc) == IDOK)
{
UpdateInputListView(GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST));
+ SetControlsState(hwndDlg);
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
}
}
@@ -266,21 +280,17 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
case IDC_REMOVE_BUTTON:
{
- HWND hwndList;
-
- hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
-
- if (hwndList != NULL)
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
+ if (hwndList)
{
- LVITEM item = { 0 };
-
- item.mask = LVIF_PARAM;
+ LVITEM item = { LVIF_PARAM };
item.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
- if (ListView_GetItem(hwndList, &item) != FALSE)
+ if (ListView_GetItem(hwndList, &item))
{
InputList_Remove((INPUT_LIST_NODE*) item.lParam);
UpdateInputListView(hwndList);
+ SetControlsState(hwndDlg);
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
}
}
@@ -289,18 +299,13 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
case IDC_PROP_BUTTON:
{
- HWND hwndList;
-
- hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
-
- if (hwndList != NULL)
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
+ if (hwndList)
{
- LVITEM item = { 0 };
-
- item.mask = LVIF_PARAM;
+ LVITEM item = { LVIF_PARAM };
item.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
- if (ListView_GetItem(hwndList, &item) != FALSE)
+ if (ListView_GetItem(hwndList, &item))
{
if (DialogBoxParamW(hApplet,
MAKEINTRESOURCEW(IDD_INPUT_LANG_PROP),
@@ -309,6 +314,7 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
item.lParam) == IDOK)
{
UpdateInputListView(hwndList);
+ SetControlsState(hwndDlg);
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
}
}
@@ -318,21 +324,17 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
case IDC_SET_DEFAULT:
{
- HWND hwndList;
-
- hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
-
- if (hwndList != NULL)
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
+ if (hwndList)
{
- LVITEM item = { 0 };
-
- item.mask = LVIF_PARAM;
+ LVITEM item = { LVIF_PARAM };
item.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
- if (ListView_GetItem(hwndList, &item) != FALSE)
+ if (ListView_GetItem(hwndList, &item))
{
InputList_SetDefault((INPUT_LIST_NODE*) item.lParam);
UpdateInputListView(hwndList);
+ SetControlsState(hwndDlg);
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
}
}
@@ -350,73 +352,18 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
}
}
-BOOL EnableProcessPrivileges(LPCWSTR lpPrivilegeName, BOOL bEnable)
-{
- HANDLE hToken;
- LUID luid;
- TOKEN_PRIVILEGES tokenPrivileges;
- BOOL Ret;
-
- Ret = OpenProcessToken(GetCurrentProcess(),
- TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
- &hToken);
- if (!Ret)
- return Ret; // failure
-
- Ret = LookupPrivilegeValueW(NULL, lpPrivilegeName, &luid);
- if (Ret)
- {
- tokenPrivileges.PrivilegeCount = 1;
- tokenPrivileges.Privileges[0].Luid = luid;
- tokenPrivileges.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
-
- Ret = AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, 0, 0, 0);
- }
-
- CloseHandle(hToken);
- return Ret;
-}
-
static VOID
OnNotifySettingsPage(HWND hwndDlg, LPARAM lParam)
{
- LPNMHDR header;
-
- header = (LPNMHDR)lParam;
+ LPNMHDR header = (LPNMHDR)lParam;
switch (header->code)
{
- case NM_CLICK:
+ case LVN_ITEMCHANGED:
{
if (header->idFrom == IDC_KEYLAYOUT_LIST)
{
- INT iSelected = ListView_GetNextItem(header->hwndFrom, -1,
LVNI_SELECTED);
-
- if (iSelected != -1)
- {
- LVITEM item = { 0 };
-
- SetControlsState(hwndDlg, TRUE);
-
- item.mask = LVIF_PARAM;
- item.iItem = iSelected;
-
- if (ListView_GetItem(header->hwndFrom, &item) != FALSE)
- {
- INPUT_LIST_NODE *pInput;
-
- pInput = (INPUT_LIST_NODE*) item.lParam;
-
- if (pInput != NULL && pInput->wFlags &
INPUT_LIST_NODE_FLAG_DEFAULT)
- {
- EnableWindow(GetDlgItem(hwndDlg, IDC_SET_DEFAULT), FALSE);
- }
- }
- }
- else
- {
- SetControlsState(hwndDlg, FALSE);
- }
+ SetControlsState(hwndDlg);
}
}
break;
@@ -424,20 +371,7 @@ OnNotifySettingsPage(HWND hwndDlg, LPARAM lParam)
case PSN_APPLY:
{
/* Write Input Methods list to registry */
- if (InputList_Process())
- {
- /* Needs reboot */
- WCHAR szNeedsReboot[128], szLanguage[64];
- LoadStringW(hApplet, IDS_REBOOT_NOW, szNeedsReboot,
_countof(szNeedsReboot));
- LoadStringW(hApplet, IDS_LANGUAGE, szLanguage, _countof(szLanguage));
-
- if (MessageBoxW(hwndDlg, szNeedsReboot, szLanguage,
- MB_ICONINFORMATION | MB_YESNOCANCEL) == IDYES)
- {
- EnableProcessPrivileges(SE_SHUTDOWN_NAME, TRUE);
- ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0);
- }
- }
+ InputList_Process();
}
break;
}
diff --git a/win32ss/user/user32/windows/input.c b/win32ss/user/user32/windows/input.c
index 87df74fc06b..a9aac9e82a3 100644
--- a/win32ss/user/user32/windows/input.c
+++ b/win32ss/user/user32/windows/input.c
@@ -706,6 +706,13 @@ inline BOOL IsValidKLID(_In_ LPCWSTR pwszKLID)
return (pwszKLID != NULL) && (wcsspn(pwszKLID,
L"0123456789ABCDEFabcdef") == (KL_NAMELENGTH - 1));
}
+VOID GetSystemLibraryPath(LPWSTR pszPath, INT cchPath, LPCWSTR pszFileName)
+{
+ WCHAR szSysDir[MAX_PATH];
+ GetSystemDirectoryW(szSysDir, _countof(szSysDir));
+ StringCchPrintfW(pszPath, cchPath, L"%s\\%s", szSysDir, pszFileName);
+}
+
#define ENGLISH_US MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)
/*
@@ -722,15 +729,15 @@ IntLoadKeyboardLayout(
_In_ UINT Flags,
_In_ BOOL unknown5)
{
- DWORD dwhkl, dwType, dwSize;
+ DWORD dwKLID, dwHKL, dwType, dwSize;
UNICODE_STRING ustrKbdName;
UNICODE_STRING ustrKLID;
WCHAR wszRegKey[256] = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard
Layouts\\";
WCHAR wszLayoutId[10], wszNewKLID[KL_NAMELENGTH], szImeFileName[80];
- PWCHAR endptr;
HKL hNewKL;
HKEY hKey;
BOOL bIsIME;
+ WORD wLow, wHigh;
if (!IsValidKLID(pwszKLID))
{
@@ -738,13 +745,11 @@ IntLoadKeyboardLayout(
return UlongToHandle(MAKELONG(ENGLISH_US, ENGLISH_US));
}
- dwhkl = wcstoul(pwszKLID, &endptr, 16);
+ dwKLID = wcstoul(pwszKLID, NULL, 16);
+ bIsIME = IS_IME_HKL(UlongToHandle(dwKLID));
- bIsIME = IS_IME_HKL(UlongToHandle(dwhkl));
- if (!bIsIME) /* Not IME? */
- {
- dwhkl = LOWORD(dwhkl); /* LOWORD of dwhkl is language identifier */
- }
+ wLow = LOWORD(dwKLID);
+ wHigh = HIWORD(dwKLID);
if (Flags & KLF_SUBSTITUTE_OK)
{
@@ -753,10 +758,14 @@ IntLoadKeyboardLayout(
KEY_READ, &hKey) == ERROR_SUCCESS)
{
dwSize = sizeof(wszNewKLID);
- if (RegQueryValueExW(hKey, pwszKLID, NULL, &dwType, (LPBYTE)wszNewKLID,
&dwSize) == ERROR_SUCCESS)
+ if (RegQueryValueExW(hKey, pwszKLID, NULL, &dwType, (LPBYTE)wszNewKLID,
+ &dwSize) == ERROR_SUCCESS &&
+ dwType == REG_SZ)
{
/* Use new KLID value */
pwszKLID = wszNewKLID;
+ dwKLID = wcstoul(pwszKLID, NULL, 16);
+ wHigh = LOWORD(dwKLID);
}
/* Close the key now */
@@ -771,14 +780,11 @@ IntLoadKeyboardLayout(
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegKey, 0, KEY_READ, &hKey) ==
ERROR_SUCCESS)
{
dwSize = sizeof(wszLayoutId);
- if (RegQueryValueExW(hKey, L"Layout Id", NULL, &dwType,
(LPBYTE)wszLayoutId, &dwSize) == ERROR_SUCCESS)
+ if (RegQueryValueExW(hKey, L"Layout Id", NULL, &dwType,
(LPBYTE)wszLayoutId,
+ &dwSize) == ERROR_SUCCESS && dwType == REG_SZ)
{
/* If Layout Id is specified, use this value | f000 as HIWORD */
- /* FIXME: Microsoft Office expects this value to be something specific
- * for Japanese and Korean Windows with an IME the value is 0xe001
- */
- if (!bIsIME)
- dwhkl |= (0xf000 | wcstol(wszLayoutId, NULL, 16)) << 16;
+ wHigh = (0xF000 | wcstoul(wszLayoutId, NULL, 16));
}
if (bIsIME)
@@ -788,9 +794,18 @@ IntLoadKeyboardLayout(
if (RegQueryValueExW(hKey, L"IME File", NULL, &dwType,
(LPBYTE)szImeFileName,
&dwSize) != ERROR_SUCCESS)
{
- FIXME("Check IME file existence in system32\n");
bIsIME = FALSE;
- dwhkl = LOWORD(dwhkl);
+ wHigh = 0;
+ }
+ else
+ {
+ WCHAR szPath[MAX_PATH];
+ GetSystemLibraryPath(szPath, _countof(szPath), szImeFileName);
+ if (GetFileAttributesW(szPath) == INVALID_FILE_ATTRIBUTES) /* Does not
exist? */
+ {
+ bIsIME = FALSE;
+ wHigh = 0;
+ }
}
}
@@ -803,13 +818,14 @@ IntLoadKeyboardLayout(
return NULL;
}
- /* If Layout Id is not given HIWORD == LOWORD (for dwhkl) */
- if (!HIWORD(dwhkl))
- dwhkl |= dwhkl << 16;
+ if (wHigh == 0)
+ wHigh = wLow;
+
+ dwHKL = MAKELONG(wLow, wHigh);
ZeroMemory(&ustrKbdName, sizeof(ustrKbdName));
RtlInitUnicodeString(&ustrKLID, pwszKLID);
- hNewKL = NtUserLoadKeyboardLayoutEx(NULL, 0, &ustrKbdName, NULL, &ustrKLID,
dwhkl, Flags);
+ hNewKL = NtUserLoadKeyboardLayoutEx(NULL, 0, &ustrKbdName, NULL, &ustrKLID,
dwHKL, Flags);
CliImmInitializeHotKeys(SETIMEHOTKEY_ADD, hNewKL);
return hNewKL;
}