1 /*
2 * PROJECT: input.dll
3 * FILE: dll/cpl/input/layout_list.c
4 * PURPOSE: input.dll
5 * PROGRAMMER: Dmitry Chapyshev (dmitry@reactos.org)
6 * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
7 */
8
9 #include "layout_list.h"
10
11 static LAYOUT_LIST_NODE *_LayoutList = NULL;
12
13 static LAYOUT_LIST_NODE*
LayoutList_AppendNode(DWORD dwKLID,WORD wSpecialId,LPCWSTR pszFile,LPCWSTR pszName,LPCWSTR pszImeFile)14 LayoutList_AppendNode(DWORD dwKLID, WORD wSpecialId, LPCWSTR pszFile, LPCWSTR pszName,
15 LPCWSTR pszImeFile)
16 {
17 LAYOUT_LIST_NODE *pCurrent;
18 LAYOUT_LIST_NODE *pNew;
19
20 if (pszName == NULL)
21 return NULL;
22
23 pCurrent = _LayoutList;
24
25 pNew = (LAYOUT_LIST_NODE*)malloc(sizeof(LAYOUT_LIST_NODE));
26 if (pNew == NULL)
27 return NULL;
28
29 ZeroMemory(pNew, sizeof(LAYOUT_LIST_NODE));
30
31 pNew->dwKLID = dwKLID;
32 pNew->wSpecialId = wSpecialId;
33
34 pNew->pszName = _wcsdup(pszName);
35 pNew->pszFile = _wcsdup(pszFile);
36 pNew->pszImeFile = _wcsdup(pszImeFile);
37 if (pNew->pszName == NULL || pNew->pszFile == NULL ||
38 (pszImeFile && pNew->pszImeFile == NULL))
39 {
40 free(pNew->pszName);
41 free(pNew->pszFile);
42 free(pNew->pszImeFile);
43 free(pNew);
44 return NULL;
45 }
46
47 if (pCurrent == NULL)
48 {
49 _LayoutList = pNew;
50 }
51 else
52 {
53 while (pCurrent->pNext != NULL)
54 {
55 pCurrent = pCurrent->pNext;
56 }
57
58 pNew->pPrev = pCurrent;
59 pCurrent->pNext = pNew;
60 }
61
62 return pNew;
63 }
64
65
66 VOID
LayoutList_Destroy(VOID)67 LayoutList_Destroy(VOID)
68 {
69 LAYOUT_LIST_NODE *pCurrent;
70 LAYOUT_LIST_NODE *pNext;
71
72 if (_LayoutList == NULL)
73 return;
74
75 for (pCurrent = _LayoutList; pCurrent; pCurrent = pNext)
76 {
77 pNext = pCurrent->pNext;
78
79 free(pCurrent->pszName);
80 free(pCurrent->pszFile);
81 free(pCurrent->pszImeFile);
82 free(pCurrent);
83 }
84
85 _LayoutList = NULL;
86 }
87
88 typedef HRESULT (WINAPI *FN_SHLoadRegUIStringW)(HKEY, LPCWSTR, LPWSTR, DWORD);
89
FakeSHLoadRegUIStringW(HKEY hkey,LPCWSTR value,LPWSTR buf,DWORD size)90 HRESULT FakeSHLoadRegUIStringW(HKEY hkey, LPCWSTR value, LPWSTR buf, DWORD size)
91 {
92 HRESULT hr = E_FAIL;
93 HINSTANCE hSHLWAPI = LoadLibraryW(L"shlwapi");
94 FN_SHLoadRegUIStringW fn;
95 fn = (FN_SHLoadRegUIStringW)GetProcAddress(hSHLWAPI, (LPCSTR)(INT_PTR)439);
96 if (fn)
97 hr = fn(hkey, value, buf, size);
98 FreeLibrary(hSHLWAPI);
99 return hr;
100 }
101
102 static BOOL
LayoutList_ReadLayout(HKEY hLayoutKey,LPCWSTR szKLID,LPCWSTR szSystemDirectory)103 LayoutList_ReadLayout(HKEY hLayoutKey, LPCWSTR szKLID, LPCWSTR szSystemDirectory)
104 {
105 WCHAR szFile[80], szImeFile[80], szBuffer[MAX_PATH], szFilePath[MAX_PATH];
106 DWORD dwSize, dwKLID = DWORDfromString(szKLID);
107 WORD wSpecialId = 0;
108 LPWSTR pszImeFile = NULL;
109
110 dwSize = sizeof(szFile);
111 if (RegQueryValueExW(hLayoutKey, L"Layout File", NULL, NULL,
112 (LPBYTE)szFile, &dwSize) != ERROR_SUCCESS)
113 {
114 return FALSE; /* No "Layout File" value */
115 }
116
117 if (IS_IME_KLID(dwKLID))
118 {
119 WCHAR szPath[MAX_PATH];
120 dwSize = sizeof(szImeFile);
121 if (RegQueryValueExW(hLayoutKey, L"IME File", NULL, NULL,
122 (LPBYTE)szImeFile, &dwSize) != ERROR_SUCCESS)
123 {
124 return FALSE; /* No "IME File" value */
125 }
126
127 if (wcschr(szImeFile, L'\\') != NULL)
128 return FALSE; /* Invalid character */
129
130 GetSystemLibraryPath(szPath, ARRAYSIZE(szPath), szImeFile);
131 if (GetFileAttributesW(szPath) == INVALID_FILE_ATTRIBUTES)
132 return FALSE; /* Does not exist */
133
134 pszImeFile = szImeFile;
135 }
136
137 /* Build the "Layout File" full path and check existence */
138 StringCchPrintfW(szFilePath, ARRAYSIZE(szFilePath), L"%s\\%s", szSystemDirectory, szFile);
139 if (GetFileAttributesW(szFilePath) == INVALID_FILE_ATTRIBUTES)
140 return FALSE; /* No layout file found */
141
142 /* Get the special ID */
143 dwSize = sizeof(szBuffer);
144 if (RegQueryValueExW(hLayoutKey, L"Layout Id", NULL, NULL,
145 (LPBYTE)szBuffer, &dwSize) == ERROR_SUCCESS)
146 {
147 wSpecialId = LOWORD(DWORDfromString(szBuffer));
148 }
149
150 /* If there is a valid "Layout Display Name", then use it as the entry name */
151 if (FakeSHLoadRegUIStringW(hLayoutKey, L"Layout Display Name",
152 szBuffer, ARRAYSIZE(szBuffer)) == S_OK)
153 {
154 LayoutList_AppendNode(dwKLID, wSpecialId, szFile, szBuffer, pszImeFile);
155 return TRUE;
156 }
157
158 /* Otherwise, use "Layout Text" value as the entry name */
159 dwSize = sizeof(szBuffer);
160 if (RegQueryValueExW(hLayoutKey, L"Layout Text", NULL, NULL,
161 (LPBYTE)szBuffer, &dwSize) == ERROR_SUCCESS)
162 {
163 LayoutList_AppendNode(dwKLID, wSpecialId, szFile, szBuffer, pszImeFile);
164 return TRUE;
165 }
166
167 return FALSE;
168 }
169
170 VOID
LayoutList_Create(VOID)171 LayoutList_Create(VOID)
172 {
173 WCHAR szSystemDirectory[MAX_PATH], szKLID[KL_NAMELENGTH];
174 DWORD dwSize, dwIndex;
175 HKEY hKey, hLayoutKey;
176
177 if (!GetSystemDirectoryW(szSystemDirectory, ARRAYSIZE(szSystemDirectory)))
178 return;
179
180 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts",
181 0, KEY_READ, &hKey) != ERROR_SUCCESS)
182 {
183 return;
184 }
185
186 for (dwIndex = 0; ; ++dwIndex)
187 {
188 dwSize = ARRAYSIZE(szKLID);
189 if (RegEnumKeyExW(hKey, dwIndex, szKLID, &dwSize, NULL, NULL,
190 NULL, NULL) != ERROR_SUCCESS)
191 {
192 break;
193 }
194
195 if (RegOpenKeyExW(hKey, szKLID, 0, KEY_QUERY_VALUE, &hLayoutKey) == ERROR_SUCCESS)
196 {
197 LayoutList_ReadLayout(hLayoutKey, szKLID, szSystemDirectory);
198 RegCloseKey(hLayoutKey);
199 }
200 }
201
202 RegCloseKey(hKey);
203 }
204
205
206 LAYOUT_LIST_NODE*
LayoutList_GetByHkl(HKL hkl)207 LayoutList_GetByHkl(HKL hkl)
208 {
209 LAYOUT_LIST_NODE *pCurrent;
210
211 if (IS_SPECIAL_HKL(hkl))
212 {
213 WORD wSpecialId = SPECIALIDFROMHKL(hkl);
214
215 for (pCurrent = _LayoutList; pCurrent != NULL; pCurrent = pCurrent->pNext)
216 {
217 if (wSpecialId == pCurrent->wSpecialId)
218 {
219 return pCurrent;
220 }
221 }
222 }
223 else if (IS_IME_HKL(hkl))
224 {
225 for (pCurrent = _LayoutList; pCurrent != NULL; pCurrent = pCurrent->pNext)
226 {
227 if (hkl == UlongToHandle(pCurrent->dwKLID))
228 {
229 return pCurrent;
230 }
231 }
232 }
233 else
234 {
235 for (pCurrent = _LayoutList; pCurrent != NULL; pCurrent = pCurrent->pNext)
236 {
237 if (HIWORD(hkl) == LOWORD(pCurrent->dwKLID))
238 {
239 return pCurrent;
240 }
241 }
242 }
243
244 return NULL;
245 }
246
247
248 LAYOUT_LIST_NODE*
LayoutList_GetFirst(VOID)249 LayoutList_GetFirst(VOID)
250 {
251 return _LayoutList;
252 }
253