reactos/dll/cpl/input/input_list.c

589 lines
14 KiB
C
Raw Normal View History

/*
* PROJECT: input.dll
* FILE: dll/cpl/input/input_list.c
* PURPOSE: input.dll
* PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org)
* Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
*/
#include "input_list.h"
typedef struct
{
PWCHAR FontName;
PWCHAR SubFontName;
} MUI_SUBFONT;
[SETUPLIB][USETUP][INPUT.CPL] MUI integration with setuplib. [SETUPLIB] Copy the mui* files from usetup into the setuplib for later usage, and add mui.c to build. svn path=/branches/setup_improvements/; revision=75711 [SETUPLIB][USETUP] Start massaging the MUI files and split up what concerns only the usetup "resources", and what concerns general language parameters (in the setuplib). It may be interesting to retrieve the language parameters from INF file (e.g. intl.inf) (suggested by Giannis). svn path=/branches/setup_improvements/; revision=75715 [SETUPLIB] Add the necessary headers to mui.c to be able to compile. [USETUP] Comment out the languages that don't have any resources. svn path=/branches/setup_improvements/; revision=75716 [SETUPLIB][USETUP] Adjust MUI and settings code. - Re-enable settings code concerning language, keyboards & layout in the setuplib, and remove the old code in usetup. - Remove useless code in setuplib's mui.c. - Rename usetup's MUI "LanguageList" into "ResourceList" so as to avoid colliding with the "LanguageList" of setuplib. - Add the magic CMakeLists line "add_definitions(${I18N_DEFS})" that I forgot previously, that caused the "LanguageList" of setuplib to be empty! The code compiles and works during my tests. svn path=/branches/setup_improvements/; revision=75717 [SETUPLIB] Change some string pointer types & function prototypes so that the usetup-specific "SelectedLanguageId" variable is not used in the library. svn path=/branches/setup_improvements/; revision=75719 [SETUPLIB] Change some function prototypes so that the usetup-specific "SelectedLanguageId" variable is not used in the library. Also, make AddEntriesFromInfSection(), DefaultProcessEntry() and the typedef PPROCESS_ENTRY_ROUTINE private again. svn path=/branches/setup_improvements/; revision=75720 svn path=/branches/setup_improvements/; revision=75724 [USETUP] Code adaptations. - Transform some do{}while() loops into while(){} ones, since the lists on which we work may only contain one single {NULL} element. - Modify MUIGetOEMCodePage() call after r75719. - Use PCWSTR where needed. svn path=/branches/setup_improvements/; revision=75722 [USETUP] Adjust some MUI & settings calls, following the commits r75719, r75720 and r75721. svn path=/branches/setup_improvements/; revision=75723 [INPUT.CPL] Adjust inclusion of "muifonts.h" (commit 3dbd44f) due to changes introduced in r75711 and r75715.
2017-08-30 11:28:52 +00:00
#include "../../../base/setup/lib/muifonts.h"
BOOL UpdateRegistryForFontSubstitutes(MUI_SUBFONT *pSubstitutes)
{
DWORD cbData;
HKEY hKey;
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)
return FALSE;
/* Overwrite only */
for (; pSubstitutes->FontName; ++pSubstitutes)
{
cbData = (lstrlenW(pSubstitutes->SubFontName) + 1) * sizeof(WCHAR);
RegSetValueExW(hKey, pSubstitutes->FontName, 0,
REG_SZ, (LPBYTE)pSubstitutes->SubFontName, cbData);
}
RegCloseKey(hKey);
return TRUE;
}
BOOL
InputList_SetFontSubstitutes(LCID dwLocaleId)
{
MUI_SUBFONT *pSubstitutes;
WORD wLangID, wPrimaryLangID, wSubLangID;
wLangID = LANGIDFROMLCID(dwLocaleId);
wPrimaryLangID = PRIMARYLANGID(wLangID);
wSubLangID = SUBLANGID(wLangID);
/* FIXME: Add more if necessary */
switch (wPrimaryLangID)
{
default:
pSubstitutes = LatinFonts;
break;
case LANG_AZERI:
case LANG_BELARUSIAN:
case LANG_BULGARIAN:
case LANG_KAZAK:
case LANG_RUSSIAN:
case LANG_SERBIAN:
case LANG_TATAR:
case LANG_UKRAINIAN:
case LANG_UZBEK:
pSubstitutes = CyrillicFonts;
break;
case LANG_GREEK:
pSubstitutes = GreekFonts;
break;
case LANG_HEBREW:
pSubstitutes = HebrewFonts;
break;
case LANG_CHINESE:
switch (wSubLangID)
{
case SUBLANG_CHINESE_SIMPLIFIED:
case SUBLANG_CHINESE_SINGAPORE:
case SUBLANG_CHINESE_MACAU:
pSubstitutes = ChineseSimplifiedFonts;
break;
case SUBLANG_CHINESE_TRADITIONAL:
case SUBLANG_CHINESE_HONGKONG:
pSubstitutes = ChineseTraditionalFonts;
break;
default:
pSubstitutes = NULL;
DebugBreak();
break;
}
break;
case LANG_JAPANESE:
pSubstitutes = JapaneseFonts;
break;
case LANG_KOREAN:
pSubstitutes = KoreanFonts;
break;
case LANG_ARABIC:
case LANG_ARMENIAN:
case LANG_BENGALI:
case LANG_FARSI:
case LANG_GEORGIAN:
case LANG_GUJARATI:
case LANG_HINDI:
case LANG_KONKANI:
case LANG_MARATHI:
case LANG_PUNJABI:
case LANG_SANSKRIT:
case LANG_TAMIL:
case LANG_TELUGU:
case LANG_THAI:
case LANG_URDU:
case LANG_VIETNAMESE:
pSubstitutes = UnicodeFonts;
break;
}
if (pSubstitutes)
{
UpdateRegistryForFontSubstitutes(pSubstitutes);
return TRUE;
}
return FALSE;
}
static INPUT_LIST_NODE *_InputList = NULL;
static INPUT_LIST_NODE*
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)
{
_InputList = pNew;
}
else
{
while (pCurrent->pNext != NULL)
{
pCurrent = pCurrent->pNext;
}
pNew->pPrev = pCurrent;
pCurrent->pNext = pNew;
}
return pNew;
}
static VOID
InputList_RemoveNode(INPUT_LIST_NODE *pNode)
{
INPUT_LIST_NODE *pCurrent = pNode;
if (_InputList == NULL)
return;
if (pCurrent != NULL)
{
INPUT_LIST_NODE *pNext = pCurrent->pNext;
INPUT_LIST_NODE *pPrev = pCurrent->pPrev;
free(pCurrent->pszIndicator);
free(pCurrent);
if (pNext != NULL)
pNext->pPrev = pPrev;
if (pPrev != NULL)
pPrev->pNext = pNext;
else
_InputList = pNext;
}
}
VOID
InputList_Destroy(VOID)
{
INPUT_LIST_NODE *pCurrent;
if (_InputList == NULL)
return;
pCurrent = _InputList;
while (pCurrent != NULL)
{
INPUT_LIST_NODE *pNext = pCurrent->pNext;
free(pCurrent->pszIndicator);
free(pCurrent);
pCurrent = pNext;
}
_InputList = NULL;
}
static BOOL
InputList_PrepareUserRegistry(VOID)
{
BOOL bResult = FALSE;
HKEY hTempKey = NULL;
HKEY hKey = NULL;
if (RegOpenKeyExW(HKEY_CURRENT_USER,
L"Keyboard Layout",
0,
KEY_ALL_ACCESS,
&hKey) == ERROR_SUCCESS)
{
RegDeleteKeyW(hKey, L"Preload");
RegDeleteKeyW(hKey, L"Substitutes");
RegCloseKey(hKey);
}
if (RegCreateKeyW(HKEY_CURRENT_USER, L"Keyboard Layout", &hKey) != ERROR_SUCCESS)
{
goto Cleanup;
}
if (RegCreateKeyW(hKey, L"Preload", &hTempKey) != ERROR_SUCCESS)
{
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);
return bResult;
}
static VOID
InputList_AddInputMethodToUserRegistry(DWORD dwIndex, INPUT_LIST_NODE *pNode)
{
WCHAR szMethodIndex[MAX_PATH];
WCHAR szPreload[MAX_PATH];
BOOL bIsImeMethod = FALSE;
HKEY hKey;
StringCchPrintfW(szMethodIndex, ARRAYSIZE(szMethodIndex), L"%lu", dwIndex);
/* 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);
}
if (RegOpenKeyExW(HKEY_CURRENT_USER,
L"Keyboard Layout\\Preload",
0,
KEY_SET_VALUE,
&hKey) == ERROR_SUCCESS)
{
RegSetValueExW(hKey,
szMethodIndex,
0,
REG_SZ,
(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) ||
(pNode->wFlags & INPUT_LIST_NODE_FLAG_EDITED))
{
pNode->hkl = LoadKeyboardLayoutW(szPreload, KLF_SUBSTITUTE_OK | KLF_NOTELLSHELL);
}
}
/*
* Writes any changes in input methods to the registry
*/
BOOL
InputList_Process(VOID)
{
INPUT_LIST_NODE *pCurrent;
DWORD dwIndex;
BOOL bRet = FALSE;
/* Process deleted and edited input methods */
for (pCurrent = _InputList; pCurrent != NULL; pCurrent = pCurrent->pNext)
{
if ((pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DELETED) ||
(pCurrent->wFlags & INPUT_LIST_NODE_FLAG_EDITED))
{
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))
{
InputList_RemoveNode(pCurrent);
}
}
}
}
InputList_PrepareUserRegistry();
/* Find default input method */
for (pCurrent = _InputList; pCurrent != NULL; pCurrent = pCurrent->pNext)
{
if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT)
{
bRet = InputList_SetFontSubstitutes(pCurrent->pLocale->dwId);
InputList_AddInputMethodToUserRegistry(1, pCurrent);
break;
}
}
if (SystemParametersInfoW(SPI_SETDEFAULTINPUTLANG,
0,
(LPVOID)((LPDWORD)&pCurrent->hkl),
0))
{
DWORD dwRecipients;
dwRecipients = BSM_ALLCOMPONENTS;
BroadcastSystemMessageW(BSF_POSTMESSAGE,
&dwRecipients,
WM_INPUTLANGCHANGEREQUEST,
0,
(LPARAM)pCurrent->hkl);
}
/* Add methods to registry */
dwIndex = 2;
for (pCurrent = _InputList; pCurrent != NULL; pCurrent = pCurrent->pNext)
{
if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT)
continue;
InputList_AddInputMethodToUserRegistry(dwIndex, pCurrent);
dwIndex++;
}
return bRet;
}
BOOL
InputList_Add(LOCALE_LIST_NODE *pLocale, LAYOUT_LIST_NODE *pLayout)
{
WCHAR szIndicator[MAX_STR_LEN];
INPUT_LIST_NODE *pInput;
if (pLocale == NULL || pLayout == NULL)
{
return FALSE;
}
for (pInput = _InputList; pInput != NULL; pInput = pInput->pNext)
{
if (pInput->pLocale == pLocale && pInput->pLayout == pLayout)
{
return FALSE;
}
}
pInput = InputList_AppendNode();
pInput->wFlags = INPUT_LIST_NODE_FLAG_ADDED;
pInput->pLocale = pLocale;
pInput->pLayout = pLayout;
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);
}
}
return TRUE;
}
VOID
InputList_SetDefault(INPUT_LIST_NODE *pNode)
{
INPUT_LIST_NODE *pCurrent;
if (pNode == NULL)
return;
for (pCurrent = _InputList; pCurrent != NULL; pCurrent = pCurrent->pNext)
{
if (pCurrent == pNode)
{
pCurrent->wFlags |= INPUT_LIST_NODE_FLAG_DEFAULT;
}
else
{
pCurrent->wFlags &= ~INPUT_LIST_NODE_FLAG_DEFAULT;
}
}
}
/*
* It marks the input method for deletion, but does not delete it directly.
* To apply the changes using InputList_Process()
*/
VOID
InputList_Remove(INPUT_LIST_NODE *pNode)
{
BOOL bRemoveNode = FALSE;
if (pNode == NULL)
return;
if (pNode->wFlags & INPUT_LIST_NODE_FLAG_ADDED)
{
/*
* If the input method has been added to the list, but not yet written
* in the registry, then simply remove it from the list
*/
bRemoveNode = TRUE;
}
else
{
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;
}
}
if (bRemoveNode != FALSE)
{
InputList_RemoveNode(pNode);
}
}
VOID
InputList_Create(VOID)
{
INT iLayoutCount;
HKL *pLayoutList;
iLayoutCount = GetKeyboardLayoutList(0, NULL);
pLayoutList = (HKL*) malloc(iLayoutCount * sizeof(HKL));
if (pLayoutList != NULL)
{
if (GetKeyboardLayoutList(iLayoutCount, pLayoutList) > 0)
{
INT iIndex;
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);
}
}
INPUT_LIST_NODE*
InputList_GetFirst(VOID)
{
return _InputList;
}