https://git.reactos.org/?p=reactos.git;a=commitdiff;h=596f04be6b1710bb255b346bc9bc7153c7d6eb0c

commit 596f04be6b1710bb255b346bc9bc7153c7d6eb0c
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Fri Sep 16 08:09:37 2022 +0900
Commit:     GitHub <[email protected]>
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 ([email protected])
+ *                  Katayama Hirofumi MZ ([email protected])
  */
 
 #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;
 }

Reply via email to