[WINHTTP] Sync with Wine Staging 3.9. CORE-14656
[reactos.git] / dll / cpl / intl / kblayouts.c
1 /*
2 * PROJECT: ReactOS International Control Panel
3 * FILE: dll/cpl/intl/kblayouts.c
4 * PURPOSE: Functions for manipulation with keyboard layouts
5 * PROGRAMMER: Dmitry Chapyshev (dmitry@reactos.org)
6 */
7
8 #include "intl.h"
9
10 /* Character Count of a layout ID like "00000409" */
11 #define CCH_LAYOUT_ID 8
12
13 /* Maximum Character Count of a ULONG in decimal */
14 #define CCH_ULONG_DEC 10
15
16
17 /* szLayoutID like 00000409, szLangID like 00000409 */
18 static BOOL
19 IsLayoutExists(PWSTR szLayoutID, PWSTR szLangID)
20 {
21 HKEY hKey, hSubKey;
22 WCHAR szPreload[CCH_LAYOUT_ID + 1], szLayoutNum[3 + 1],
23 szTmp[CCH_LAYOUT_ID + 1], szOldLangID[CCH_LAYOUT_ID + 1];
24 DWORD dwIndex = 0, dwType, dwSize;
25 BOOL IsLangExists = FALSE;
26 LANGID langid;
27
28 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload",
29 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
30 {
31 dwSize = sizeof(szLayoutNum);
32
33 while (RegEnumValueW(hKey, dwIndex, szLayoutNum, &dwSize, NULL, &dwType, NULL, NULL) == ERROR_SUCCESS)
34 {
35 dwSize = sizeof(szPreload);
36 if (RegQueryValueExW(hKey, szLayoutNum, NULL, NULL, (LPBYTE)szPreload, &dwSize) != ERROR_SUCCESS)
37 {
38 RegCloseKey(hKey);
39 return FALSE;
40 }
41
42 langid = (LANGID)wcstoul(szPreload, NULL, 16);
43 GetLocaleInfoW(langid, LOCALE_ILANGUAGE, szTmp, sizeof(szTmp) / sizeof(WCHAR));
44 wsprintf(szOldLangID, L"0000%s", szTmp);
45
46 if (wcscmp(szOldLangID, szLangID) == 0)
47 IsLangExists = TRUE;
48 else
49 IsLangExists = FALSE;
50
51 if (szPreload[0] == 'd')
52 {
53 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Substitutes",
54 0, KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS)
55 {
56 dwSize = sizeof(szTmp);
57 RegQueryValueExW(hSubKey, szPreload, NULL, NULL, (LPBYTE)szTmp, &dwSize);
58
59 if ((wcscmp(szTmp, szLayoutID) == 0)&&(IsLangExists))
60 {
61 RegCloseKey(hSubKey);
62 RegCloseKey(hKey);
63 return TRUE;
64 }
65 }
66 }
67 else
68 {
69 if ((wcscmp(szPreload, szLayoutID) == 0) && (IsLangExists))
70 {
71 RegCloseKey(hKey);
72 return TRUE;
73 }
74 }
75
76 IsLangExists = FALSE;
77 dwSize = sizeof(szLayoutNum);
78 dwIndex++;
79 }
80
81 RegCloseKey(hKey);
82 }
83
84 return FALSE;
85 }
86
87 static INT
88 GetLayoutCount(PWSTR szLang)
89 {
90 HKEY hKey;
91 WCHAR szLayoutID[3 + 1], szPreload[CCH_LAYOUT_ID + 1], szLOLang[MAX_PATH];
92 DWORD dwIndex = 0, dwType, dwSize;
93 UINT Count = 0, i, j;
94
95 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload",
96 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
97 {
98 dwSize = sizeof(szLayoutID);
99
100 while (RegEnumValue(hKey, dwIndex, szLayoutID, &dwSize, NULL, &dwType, NULL, NULL) == ERROR_SUCCESS)
101 {
102 dwSize = sizeof(szPreload);
103 RegQueryValueExW(hKey, szLayoutID, NULL, NULL, (LPBYTE)szPreload, &dwSize);
104
105 for (i = 4, j = 0; i < wcslen(szPreload)+1; i++, j++)
106 szLOLang[j] = szPreload[i];
107
108 if (wcscmp(szLOLang, szLang) == 0) Count += 1;
109
110 dwSize = sizeof(szLayoutID);
111 dwIndex++;
112 }
113
114 RegCloseKey(hKey);
115 }
116
117 return Count;
118 }
119
120 /* szLayoutID like 00000409, szLangID like 00000409 */
121 static BOOL
122 AddNewLayout(PWSTR szLayoutID, PWSTR szLangID)
123 {
124 WCHAR NewLayout[CCH_ULONG_DEC + 1], Lang[MAX_PATH],
125 LangID[CCH_LAYOUT_ID + 1], SubPath[CCH_LAYOUT_ID + 1];
126 HKEY hKey, hSubKey;
127 DWORD cValues;
128 LCID lcid;
129
130 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
131 {
132 if (RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &cValues, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
133 {
134 _ultow(cValues + 1, NewLayout, 10);
135
136 lcid = wcstoul(szLangID, NULL, 16);
137
138 GetLocaleInfoW(MAKELCID(lcid, SORT_DEFAULT), LOCALE_ILANGUAGE, Lang, sizeof(Lang) / sizeof(WCHAR));
139 wsprintf(LangID, L"0000%s", Lang);
140
141 if (IsLayoutExists(szLayoutID, LangID))
142 {
143 RegCloseKey(hKey);
144 return FALSE;
145 }
146
147 if (GetLayoutCount(Lang) >= 1)
148 {
149 wsprintf(SubPath, L"d%03d%s", GetLayoutCount(Lang), Lang);
150 }
151 else if ((wcscmp(LangID, szLayoutID) != 0) && (GetLayoutCount(Lang) == 0))
152 {
153 wsprintf(SubPath, L"d%03d%s", 0, Lang);
154 }
155 else SubPath[0] = L'\0';
156
157 if (wcslen(SubPath) != 0)
158 {
159 if (RegCreateKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Substitutes", 0, NULL,
160 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
161 NULL, &hSubKey, NULL) == ERROR_SUCCESS)
162 {
163 if (RegSetValueExW(hSubKey, SubPath, 0, REG_SZ, (LPBYTE)szLayoutID,
164 (DWORD)((CCH_LAYOUT_ID + 1) * sizeof(WCHAR))) != ERROR_SUCCESS)
165 {
166 RegCloseKey(hSubKey);
167 RegCloseKey(hKey);
168 return FALSE;
169 }
170 RegCloseKey(hSubKey);
171 }
172 lstrcpy(szLayoutID, SubPath);
173 }
174
175 RegSetValueExW(hKey,
176 NewLayout,
177 0,
178 REG_SZ,
179 (LPBYTE)szLayoutID,
180 (DWORD)((CCH_LAYOUT_ID + 1) * sizeof(WCHAR)));
181 }
182 RegCloseKey(hKey);
183 }
184
185 return TRUE;
186 }
187
188 VOID
189 AddNewKbLayoutsByLcid(LCID Lcid)
190 {
191 HINF hIntlInf;
192 WCHAR szLang[CCH_LAYOUT_ID + 1], szLangID[CCH_LAYOUT_ID + 1];
193 WCHAR szLangStr[MAX_STR_SIZE], szLayoutStr[MAX_STR_SIZE], szStr[MAX_STR_SIZE];
194 INFCONTEXT InfContext;
195 LONG Count;
196 DWORD FieldCount, Index;
197
198 GetLocaleInfoW(MAKELCID(Lcid, SORT_DEFAULT), LOCALE_ILANGUAGE, szLang, sizeof(szLang) / sizeof(WCHAR));
199 wsprintf(szLangID, L"0000%s", szLang);
200
201 hIntlInf = SetupOpenInfFileW(L"intl.inf", NULL, INF_STYLE_WIN4, NULL);
202
203 if (hIntlInf == INVALID_HANDLE_VALUE)
204 return;
205
206 if (!SetupOpenAppendInfFile(NULL, hIntlInf, NULL))
207 {
208 SetupCloseInfFile(hIntlInf);
209 hIntlInf = NULL;
210 return;
211 }
212
213 Count = SetupGetLineCount(hIntlInf, L"Locales");
214 if (Count <= 0) return;
215
216 if (SetupFindFirstLine(hIntlInf, L"Locales", szLangID, &InfContext))
217 {
218 FieldCount = SetupGetFieldCount(&InfContext);
219
220 if (FieldCount != 0)
221 {
222 for (Index = 5; Index <= FieldCount; Index++)
223 {
224 if (SetupGetStringField(&InfContext, Index, szStr, MAX_STR_SIZE, NULL))
225 {
226 INT i, j;
227
228 if (wcslen(szStr) != 13) continue;
229
230 wsprintf(szLangStr, L"0000%s", szStr);
231 szLangStr[8] = L'\0';
232
233 for (i = 5, j = 0; i <= wcslen(szStr); i++, j++)
234 szLayoutStr[j] = szStr[i];
235
236 AddNewLayout(szLayoutStr, szLangStr);
237 }
238 }
239 }
240 }
241 SetupCloseInfFile(hIntlInf);
242 }