mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
[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
This commit is contained in:
parent
3f411c5da7
commit
596f04be6b
8 changed files with 548 additions and 422 deletions
|
@ -93,7 +93,7 @@ OnInitAddDialog(HWND hwndDlg)
|
||||||
iItemIndex = ComboBox_AddString(hwndLayoutCombo, pCurrentLayout->pszName);
|
iItemIndex = ComboBox_AddString(hwndLayoutCombo, pCurrentLayout->pszName);
|
||||||
ComboBox_SetItemData(hwndLayoutCombo, iItemIndex, pCurrentLayout);
|
ComboBox_SetItemData(hwndLayoutCombo, iItemIndex, pCurrentLayout);
|
||||||
|
|
||||||
if (pCurrentLayout->dwId == dwDefaultLayoutId)
|
if (pCurrentLayout->dwKLID == dwDefaultLayoutId)
|
||||||
{
|
{
|
||||||
ComboBox_SetCurSel(hwndLayoutCombo, iItemIndex);
|
ComboBox_SetCurSel(hwndLayoutCombo, iItemIndex);
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ OnCommandAddDialog(HWND hwndDlg, WPARAM wParam)
|
||||||
|
|
||||||
pCurrentLayout = (LAYOUT_LIST_NODE*)ComboBox_GetItemData(hwndLayoutCombo, iIndex);
|
pCurrentLayout = (LAYOUT_LIST_NODE*)ComboBox_GetItemData(hwndLayoutCombo, iIndex);
|
||||||
|
|
||||||
if (pCurrentLayout != NULL && pCurrentLayout->dwId == dwLayoutId)
|
if (pCurrentLayout != NULL && pCurrentLayout->dwKLID == dwLayoutId)
|
||||||
{
|
{
|
||||||
ComboBox_SetCurSel(hwndLayoutCombo, iIndex);
|
ComboBox_SetCurSel(hwndLayoutCombo, iIndex);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -81,4 +81,17 @@ DWORDfromString(const WCHAR *pszString)
|
||||||
return wcstoul(pszString, &pszEnd, 16);
|
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 */
|
#endif /* _INPUT_H */
|
||||||
|
|
|
@ -23,9 +23,7 @@ BOOL UpdateRegistryForFontSubstitutes(MUI_SUBFONT *pSubstitutes)
|
||||||
static const WCHAR pszKey[] =
|
static const WCHAR pszKey[] =
|
||||||
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes";
|
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes";
|
||||||
|
|
||||||
hKey = NULL;
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, pszKey, 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS)
|
||||||
RegOpenKeyExW(HKEY_LOCAL_MACHINE, pszKey, 0, KEY_ALL_ACCESS, &hKey);
|
|
||||||
if (hKey == NULL)
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* Overwrite only */
|
/* Overwrite only */
|
||||||
|
@ -37,10 +35,16 @@ BOOL UpdateRegistryForFontSubstitutes(MUI_SUBFONT *pSubstitutes)
|
||||||
}
|
}
|
||||||
|
|
||||||
RegCloseKey(hKey);
|
RegCloseKey(hKey);
|
||||||
|
|
||||||
return TRUE;
|
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
|
BOOL
|
||||||
InputList_SetFontSubstitutes(LCID dwLocaleId)
|
InputList_SetFontSubstitutes(LCID dwLocaleId)
|
||||||
{
|
{
|
||||||
|
@ -135,29 +139,28 @@ InputList_AppendNode(VOID)
|
||||||
INPUT_LIST_NODE *pCurrent;
|
INPUT_LIST_NODE *pCurrent;
|
||||||
INPUT_LIST_NODE *pNew;
|
INPUT_LIST_NODE *pNew;
|
||||||
|
|
||||||
pCurrent = _InputList;
|
|
||||||
|
|
||||||
pNew = (INPUT_LIST_NODE*)malloc(sizeof(INPUT_LIST_NODE));
|
pNew = (INPUT_LIST_NODE*)malloc(sizeof(INPUT_LIST_NODE));
|
||||||
if (pNew == NULL)
|
if (pNew == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
ZeroMemory(pNew, sizeof(INPUT_LIST_NODE));
|
ZeroMemory(pNew, sizeof(INPUT_LIST_NODE));
|
||||||
|
|
||||||
if (pCurrent == NULL)
|
if (_InputList == NULL) /* Empty? */
|
||||||
{
|
{
|
||||||
_InputList = pNew;
|
_InputList = pNew;
|
||||||
|
return pNew;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
while (pCurrent->pNext != NULL)
|
|
||||||
{
|
|
||||||
pCurrent = pCurrent->pNext;
|
|
||||||
}
|
|
||||||
|
|
||||||
pNew->pPrev = pCurrent;
|
/* Find last node */
|
||||||
pCurrent->pNext = pNew;
|
for (pCurrent = _InputList; pCurrent->pNext; pCurrent = pCurrent->pNext)
|
||||||
|
{
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add to the end */
|
||||||
|
pCurrent->pNext = pNew;
|
||||||
|
pNew->pPrev = pCurrent;
|
||||||
|
|
||||||
return pNew;
|
return pNew;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,20 +196,17 @@ VOID
|
||||||
InputList_Destroy(VOID)
|
InputList_Destroy(VOID)
|
||||||
{
|
{
|
||||||
INPUT_LIST_NODE *pCurrent;
|
INPUT_LIST_NODE *pCurrent;
|
||||||
|
INPUT_LIST_NODE *pNext;
|
||||||
|
|
||||||
if (_InputList == NULL)
|
if (_InputList == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pCurrent = _InputList;
|
for (pCurrent = _InputList; pCurrent; pCurrent = pNext)
|
||||||
|
|
||||||
while (pCurrent != NULL)
|
|
||||||
{
|
{
|
||||||
INPUT_LIST_NODE *pNext = pCurrent->pNext;
|
pNext = pCurrent->pNext;
|
||||||
|
|
||||||
free(pCurrent->pszIndicator);
|
free(pCurrent->pszIndicator);
|
||||||
free(pCurrent);
|
free(pCurrent);
|
||||||
|
|
||||||
pCurrent = pNext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_InputList = NULL;
|
_InputList = NULL;
|
||||||
|
@ -214,11 +214,12 @@ InputList_Destroy(VOID)
|
||||||
|
|
||||||
|
|
||||||
static BOOL
|
static BOOL
|
||||||
InputList_PrepareUserRegistry(VOID)
|
InputList_PrepareUserRegistry(PHKEY phPreloadKey, PHKEY phSubstKey)
|
||||||
{
|
{
|
||||||
BOOL bResult = FALSE;
|
BOOL bResult = FALSE;
|
||||||
HKEY hTempKey = NULL;
|
HKEY hKey;
|
||||||
HKEY hKey = NULL;
|
|
||||||
|
*phPreloadKey = *phSubstKey = NULL;
|
||||||
|
|
||||||
if (RegOpenKeyExW(HKEY_CURRENT_USER,
|
if (RegOpenKeyExW(HKEY_CURRENT_USER,
|
||||||
L"Keyboard Layout",
|
L"Keyboard Layout",
|
||||||
|
@ -232,101 +233,143 @@ InputList_PrepareUserRegistry(VOID)
|
||||||
RegCloseKey(hKey);
|
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)
|
if (hKey)
|
||||||
{
|
|
||||||
goto Cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
RegCloseKey(hTempKey);
|
|
||||||
|
|
||||||
if (RegCreateKeyW(hKey, L"Substitutes", &hTempKey) != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
goto Cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
RegCloseKey(hTempKey);
|
|
||||||
|
|
||||||
bResult = TRUE;
|
|
||||||
|
|
||||||
Cleanup:
|
|
||||||
if (hTempKey != NULL)
|
|
||||||
RegCloseKey(hTempKey);
|
|
||||||
if (hKey != NULL)
|
|
||||||
RegCloseKey(hKey);
|
RegCloseKey(hKey);
|
||||||
|
|
||||||
return bResult;
|
return bResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
StringCchPrintfW(szNumber, ARRAYSIZE(szNumber), L"%u", dwNumber);
|
||||||
|
|
||||||
|
cbValue = ARRAYSIZE(szValue) * sizeof(WCHAR);
|
||||||
|
if (RegQueryValueExW(hPreloadKey, szNumber, NULL, &dwType,
|
||||||
|
(LPBYTE)szValue, &cbValue) != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dwType != REG_SZ)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
szValue[ARRAYSIZE(szValue) - 1] = 0;
|
||||||
|
if (_wcsicmp(szKLID, szValue) == 0)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL
|
||||||
|
InputList_WriteSubst(HKEY hSubstKey, DWORD dwPhysicalKLID, DWORD dwLogicalKLID)
|
||||||
|
{
|
||||||
|
DWORD cbValue;
|
||||||
|
WCHAR szLogicalKLID[KL_NAMELENGTH], szPhysicalKLID[KL_NAMELENGTH];
|
||||||
|
|
||||||
|
StringCchPrintfW(szLogicalKLID, ARRAYSIZE(szLogicalKLID), L"%08x", dwLogicalKLID);
|
||||||
|
StringCchPrintfW(szPhysicalKLID, ARRAYSIZE(szPhysicalKLID), L"%08x", dwPhysicalKLID);
|
||||||
|
|
||||||
|
cbValue = (wcslen(szPhysicalKLID) + 1) * sizeof(WCHAR);
|
||||||
|
return RegSetValueExW(hSubstKey, szLogicalKLID, 0, REG_SZ, (LPBYTE)szPhysicalKLID,
|
||||||
|
cbValue) == 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)
|
||||||
|
{
|
||||||
|
if (!InputList_FindPreloadKLID(hPreloadKey, dwLogicalKLID)) /* Not found? */
|
||||||
|
{
|
||||||
|
if (bSubstNeeded)
|
||||||
|
{
|
||||||
|
/* Write now */
|
||||||
|
InputList_WriteSubst(hSubstKey, dwPhysicalKLID, dwLogicalKLID);
|
||||||
|
}
|
||||||
|
return dwLogicalKLID;
|
||||||
|
}
|
||||||
|
|
||||||
|
bSubstNeeded = TRUE;
|
||||||
|
|
||||||
|
/* Calculate the next logical KLID */
|
||||||
|
if (!IS_SUBST_KLID(dwLogicalKLID))
|
||||||
|
{
|
||||||
|
dwLogicalKLID |= SUBST_MASK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WORD wLow = LOWORD(dwLogicalKLID);
|
||||||
|
WORD wHigh = HIWORD(dwLogicalKLID);
|
||||||
|
dwLogicalKLID = MAKELONG(wLow, wHigh + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static VOID
|
static VOID
|
||||||
InputList_AddInputMethodToUserRegistry(DWORD dwIndex, INPUT_LIST_NODE *pNode)
|
InputList_AddInputMethodToUserRegistry(
|
||||||
|
HKEY hPreloadKey,
|
||||||
|
HKEY hSubstKey,
|
||||||
|
DWORD dwNumber,
|
||||||
|
INPUT_LIST_NODE *pNode)
|
||||||
{
|
{
|
||||||
WCHAR szMethodIndex[MAX_PATH];
|
WCHAR szNumber[32], szLogicalKLID[KL_NAMELENGTH];
|
||||||
WCHAR szPreload[MAX_PATH];
|
DWORD dwPhysicalKLID, dwLogicalKLID, cbValue;
|
||||||
BOOL bIsImeMethod = FALSE;
|
HKL hKL = pNode->hkl;
|
||||||
HKEY hKey;
|
|
||||||
|
|
||||||
StringCchPrintfW(szMethodIndex, ARRAYSIZE(szMethodIndex), L"%lu", dwIndex);
|
if (IS_IME_HKL(hKL)) /* IME? */
|
||||||
|
|
||||||
/* Check is IME method */
|
|
||||||
if ((HIWORD(pNode->pLayout->dwId) & 0xF000) == 0xE000)
|
|
||||||
{
|
{
|
||||||
StringCchPrintfW(szPreload, ARRAYSIZE(szPreload), L"%08X", pNode->pLayout->dwId);
|
/* Do not substitute the IME KLID */
|
||||||
bIsImeMethod = TRUE;
|
dwLogicalKLID = dwPhysicalKLID = HandleToUlong(hKL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
StringCchPrintfW(szPreload, ARRAYSIZE(szPreload), L"%08X", pNode->pLocale->dwId);
|
/* Substitute the KLID if necessary */
|
||||||
|
dwPhysicalKLID = pNode->pLayout->dwKLID;
|
||||||
|
dwLogicalKLID = pNode->pLocale->dwId;
|
||||||
|
dwLogicalKLID = InputList_DoSubst(hPreloadKey, hSubstKey, dwPhysicalKLID, dwLogicalKLID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RegOpenKeyExW(HKEY_CURRENT_USER,
|
/* Write the Preload value (number |--> logical KLID) */
|
||||||
L"Keyboard Layout\\Preload",
|
StringCchPrintfW(szNumber, ARRAYSIZE(szNumber), L"%lu", dwNumber);
|
||||||
0,
|
StringCchPrintfW(szLogicalKLID, ARRAYSIZE(szLogicalKLID), L"%08x", dwLogicalKLID);
|
||||||
KEY_SET_VALUE,
|
cbValue = (wcslen(szLogicalKLID) + 1) * sizeof(WCHAR);
|
||||||
&hKey) == ERROR_SUCCESS)
|
RegSetValueExW(hPreloadKey,
|
||||||
{
|
szNumber,
|
||||||
RegSetValueExW(hKey,
|
0,
|
||||||
szMethodIndex,
|
REG_SZ,
|
||||||
0,
|
(LPBYTE)szLogicalKLID,
|
||||||
REG_SZ,
|
cbValue);
|
||||||
(LPBYTE)szPreload,
|
|
||||||
(wcslen(szPreload) + 1) * sizeof(WCHAR));
|
|
||||||
|
|
||||||
RegCloseKey(hKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
WCHAR szSubstitutes[MAX_PATH];
|
|
||||||
|
|
||||||
StringCchPrintfW(szSubstitutes, ARRAYSIZE(szSubstitutes), L"%08X", pNode->pLayout->dwId);
|
|
||||||
|
|
||||||
RegSetValueExW(hKey,
|
|
||||||
szPreload,
|
|
||||||
0,
|
|
||||||
REG_SZ,
|
|
||||||
(LPBYTE)szSubstitutes,
|
|
||||||
(wcslen(szSubstitutes) + 1) * sizeof(WCHAR));
|
|
||||||
|
|
||||||
RegCloseKey(hKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((pNode->wFlags & INPUT_LIST_NODE_FLAG_ADDED) ||
|
if ((pNode->wFlags & INPUT_LIST_NODE_FLAG_ADDED) ||
|
||||||
(pNode->wFlags & INPUT_LIST_NODE_FLAG_EDITED))
|
(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)
|
InputList_Process(VOID)
|
||||||
{
|
{
|
||||||
INPUT_LIST_NODE *pCurrent;
|
INPUT_LIST_NODE *pCurrent;
|
||||||
DWORD dwIndex;
|
DWORD dwNumber;
|
||||||
BOOL bRet = FALSE;
|
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)
|
for (pCurrent = _InputList; pCurrent != NULL; pCurrent = pCurrent->pNext)
|
||||||
{
|
{
|
||||||
if ((pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DELETED) ||
|
if ((pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DELETED) ||
|
||||||
(pCurrent->wFlags & INPUT_LIST_NODE_FLAG_EDITED))
|
(pCurrent->wFlags & INPUT_LIST_NODE_FLAG_EDITED))
|
||||||
{
|
{
|
||||||
|
/* Only unload the DELETED and EDITED entries */
|
||||||
if (UnloadKeyboardLayout(pCurrent->hkl))
|
if (UnloadKeyboardLayout(pCurrent->hkl))
|
||||||
{
|
{
|
||||||
/* Only unload the edited input method, but does not delete it from the list */
|
/* But the EDITED entries are used later */
|
||||||
if (!(pCurrent->wFlags & INPUT_LIST_NODE_FLAG_EDITED))
|
if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DELETED)
|
||||||
{
|
{
|
||||||
InputList_RemoveNode(pCurrent);
|
InputList_RemoveNode(pCurrent);
|
||||||
}
|
}
|
||||||
|
@ -358,27 +412,44 @@ InputList_Process(VOID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InputList_PrepareUserRegistry();
|
/* Add the DEFAULT entry and set font substitutes */
|
||||||
|
|
||||||
/* Find default input method */
|
|
||||||
for (pCurrent = _InputList; pCurrent != NULL; pCurrent = pCurrent->pNext)
|
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)
|
if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT)
|
||||||
{
|
{
|
||||||
bRet = InputList_SetFontSubstitutes(pCurrent->pLocale->dwId);
|
bRet = InputList_SetFontSubstitutes(pCurrent->pLocale->dwId);
|
||||||
InputList_AddInputMethodToUserRegistry(1, pCurrent);
|
InputList_AddInputMethodToUserRegistry(hPreloadKey, hSubstKey, 1, pCurrent);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SystemParametersInfoW(SPI_SETDEFAULTINPUTLANG,
|
/* Add entries except DEFAULT to registry */
|
||||||
0,
|
dwNumber = 2;
|
||||||
(LPVOID)((LPDWORD)&pCurrent->hkl),
|
for (pCurrent = _InputList; pCurrent != NULL; pCurrent = pCurrent->pNext)
|
||||||
0))
|
|
||||||
{
|
{
|
||||||
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,
|
BroadcastSystemMessageW(BSF_POSTMESSAGE,
|
||||||
&dwRecipients,
|
&dwRecipients,
|
||||||
|
@ -387,19 +458,18 @@ InputList_Process(VOID)
|
||||||
(LPARAM)pCurrent->hkl);
|
(LPARAM)pCurrent->hkl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add methods to registry */
|
/* Retry to delete (in case of failure to delete the default keyboard) */
|
||||||
dwIndex = 2;
|
|
||||||
|
|
||||||
for (pCurrent = _InputList; pCurrent != NULL; pCurrent = pCurrent->pNext)
|
for (pCurrent = _InputList; pCurrent != NULL; pCurrent = pCurrent->pNext)
|
||||||
{
|
{
|
||||||
if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT)
|
if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DELETED)
|
||||||
continue;
|
{
|
||||||
|
UnloadKeyboardLayout(pCurrent->hkl);
|
||||||
InputList_AddInputMethodToUserRegistry(dwIndex, pCurrent);
|
InputList_RemoveNode(pCurrent);
|
||||||
|
}
|
||||||
dwIndex++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RegCloseKey(hPreloadKey);
|
||||||
|
RegCloseKey(hSubstKey);
|
||||||
return bRet;
|
return bRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,7 +478,7 @@ BOOL
|
||||||
InputList_Add(LOCALE_LIST_NODE *pLocale, LAYOUT_LIST_NODE *pLayout)
|
InputList_Add(LOCALE_LIST_NODE *pLocale, LAYOUT_LIST_NODE *pLayout)
|
||||||
{
|
{
|
||||||
WCHAR szIndicator[MAX_STR_LEN];
|
WCHAR szIndicator[MAX_STR_LEN];
|
||||||
INPUT_LIST_NODE *pInput;
|
INPUT_LIST_NODE *pInput = NULL;
|
||||||
|
|
||||||
if (pLocale == NULL || pLayout == 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)
|
for (pInput = _InputList; pInput != NULL; pInput = pInput->pNext)
|
||||||
{
|
{
|
||||||
|
if (pInput->wFlags & INPUT_LIST_NODE_FLAG_DELETED)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (pInput->pLocale == pLocale && pInput->pLayout == pLayout)
|
if (pInput->pLocale == pLocale && pInput->pLayout == pLayout)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE; /* Already exists */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pInput = InputList_AppendNode();
|
pInput = InputList_AppendNode();
|
||||||
|
|
||||||
pInput->wFlags = INPUT_LIST_NODE_FLAG_ADDED;
|
pInput->wFlags = INPUT_LIST_NODE_FLAG_ADDED;
|
||||||
|
|
||||||
pInput->pLocale = pLocale;
|
pInput->pLocale = pLocale;
|
||||||
pInput->pLayout = pLayout;
|
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.
|
* It marks the input method for deletion, but does not delete it directly.
|
||||||
|
@ -492,22 +586,19 @@ InputList_Remove(INPUT_LIST_NODE *pNode)
|
||||||
}
|
}
|
||||||
else
|
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->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT)
|
||||||
{
|
{
|
||||||
if (pNode->pNext != NULL)
|
INPUT_LIST_NODE *pCurrent = InputList_FindNextDefault(pNode);
|
||||||
{
|
if (pCurrent)
|
||||||
pNode->pNext->wFlags |= INPUT_LIST_NODE_FLAG_DEFAULT;
|
pCurrent->wFlags |= INPUT_LIST_NODE_FLAG_DEFAULT;
|
||||||
}
|
|
||||||
else if (pNode->pPrev != NULL)
|
pNode->wFlags &= ~INPUT_LIST_NODE_FLAG_DEFAULT;
|
||||||
{
|
|
||||||
pNode->pPrev->wFlags |= INPUT_LIST_NODE_FLAG_DEFAULT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bRemoveNode != FALSE)
|
if (bRemoveNode)
|
||||||
{
|
{
|
||||||
InputList_RemoveNode(pNode);
|
InputList_RemoveNode(pNode);
|
||||||
}
|
}
|
||||||
|
@ -517,67 +608,58 @@ InputList_Remove(INPUT_LIST_NODE *pNode)
|
||||||
VOID
|
VOID
|
||||||
InputList_Create(VOID)
|
InputList_Create(VOID)
|
||||||
{
|
{
|
||||||
INT iLayoutCount;
|
INT iLayoutCount, iIndex;
|
||||||
HKL *pLayoutList;
|
WCHAR szIndicator[MAX_STR_LEN];
|
||||||
|
INPUT_LIST_NODE *pInput;
|
||||||
|
HKL *pLayoutList, hklDefault;
|
||||||
|
|
||||||
|
SystemParametersInfoW(SPI_GETDEFAULTINPUTLANG, 0, &hklDefault, 0);
|
||||||
|
|
||||||
iLayoutCount = GetKeyboardLayoutList(0, NULL);
|
iLayoutCount = GetKeyboardLayoutList(0, NULL);
|
||||||
pLayoutList = (HKL*) malloc(iLayoutCount * sizeof(HKL));
|
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++)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(pLayoutList);
|
/* 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)
|
||||||
|
{
|
||||||
|
szIndicator[len - 1] = 0;
|
||||||
|
pInput->pszIndicator = _wcsdup(szIndicator);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(pLayoutList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,30 @@
|
||||||
#include "locale_list.h"
|
#include "locale_list.h"
|
||||||
#include "layout_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
|
#define INPUT_LIST_NODE_FLAG_EDITED 0x0001
|
||||||
#define INPUT_LIST_NODE_FLAG_ADDED 0x0002
|
|
||||||
#define INPUT_LIST_NODE_FLAG_DELETED 0x0004
|
|
||||||
#define INPUT_LIST_NODE_FLAG_DEFAULT 0x0008
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
typedef struct _INPUT_LIST_NODE
|
||||||
{
|
{
|
||||||
|
@ -20,7 +38,7 @@ typedef struct _INPUT_LIST_NODE
|
||||||
|
|
||||||
HKL hkl; /* Only for loaded input methods */
|
HKL hkl; /* Only for loaded input methods */
|
||||||
|
|
||||||
WCHAR *pszIndicator;
|
LPWSTR pszIndicator;
|
||||||
|
|
||||||
struct _INPUT_LIST_NODE *pPrev;
|
struct _INPUT_LIST_NODE *pPrev;
|
||||||
struct _INPUT_LIST_NODE *pNext;
|
struct _INPUT_LIST_NODE *pNext;
|
||||||
|
|
|
@ -3,16 +3,16 @@
|
||||||
* FILE: dll/cpl/input/layout_list.c
|
* FILE: dll/cpl/input/layout_list.c
|
||||||
* PURPOSE: input.dll
|
* PURPOSE: input.dll
|
||||||
* PROGRAMMER: Dmitry Chapyshev (dmitry@reactos.org)
|
* PROGRAMMER: Dmitry Chapyshev (dmitry@reactos.org)
|
||||||
|
* Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "layout_list.h"
|
#include "layout_list.h"
|
||||||
|
|
||||||
|
|
||||||
static LAYOUT_LIST_NODE *_LayoutList = NULL;
|
static LAYOUT_LIST_NODE *_LayoutList = NULL;
|
||||||
|
|
||||||
|
|
||||||
static LAYOUT_LIST_NODE*
|
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 *pCurrent;
|
||||||
LAYOUT_LIST_NODE *pNew;
|
LAYOUT_LIST_NODE *pNew;
|
||||||
|
@ -28,16 +28,22 @@ LayoutList_AppendNode(DWORD dwId, DWORD dwSpecialId, const WCHAR *pszName)
|
||||||
|
|
||||||
ZeroMemory(pNew, sizeof(LAYOUT_LIST_NODE));
|
ZeroMemory(pNew, sizeof(LAYOUT_LIST_NODE));
|
||||||
|
|
||||||
|
pNew->dwKLID = dwKLID;
|
||||||
|
pNew->wSpecialId = wSpecialId;
|
||||||
|
|
||||||
pNew->pszName = _wcsdup(pszName);
|
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);
|
free(pNew);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pNew->dwId = dwId;
|
|
||||||
pNew->dwSpecialId = dwSpecialId;
|
|
||||||
|
|
||||||
if (pCurrent == NULL)
|
if (pCurrent == NULL)
|
||||||
{
|
{
|
||||||
_LayoutList = pNew;
|
_LayoutList = pNew;
|
||||||
|
@ -61,90 +67,136 @@ VOID
|
||||||
LayoutList_Destroy(VOID)
|
LayoutList_Destroy(VOID)
|
||||||
{
|
{
|
||||||
LAYOUT_LIST_NODE *pCurrent;
|
LAYOUT_LIST_NODE *pCurrent;
|
||||||
|
LAYOUT_LIST_NODE *pNext;
|
||||||
|
|
||||||
if (_LayoutList == NULL)
|
if (_LayoutList == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pCurrent = _LayoutList;
|
for (pCurrent = _LayoutList; pCurrent; pCurrent = pNext)
|
||||||
|
|
||||||
while (pCurrent != NULL)
|
|
||||||
{
|
{
|
||||||
LAYOUT_LIST_NODE *pNext = pCurrent->pNext;
|
pNext = pCurrent->pNext;
|
||||||
|
|
||||||
free(pCurrent->pszName);
|
free(pCurrent->pszName);
|
||||||
|
free(pCurrent->pszFile);
|
||||||
|
free(pCurrent->pszImeFile);
|
||||||
free(pCurrent);
|
free(pCurrent);
|
||||||
|
|
||||||
pCurrent = pNext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_LayoutList = NULL;
|
_LayoutList = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL
|
typedef HRESULT (WINAPI *FN_SHLoadRegUIStringW)(HKEY, LPCWSTR, LPWSTR, DWORD);
|
||||||
LayoutList_ReadLayout(HKEY hLayoutKey, LPCWSTR szLayoutId, LPCWSTR szSystemDirectory)
|
|
||||||
{
|
|
||||||
WCHAR szBuffer[MAX_PATH], szFilePath[MAX_PATH], szDllPath[MAX_PATH];
|
|
||||||
INT iIndex, iLength = 0;
|
|
||||||
DWORD dwSize, dwSpecialId, dwLayoutId = DWORDfromString(szLayoutId);
|
|
||||||
HINSTANCE hDllInst;
|
|
||||||
|
|
||||||
dwSize = sizeof(szBuffer);
|
/* FIXME: Use shlwapi!SHLoadRegUIStringW instead when it is fully implemented */
|
||||||
|
HRESULT FakeSHLoadRegUIStringW(HKEY hkey, LPCWSTR value, LPWSTR buf, DWORD size)
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
PWCHAR pBuffer, pIndex;
|
||||||
|
WCHAR szDllPath[MAX_PATH];
|
||||||
|
DWORD dwSize;
|
||||||
|
HINSTANCE hDllInst;
|
||||||
|
INT iIndex, iLength;
|
||||||
|
|
||||||
|
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,
|
if (RegQueryValueExW(hLayoutKey, L"Layout File", NULL, NULL,
|
||||||
(LPBYTE)szBuffer, &dwSize) != ERROR_SUCCESS)
|
(LPBYTE)szFile, &dwSize) != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
return FALSE; /* No "Layout File" value */
|
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 */
|
/* 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)
|
if (GetFileAttributesW(szFilePath) == INVALID_FILE_ATTRIBUTES)
|
||||||
return FALSE; /* No layout file found */
|
return FALSE; /* No layout file found */
|
||||||
|
|
||||||
/* Get the special ID */
|
/* Get the special ID */
|
||||||
dwSpecialId = 0;
|
|
||||||
dwSize = sizeof(szBuffer);
|
dwSize = sizeof(szBuffer);
|
||||||
if (RegQueryValueExW(hLayoutKey, L"Layout Id", NULL, NULL,
|
if (RegQueryValueExW(hLayoutKey, L"Layout Id", NULL, NULL,
|
||||||
(LPBYTE)szBuffer, &dwSize) == ERROR_SUCCESS)
|
(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 */
|
/* If there is a valid "Layout Display Name", then use it as the entry name */
|
||||||
dwSize = sizeof(szBuffer);
|
if (FakeSHLoadRegUIStringW(hLayoutKey, L"Layout Display Name",
|
||||||
if (RegQueryValueExW(hLayoutKey, L"Layout Display Name", NULL, NULL,
|
szBuffer, ARRAYSIZE(szBuffer)) == S_OK)
|
||||||
(LPBYTE)szBuffer, &dwSize) == ERROR_SUCCESS && szBuffer[0] == L'@')
|
|
||||||
{
|
{
|
||||||
/* FIXME: Use shlwapi!SHLoadRegUIStringW instead if it had fully implemented */
|
LayoutList_AppendNode(dwKLID, wSpecialId, szFile, szBuffer, pszImeFile);
|
||||||
|
return TRUE;
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise, use "Layout Text" value as the entry name */
|
/* 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,
|
if (RegQueryValueExW(hLayoutKey, L"Layout Text", NULL, NULL,
|
||||||
(LPBYTE)szBuffer, &dwSize) == ERROR_SUCCESS)
|
(LPBYTE)szBuffer, &dwSize) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
LayoutList_AppendNode(dwLayoutId, dwSpecialId, szBuffer);
|
LayoutList_AppendNode(dwKLID, wSpecialId, szFile, szBuffer, pszImeFile);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +214,7 @@ LayoutList_ReadLayout(HKEY hLayoutKey, LPCWSTR szLayoutId, LPCWSTR szSystemDirec
|
||||||
VOID
|
VOID
|
||||||
LayoutList_Create(VOID)
|
LayoutList_Create(VOID)
|
||||||
{
|
{
|
||||||
WCHAR szSystemDirectory[MAX_PATH], szLayoutId[MAX_PATH];
|
WCHAR szSystemDirectory[MAX_PATH], szKLID[KL_NAMELENGTH];
|
||||||
DWORD dwSize, dwIndex;
|
DWORD dwSize, dwIndex;
|
||||||
HKEY hKey, hLayoutKey;
|
HKEY hKey, hLayoutKey;
|
||||||
|
|
||||||
|
@ -170,23 +222,23 @@ LayoutList_Create(VOID)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts",
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (dwIndex = 0; ; ++dwIndex)
|
for (dwIndex = 0; ; ++dwIndex)
|
||||||
{
|
{
|
||||||
dwSize = ARRAYSIZE(szLayoutId);
|
dwSize = ARRAYSIZE(szKLID);
|
||||||
if (RegEnumKeyExW(hKey, dwIndex, szLayoutId, &dwSize, NULL, NULL,
|
if (RegEnumKeyExW(hKey, dwIndex, szKLID, &dwSize, NULL, NULL,
|
||||||
NULL, NULL) != ERROR_SUCCESS)
|
NULL, NULL) != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
break;
|
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);
|
RegCloseKey(hLayoutKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,13 +252,23 @@ LayoutList_GetByHkl(HKL hkl)
|
||||||
{
|
{
|
||||||
LAYOUT_LIST_NODE *pCurrent;
|
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)
|
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;
|
return pCurrent;
|
||||||
}
|
}
|
||||||
|
@ -216,7 +278,7 @@ LayoutList_GetByHkl(HKL hkl)
|
||||||
{
|
{
|
||||||
for (pCurrent = _LayoutList; pCurrent != NULL; pCurrent = pCurrent->pNext)
|
for (pCurrent = _LayoutList; pCurrent != NULL; pCurrent = pCurrent->pNext)
|
||||||
{
|
{
|
||||||
if (HIWORD(hkl) == LOWORD(pCurrent->dwId))
|
if (HIWORD(hkl) == LOWORD(pCurrent->dwKLID))
|
||||||
{
|
{
|
||||||
return pCurrent;
|
return pCurrent;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,11 @@
|
||||||
|
|
||||||
typedef struct _LAYOUT_LIST_NODE
|
typedef struct _LAYOUT_LIST_NODE
|
||||||
{
|
{
|
||||||
WCHAR *pszName;
|
DWORD dwKLID; /* The physical KLID */
|
||||||
|
WORD wSpecialId; /* The special ID */
|
||||||
DWORD dwId;
|
LPWSTR pszName; /* The layout text */
|
||||||
DWORD dwSpecialId;
|
LPWSTR pszFile; /* The layout file */
|
||||||
|
LPWSTR pszImeFile; /* The IME file */
|
||||||
|
|
||||||
struct _LAYOUT_LIST_NODE *pPrev;
|
struct _LAYOUT_LIST_NODE *pPrev;
|
||||||
struct _LAYOUT_LIST_NODE *pNext;
|
struct _LAYOUT_LIST_NODE *pNext;
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#include "locale_list.h"
|
#include "locale_list.h"
|
||||||
#include "input_list.h"
|
#include "input_list.h"
|
||||||
|
|
||||||
|
|
||||||
static HICON
|
static HICON
|
||||||
CreateLayoutIcon(LPWSTR szLayout, BOOL bIsDefault)
|
CreateLayoutIcon(LPWSTR szLayout, BOOL bIsDefault)
|
||||||
{
|
{
|
||||||
|
@ -112,23 +111,37 @@ CreateLayoutIcon(LPWSTR szLayout, BOOL bIsDefault)
|
||||||
|
|
||||||
|
|
||||||
static VOID
|
static VOID
|
||||||
SetControlsState(HWND hwndDlg, BOOL bIsEnabled)
|
SetControlsState(HWND hwndDlg)
|
||||||
{
|
{
|
||||||
EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE_BUTTON), bIsEnabled);
|
HWND hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
|
||||||
EnableWindow(GetDlgItem(hwndDlg, IDC_PROP_BUTTON), bIsEnabled);
|
INT iSelected = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
|
||||||
EnableWindow(GetDlgItem(hwndDlg, IDC_SET_DEFAULT), bIsEnabled);
|
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
|
static VOID
|
||||||
AddToInputListView(HWND hwndList, INPUT_LIST_NODE *pInputNode)
|
AddToInputListView(HWND hwndList, INPUT_LIST_NODE *pInputNode)
|
||||||
{
|
{
|
||||||
INT ItemIndex = -1;
|
INT ItemIndex, ImageIndex = -1;
|
||||||
INT ImageIndex = -1;
|
|
||||||
LV_ITEM item;
|
LV_ITEM item;
|
||||||
HIMAGELIST hImageList;
|
HIMAGELIST hImageList = ListView_GetImageList(hwndList, LVSIL_SMALL);
|
||||||
|
|
||||||
hImageList = ListView_GetImageList(hwndList, LVSIL_SMALL);
|
|
||||||
|
|
||||||
if (hImageList != NULL)
|
if (hImageList != NULL)
|
||||||
{
|
{
|
||||||
|
@ -136,7 +149,6 @@ AddToInputListView(HWND hwndList, INPUT_LIST_NODE *pInputNode)
|
||||||
|
|
||||||
hLayoutIcon = CreateLayoutIcon(pInputNode->pszIndicator,
|
hLayoutIcon = CreateLayoutIcon(pInputNode->pszIndicator,
|
||||||
(pInputNode->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT));
|
(pInputNode->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT));
|
||||||
|
|
||||||
if (hLayoutIcon != NULL)
|
if (hLayoutIcon != NULL)
|
||||||
{
|
{
|
||||||
ImageIndex = ImageList_AddIcon(hImageList, hLayoutIcon);
|
ImageIndex = ImageList_AddIcon(hImageList, hLayoutIcon);
|
||||||
|
@ -145,13 +157,11 @@ AddToInputListView(HWND hwndList, INPUT_LIST_NODE *pInputNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
ZeroMemory(&item, sizeof(item));
|
ZeroMemory(&item, sizeof(item));
|
||||||
|
|
||||||
item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
|
item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
|
||||||
item.pszText = pInputNode->pLocale->pszName;
|
item.pszText = pInputNode->pLocale->pszName;
|
||||||
item.iItem = ListView_GetItemCount(hwndList) + 1;
|
item.iItem = ListView_GetItemCount(hwndList);
|
||||||
item.lParam = (LPARAM)pInputNode;
|
item.lParam = (LPARAM)pInputNode;
|
||||||
item.iImage = ImageIndex;
|
item.iImage = ImageIndex;
|
||||||
|
|
||||||
ItemIndex = ListView_InsertItem(hwndList, &item);
|
ItemIndex = ListView_InsertItem(hwndList, &item);
|
||||||
|
|
||||||
ListView_SetItemText(hwndList, ItemIndex, 1, pInputNode->pLayout->pszName);
|
ListView_SetItemText(hwndList, ItemIndex, 1, pInputNode->pLayout->pszName);
|
||||||
|
@ -161,52 +171,55 @@ AddToInputListView(HWND hwndList, INPUT_LIST_NODE *pInputNode)
|
||||||
static VOID
|
static VOID
|
||||||
UpdateInputListView(HWND hwndList)
|
UpdateInputListView(HWND hwndList)
|
||||||
{
|
{
|
||||||
INPUT_LIST_NODE *pCurrentInputNode;
|
INPUT_LIST_NODE *pNode;
|
||||||
HIMAGELIST hImageList;
|
HIMAGELIST hImageList = ListView_GetImageList(hwndList, LVSIL_SMALL);
|
||||||
|
INT iSelected = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
|
||||||
|
|
||||||
hImageList = ListView_GetImageList(hwndList, LVSIL_SMALL);
|
if (hImageList)
|
||||||
if (hImageList != NULL)
|
|
||||||
{
|
{
|
||||||
ImageList_RemoveAll(hImageList);
|
ImageList_RemoveAll(hImageList);
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView_DeleteAllItems(hwndList);
|
ListView_DeleteAllItems(hwndList);
|
||||||
|
|
||||||
for (pCurrentInputNode = InputList_GetFirst();
|
for (pNode = InputList_GetFirst(); pNode != NULL; pNode = pNode->pNext)
|
||||||
pCurrentInputNode != NULL;
|
|
||||||
pCurrentInputNode = pCurrentInputNode->pNext)
|
|
||||||
{
|
{
|
||||||
if (!(pCurrentInputNode->wFlags & INPUT_LIST_NODE_FLAG_DELETED))
|
if (pNode->wFlags & INPUT_LIST_NODE_FLAG_DELETED)
|
||||||
{
|
continue;
|
||||||
AddToInputListView(hwndList, pCurrentInputNode);
|
|
||||||
}
|
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
|
static VOID
|
||||||
OnInitSettingsPage(HWND hwndDlg)
|
OnInitSettingsPage(HWND hwndDlg)
|
||||||
{
|
{
|
||||||
HWND hwndInputList;
|
HWND hwndInputList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
|
||||||
|
|
||||||
LayoutList_Create();
|
LayoutList_Create();
|
||||||
LocaleList_Create();
|
LocaleList_Create();
|
||||||
InputList_Create();
|
InputList_Create();
|
||||||
|
|
||||||
hwndInputList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
|
|
||||||
|
|
||||||
if (hwndInputList != NULL)
|
if (hwndInputList != NULL)
|
||||||
{
|
{
|
||||||
WCHAR szBuffer[MAX_STR_LEN];
|
WCHAR szBuffer[MAX_STR_LEN];
|
||||||
HIMAGELIST hLayoutImageList;
|
HIMAGELIST hLayoutImageList;
|
||||||
LV_COLUMN column;
|
LV_COLUMN column = { LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM };
|
||||||
|
|
||||||
ListView_SetExtendedListViewStyle(hwndInputList, LVS_EX_FULLROWSELECT);
|
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));
|
LoadStringW(hApplet, IDS_LANGUAGE, szBuffer, ARRAYSIZE(szBuffer));
|
||||||
column.fmt = LVCFMT_LEFT;
|
column.fmt = LVCFMT_LEFT;
|
||||||
column.iSubItem = 0;
|
column.iSubItem = 0;
|
||||||
|
@ -233,7 +246,7 @@ OnInitSettingsPage(HWND hwndDlg)
|
||||||
UpdateInputListView(hwndInputList);
|
UpdateInputListView(hwndInputList);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetControlsState(hwndDlg, FALSE);
|
SetControlsState(hwndDlg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -259,6 +272,7 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
|
||||||
AddDialogProc) == IDOK)
|
AddDialogProc) == IDOK)
|
||||||
{
|
{
|
||||||
UpdateInputListView(GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST));
|
UpdateInputListView(GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST));
|
||||||
|
SetControlsState(hwndDlg);
|
||||||
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
|
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,21 +280,17 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
|
||||||
|
|
||||||
case IDC_REMOVE_BUTTON:
|
case IDC_REMOVE_BUTTON:
|
||||||
{
|
{
|
||||||
HWND hwndList;
|
HWND hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
|
||||||
|
if (hwndList)
|
||||||
hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
|
|
||||||
|
|
||||||
if (hwndList != NULL)
|
|
||||||
{
|
{
|
||||||
LVITEM item = { 0 };
|
LVITEM item = { LVIF_PARAM };
|
||||||
|
|
||||||
item.mask = LVIF_PARAM;
|
|
||||||
item.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
|
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);
|
InputList_Remove((INPUT_LIST_NODE*) item.lParam);
|
||||||
UpdateInputListView(hwndList);
|
UpdateInputListView(hwndList);
|
||||||
|
SetControlsState(hwndDlg);
|
||||||
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
|
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -289,18 +299,13 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
|
||||||
|
|
||||||
case IDC_PROP_BUTTON:
|
case IDC_PROP_BUTTON:
|
||||||
{
|
{
|
||||||
HWND hwndList;
|
HWND hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
|
||||||
|
if (hwndList)
|
||||||
hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
|
|
||||||
|
|
||||||
if (hwndList != NULL)
|
|
||||||
{
|
{
|
||||||
LVITEM item = { 0 };
|
LVITEM item = { LVIF_PARAM };
|
||||||
|
|
||||||
item.mask = LVIF_PARAM;
|
|
||||||
item.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
|
item.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
|
||||||
|
|
||||||
if (ListView_GetItem(hwndList, &item) != FALSE)
|
if (ListView_GetItem(hwndList, &item))
|
||||||
{
|
{
|
||||||
if (DialogBoxParamW(hApplet,
|
if (DialogBoxParamW(hApplet,
|
||||||
MAKEINTRESOURCEW(IDD_INPUT_LANG_PROP),
|
MAKEINTRESOURCEW(IDD_INPUT_LANG_PROP),
|
||||||
|
@ -309,6 +314,7 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
|
||||||
item.lParam) == IDOK)
|
item.lParam) == IDOK)
|
||||||
{
|
{
|
||||||
UpdateInputListView(hwndList);
|
UpdateInputListView(hwndList);
|
||||||
|
SetControlsState(hwndDlg);
|
||||||
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
|
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -318,21 +324,17 @@ OnCommandSettingsPage(HWND hwndDlg, WPARAM wParam)
|
||||||
|
|
||||||
case IDC_SET_DEFAULT:
|
case IDC_SET_DEFAULT:
|
||||||
{
|
{
|
||||||
HWND hwndList;
|
HWND hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
|
||||||
|
if (hwndList)
|
||||||
hwndList = GetDlgItem(hwndDlg, IDC_KEYLAYOUT_LIST);
|
|
||||||
|
|
||||||
if (hwndList != NULL)
|
|
||||||
{
|
{
|
||||||
LVITEM item = { 0 };
|
LVITEM item = { LVIF_PARAM };
|
||||||
|
|
||||||
item.mask = LVIF_PARAM;
|
|
||||||
item.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
|
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);
|
InputList_SetDefault((INPUT_LIST_NODE*) item.lParam);
|
||||||
UpdateInputListView(hwndList);
|
UpdateInputListView(hwndList);
|
||||||
|
SetControlsState(hwndDlg);
|
||||||
PropSheet_Changed(GetParent(hwndDlg), 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
|
static VOID
|
||||||
OnNotifySettingsPage(HWND hwndDlg, LPARAM lParam)
|
OnNotifySettingsPage(HWND hwndDlg, LPARAM lParam)
|
||||||
{
|
{
|
||||||
LPNMHDR header;
|
LPNMHDR header = (LPNMHDR)lParam;
|
||||||
|
|
||||||
header = (LPNMHDR)lParam;
|
|
||||||
|
|
||||||
switch (header->code)
|
switch (header->code)
|
||||||
{
|
{
|
||||||
case NM_CLICK:
|
case LVN_ITEMCHANGED:
|
||||||
{
|
{
|
||||||
if (header->idFrom == IDC_KEYLAYOUT_LIST)
|
if (header->idFrom == IDC_KEYLAYOUT_LIST)
|
||||||
{
|
{
|
||||||
INT iSelected = ListView_GetNextItem(header->hwndFrom, -1, LVNI_SELECTED);
|
SetControlsState(hwndDlg);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -424,20 +371,7 @@ OnNotifySettingsPage(HWND hwndDlg, LPARAM lParam)
|
||||||
case PSN_APPLY:
|
case PSN_APPLY:
|
||||||
{
|
{
|
||||||
/* Write Input Methods list to registry */
|
/* Write Input Methods list to registry */
|
||||||
if (InputList_Process())
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -706,6 +706,13 @@ inline BOOL IsValidKLID(_In_ LPCWSTR pwszKLID)
|
||||||
return (pwszKLID != NULL) && (wcsspn(pwszKLID, L"0123456789ABCDEFabcdef") == (KL_NAMELENGTH - 1));
|
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)
|
#define ENGLISH_US MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -722,15 +729,15 @@ IntLoadKeyboardLayout(
|
||||||
_In_ UINT Flags,
|
_In_ UINT Flags,
|
||||||
_In_ BOOL unknown5)
|
_In_ BOOL unknown5)
|
||||||
{
|
{
|
||||||
DWORD dwhkl, dwType, dwSize;
|
DWORD dwKLID, dwHKL, dwType, dwSize;
|
||||||
UNICODE_STRING ustrKbdName;
|
UNICODE_STRING ustrKbdName;
|
||||||
UNICODE_STRING ustrKLID;
|
UNICODE_STRING ustrKLID;
|
||||||
WCHAR wszRegKey[256] = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\";
|
WCHAR wszRegKey[256] = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\";
|
||||||
WCHAR wszLayoutId[10], wszNewKLID[KL_NAMELENGTH], szImeFileName[80];
|
WCHAR wszLayoutId[10], wszNewKLID[KL_NAMELENGTH], szImeFileName[80];
|
||||||
PWCHAR endptr;
|
|
||||||
HKL hNewKL;
|
HKL hNewKL;
|
||||||
HKEY hKey;
|
HKEY hKey;
|
||||||
BOOL bIsIME;
|
BOOL bIsIME;
|
||||||
|
WORD wLow, wHigh;
|
||||||
|
|
||||||
if (!IsValidKLID(pwszKLID))
|
if (!IsValidKLID(pwszKLID))
|
||||||
{
|
{
|
||||||
|
@ -738,13 +745,11 @@ IntLoadKeyboardLayout(
|
||||||
return UlongToHandle(MAKELONG(ENGLISH_US, ENGLISH_US));
|
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));
|
wLow = LOWORD(dwKLID);
|
||||||
if (!bIsIME) /* Not IME? */
|
wHigh = HIWORD(dwKLID);
|
||||||
{
|
|
||||||
dwhkl = LOWORD(dwhkl); /* LOWORD of dwhkl is language identifier */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Flags & KLF_SUBSTITUTE_OK)
|
if (Flags & KLF_SUBSTITUTE_OK)
|
||||||
{
|
{
|
||||||
|
@ -753,10 +758,14 @@ IntLoadKeyboardLayout(
|
||||||
KEY_READ, &hKey) == ERROR_SUCCESS)
|
KEY_READ, &hKey) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
dwSize = sizeof(wszNewKLID);
|
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 */
|
/* Use new KLID value */
|
||||||
pwszKLID = wszNewKLID;
|
pwszKLID = wszNewKLID;
|
||||||
|
dwKLID = wcstoul(pwszKLID, NULL, 16);
|
||||||
|
wHigh = LOWORD(dwKLID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Close the key now */
|
/* Close the key now */
|
||||||
|
@ -771,14 +780,11 @@ IntLoadKeyboardLayout(
|
||||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
dwSize = sizeof(wszLayoutId);
|
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 */
|
/* If Layout Id is specified, use this value | f000 as HIWORD */
|
||||||
/* FIXME: Microsoft Office expects this value to be something specific
|
wHigh = (0xF000 | wcstoul(wszLayoutId, NULL, 16));
|
||||||
* for Japanese and Korean Windows with an IME the value is 0xe001
|
|
||||||
*/
|
|
||||||
if (!bIsIME)
|
|
||||||
dwhkl |= (0xf000 | wcstol(wszLayoutId, NULL, 16)) << 16;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bIsIME)
|
if (bIsIME)
|
||||||
|
@ -788,9 +794,18 @@ IntLoadKeyboardLayout(
|
||||||
if (RegQueryValueExW(hKey, L"IME File", NULL, &dwType, (LPBYTE)szImeFileName,
|
if (RegQueryValueExW(hKey, L"IME File", NULL, &dwType, (LPBYTE)szImeFileName,
|
||||||
&dwSize) != ERROR_SUCCESS)
|
&dwSize) != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
FIXME("Check IME file existence in system32\n");
|
|
||||||
bIsIME = FALSE;
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If Layout Id is not given HIWORD == LOWORD (for dwhkl) */
|
if (wHigh == 0)
|
||||||
if (!HIWORD(dwhkl))
|
wHigh = wLow;
|
||||||
dwhkl |= dwhkl << 16;
|
|
||||||
|
dwHKL = MAKELONG(wLow, wHigh);
|
||||||
|
|
||||||
ZeroMemory(&ustrKbdName, sizeof(ustrKbdName));
|
ZeroMemory(&ustrKbdName, sizeof(ustrKbdName));
|
||||||
RtlInitUnicodeString(&ustrKLID, pwszKLID);
|
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);
|
CliImmInitializeHotKeys(SETIMEHOTKEY_ADD, hNewKL);
|
||||||
return hNewKL;
|
return hNewKL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue