xref: /reactos/dll/cpl/input/layout_list.c (revision 7eda556c)
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