Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804/** 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"#define NOTHING
typedef struct{ PWCHAR FontName; PWCHAR SubFontName;} MUI_SUBFONT;
#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";
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, pszKey, 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS) 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;}
VOID GetSystemLibraryPath(LPWSTR pszPath, INT cchPath, LPCWSTR pszFileName){ WCHAR szSysDir[MAX_PATH]; GetSystemDirectoryW(szSysDir, ARRAYSIZE(szSysDir)); StringCchPrintfW(pszPath, cchPath, L"%s\\%s", szSysDir, pszFileName);}
BOOLInputList_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: pSubstitutes = ChineseSimplifiedFonts; break; case SUBLANG_CHINESE_TRADITIONAL: case SUBLANG_CHINESE_HONGKONG: case SUBLANG_CHINESE_MACAU: 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;
pNew = (INPUT_LIST_NODE*)malloc(sizeof(INPUT_LIST_NODE)); if (pNew == NULL) return NULL;
ZeroMemory(pNew, sizeof(INPUT_LIST_NODE));
if (_InputList == NULL) /* Empty? */ { _InputList = pNew; return pNew; }
/* Find last node */ for (pCurrent = _InputList; pCurrent->pNext; pCurrent = pCurrent->pNext) { NOTHING; }
/* Add to the end */ pCurrent->pNext = pNew; pNew->pPrev = pCurrent;
return pNew;}
static VOIDInputList_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; }}
VOIDInputList_Destroy(VOID){ INPUT_LIST_NODE *pCurrent; INPUT_LIST_NODE *pNext;
if (_InputList == NULL) return;
for (pCurrent = _InputList; pCurrent; pCurrent = pNext) { pNext = pCurrent->pNext;
free(pCurrent->pszIndicator); free(pCurrent); }
_InputList = NULL;}
static BOOLInputList_PrepareUserRegistry(PHKEY phPreloadKey, PHKEY phSubstKey){ BOOL bResult = FALSE; HKEY hKey;
*phPreloadKey = *phSubstKey = 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 && RegCreateKeyW(hKey, L"Preload", phPreloadKey) == ERROR_SUCCESS && RegCreateKeyW(hKey, L"Substitutes", phSubstKey) == ERROR_SUCCESS) { bResult = TRUE; }
if (hKey) RegCloseKey(hKey);
return bResult;}
static BOOLInputList_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 BOOLInputList_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 DWORDInputList_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 VOIDInputList_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;
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)) { UINT uFlags = KLF_SUBSTITUTE_OK | KLF_NOTELLSHELL; if (pNode->wFlags & INPUT_LIST_NODE_FLAG_DEFAULT) uFlags |= KLF_REPLACELANG;
pNode->hkl = LoadKeyboardLayoutW(szLogicalKLID, uFlags); }}
/* * Writes any changes in input methods to the registry */BOOLInputList_Process(VOID){ INPUT_LIST_NODE *pCurrent; DWORD dwNumber; BOOL bRet = FALSE; HKEY hPreloadKey, hSubstKey; HKL hDefaultKL = NULL;
if (!InputList_PrepareUserRegistry(&hPreloadKey, &hSubstKey)) { if (hPreloadKey) RegCloseKey(hPreloadKey); if (hSubstKey) RegCloseKey(hSubstKey); return FALSE; }
/* Find change in the IME HKLs */ for (pCurrent = _InputList; pCurrent != NULL; pCurrent = pCurrent->pNext) { if (!IS_IME_HKL(pCurrent->hkl)) continue;
if ((pCurrent->wFlags & INPUT_LIST_NODE_FLAG_ADDED) || (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_EDITED) || (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DELETED)) { bRet = TRUE; /* Reboot is needed */ break; } }
/* 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)) { /* But the EDITED entries are used later */ if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DELETED) { InputList_RemoveNode(pCurrent); } } } }
/* 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(hPreloadKey, hSubstKey, 1, pCurrent);
/* Activate the DEFAULT entry */ ActivateKeyboardLayout(pCurrent->hkl, KLF_RESET);
/* Save it */ hDefaultKL = pCurrent->hkl; break; } }
/* Add entries except DEFAULT to registry */ dwNumber = 2; 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) continue;
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, &hDefaultKL, 0)) { DWORD dwRecipients = BSM_ALLDESKTOPS | BSM_APPLICATIONS;
BroadcastSystemMessageW(BSF_POSTMESSAGE, &dwRecipients, WM_INPUTLANGCHANGEREQUEST, INPUTLANGCHANGE_SYSCHARSET, (LPARAM)hDefaultKL); }
/* 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_DELETED) { UnloadKeyboardLayout(pCurrent->hkl); InputList_RemoveNode(pCurrent); } }
RegCloseKey(hPreloadKey); RegCloseKey(hSubstKey); return bRet;}
BOOLInputList_Add(LOCALE_LIST_NODE *pLocale, LAYOUT_LIST_NODE *pLayout){ WCHAR szIndicator[MAX_STR_LEN]; INPUT_LIST_NODE *pInput = NULL;
if (pLocale == NULL || pLayout == NULL) { return FALSE; }
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; /* Already exists */ } }
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;}
VOIDInputList_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; } }}
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. * To apply the changes using InputList_Process() */BOOLInputList_Remove(INPUT_LIST_NODE *pNode){ BOOL ret = FALSE; BOOL bRemoveNode = FALSE;
if (pNode == NULL) return FALSE;
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) { INPUT_LIST_NODE *pCurrent = InputList_FindNextDefault(pNode); if (pCurrent) pCurrent->wFlags |= INPUT_LIST_NODE_FLAG_DEFAULT;
pNode->wFlags &= ~INPUT_LIST_NODE_FLAG_DEFAULT; ret = TRUE; /* default input is changed */ }
if (bRemoveNode) { InputList_RemoveNode(pNode); }
return ret;}
BOOLInputList_RemoveByLang(LANGID wLangId){ BOOL ret = FALSE; INPUT_LIST_NODE *pCurrent;
Retry: for (pCurrent = _InputList; pCurrent; pCurrent = pCurrent->pNext) { if (pCurrent->wFlags & INPUT_LIST_NODE_FLAG_DELETED) continue;
if (LOWORD(pCurrent->pLocale->dwId) == wLangId) { if (InputList_Remove(pCurrent)) ret = TRUE; /* default input is changed */ goto Retry; } }
return ret;}
VOIDInputList_Create(VOID){ 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 || 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? */ { pInput->wFlags |= INPUT_LIST_NODE_FLAG_DEFAULT; hklDefault = NULL; /* No more default item */ }
/* 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);}
static INT InputList_Compare(INPUT_LIST_NODE *pNode1, INPUT_LIST_NODE *pNode2){ INT nCompare = _wcsicmp(pNode1->pszIndicator, pNode2->pszIndicator); if (nCompare != 0) return nCompare;
return _wcsicmp(pNode1->pLayout->pszName, pNode2->pLayout->pszName);}
VOID InputList_Sort(VOID){ INPUT_LIST_NODE *pList = _InputList; INPUT_LIST_NODE *pNext, *pPrev; INPUT_LIST_NODE *pMinimum, *pNode;
_InputList = NULL;
while (pList) { /* Find the minimum node */ pMinimum = NULL; for (pNode = pList; pNode; pNode = pNext) { pNext = pNode->pNext;
if (pMinimum == NULL) { pMinimum = pNode; } else if (InputList_Compare(pNode, pMinimum) < 0) { pMinimum = pNode; } }
// Remove pMinimum from pList pNext = pMinimum->pNext; pPrev = pMinimum->pPrev; if (pNext) pNext->pPrev = pPrev; if (pPrev) pPrev->pNext = pNext; else pList = pNext;
// Append pMinimum to _InputList if (!_InputList) { pMinimum->pPrev = pMinimum->pNext = NULL; _InputList = pMinimum; } else { /* Find last node */ for (pNode = _InputList; pNode->pNext; pNode = pNode->pNext) { NOTHING; }
/* Add to the end */ pNode->pNext = pMinimum; pMinimum->pPrev = pNode; pMinimum->pNext = NULL; } }}
INTInputList_GetAliveCount(VOID){ INPUT_LIST_NODE *pNode; INT nCount = 0;
for (pNode = _InputList; pNode; pNode = pNode->pNext) { if (pNode->wFlags & INPUT_LIST_NODE_FLAG_DELETED) continue;
++nCount; }
return nCount;}
INPUT_LIST_NODE*InputList_GetFirst(VOID){ return _InputList;}