- Set catalan default keyboard layout to spanish (no specific catalan kb layout exists)
[reactos.git] / reactos / base / setup / usetup / mui.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2008 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: subsys/system/usetup/mui.c
23 * PURPOSE: Text-mode setup
24 * PROGRAMMER:
25 */
26
27 #include "usetup.h"
28 #include "interface/consup.h"
29 #include "errorcode.h"
30 #include "mui.h"
31
32 #define NDEBUG
33 #include <debug.h>
34
35 #include "lang/bg-BG.h"
36 #include "lang/cs-CZ.h"
37 #include "lang/en-US.h"
38 #include "lang/de-DE.h"
39 #include "lang/el-GR.h"
40 #include "lang/es-ES.h"
41 #include "lang/fr-FR.h"
42 #include "lang/it-IT.h"
43 #include "lang/pl-PL.h"
44 #include "lang/ru-RU.h"
45 #include "lang/sk-SK.h"
46 #include "lang/sv-SE.h"
47 #include "lang/uk-UA.h"
48 #include "lang/lt-LT.h"
49
50 static const MUI_LANGUAGE LanguageList[] =
51 {
52 /* Lang ID, DefKbdLayout, SecKbLayout, ANSI CP, OEM CP, MAC CP, Language Name, page strgs,error strings, other strings */
53 {L"00000409", L"00000409", NULL, L"1252", L"437", L"10000", L"English", enUSPages, enUSErrorEntries, enUSStrings },
54 {L"0000041C", L"0000041C", L"00000409", L"1250", L"852", L"10029", L"Albanian", enUSPages, enUSErrorEntries, enUSStrings },
55 {L"00000401", L"00000401", L"00000409", L"1256", L"720", L"10004", L"Arabic", enUSPages, enUSErrorEntries, enUSStrings },
56 {L"0000042B", L"0000042B", L"00000409", L"0", L"1", L"2", L"Armenian Eastern", enUSPages, enUSErrorEntries, enUSStrings },
57 {L"0000082C", L"0000082C", L"00000409", L"1251", L"866", L"10007", L"Azeri Cyrillic", enUSPages, enUSErrorEntries, enUSStrings },
58 {L"0000042C", L"0000042C", L"00000409", L"1254", L"857", L"10081", L"Azeri Latin", enUSPages, enUSErrorEntries, enUSStrings },
59 {L"00000423", L"00000423", L"00000409", L"1251", L"866", L"10007", L"Belarusian", enUSPages, enUSErrorEntries, enUSStrings },
60 {L"00000813", L"00000813", L"00000409", L"1252", L"850", L"10000", L"Belgian (Dutch)", enUSPages, enUSErrorEntries, enUSStrings },
61 {L"0000080C", L"0000080C", L"00000409", L"1252", L"850", L"10000", L"Belgian (French)", enUSPages, enUSErrorEntries, enUSStrings },
62 {L"00000416", L"00010416", L"00000409", L"1252", L"850", L"10000", L"Brazilian", enUSPages, enUSErrorEntries, enUSStrings },
63 {L"00000402", L"00000402", L"00000409", L"1251", L"866", L"10007", L"Bulgarian", bgBGPages, bgBGErrorEntries, bgBGStrings },
64 {L"00000455", L"00000455", L"00000409", L"0", L"1", L"2", L"Burmese", enUSPages, enUSErrorEntries, enUSStrings },// Unicode only
65 {L"00000C0C", L"00000C0C", L"00000409", L"1252", L"850", L"10000", L"Canadian (French)", enUSPages, enUSErrorEntries, enUSStrings },
66 {L"00000403", L"0000040A", L"00000409", L"1252", L"850", L"10000", L"Catalan", enUSPages, enUSErrorEntries, enUSStrings },
67 {L"00000804", L"00000804", L"00000409", L"936", L"936", L"10008", L"Chinese (PRC)", enUSPages, enUSErrorEntries, enUSStrings },
68 {L"00000405", L"00000405", L"00000409", L"1250", L"852", L"10029", L"Czech", csCZPages, csCZErrorEntries, csCZStrings },
69 {L"00000406", L"00000406", L"00000409", L"1252", L"850", L"10000", L"Danish", enUSPages, enUSErrorEntries, enUSStrings },
70 {L"00000407", L"00000407", L"00000409", L"1252", L"850", L"10000", L"Deutsch", deDEPages, deDEErrorEntries, deDEStrings },
71 {L"00000413", L"00000813", L"00000409", L"1252", L"850", L"10000", L"Dutch", enUSPages, enUSErrorEntries, enUSStrings },
72 {L"00000425", L"00000425", L"00000409", L"1257", L"775", L"10029", L"Estonian", enUSPages, enUSErrorEntries, enUSStrings },
73 {L"0000040B", L"0000040B", L"00000409", L"1252", L"850", L"10000", L"Finnish", enUSPages, enUSErrorEntries, enUSStrings },
74 {L"0000040C", L"0000040C", L"00000409", L"1252", L"850", L"10000", L"French", frFRPages, frFRErrorEntries, frFRStrings },
75 {L"00000437", L"00000437", L"00000409", L"0", L"1", L"2", L"Georgian", enUSPages, enUSErrorEntries, enUSStrings },// Unicode only
76 {L"00000408", L"00000408", L"00000409", L"1253", L"737", L"10006", L"Greek", elGRPages, elGRErrorEntries, elGRStrings },
77 {L"0000040D", L"0000040D", L"00000409", L"1255", L"862", L"10005", L"Hebrew", enUSPages, enUSErrorEntries, enUSStrings },
78 {L"0000040E", L"0000040E", L"00000409", L"1250", L"852", L"10029", L"Hungarian", enUSPages, enUSErrorEntries, enUSStrings },
79 {L"0000040F", L"0000040F", L"00000409", L"1252", L"850", L"10079", L"Icelandic", enUSPages, enUSErrorEntries, enUSStrings },
80 {L"00000410", L"00000410", L"00000409", L"1252", L"850", L"10000", L"Italian", itITPages, itITErrorEntries, itITStrings },
81 {L"00000411", L"00000411", L"00000409", L"932", L"932", L"10001", L"Japanese", enUSPages, enUSErrorEntries, enUSStrings },
82 {L"0000043F", L"0000043F", L"00000409", L"1251", L"866", L"10007", L"Kazakh", enUSPages, enUSErrorEntries, enUSStrings },
83 {L"00000412", L"00000412", L"00000409", L"949", L"949", L"10003", L"Korean", enUSPages, enUSErrorEntries, enUSStrings },
84 {L"00000426", L"00000426", L"00000409", L"1257", L"775", L"10029", L"Latvian", enUSPages, enUSErrorEntries, enUSStrings },
85 {L"00000427", L"00000427", L"00000409", L"1257", L"775", L"10029", L"Lithuanian", ltLTPages, ltLTErrorEntries, ltLTStrings },
86 {L"0000042F", L"0000042F", L"00000409", L"1251", L"866", L"10007", L"Macedonian", enUSPages, enUSErrorEntries, enUSStrings },
87 {L"00000414", L"00000414", L"00000409", L"1252", L"850", L"10000", L"Norwegian", enUSPages, enUSErrorEntries, enUSStrings },
88 {L"00000418", L"00000418", L"00000409", L"1250", L"852", L"10029", L"Romanian", enUSPages, enUSErrorEntries, enUSStrings },
89 {L"00000419", L"00000419", L"00000409", L"1251", L"866", L"10007", L"Russkij", ruRUPages, ruRUErrorEntries, ruRUStrings },
90 {L"00000415", L"00000415", L"00000409", L"1250", L"852", L"10029", L"Polski", plPLPages, plPLErrorEntries, plPLStrings },
91 {L"00000816", L"00000816", L"00000409", L"1252", L"850", L"10000", L"Portuguese", enUSPages, enUSErrorEntries, enUSStrings },
92 {L"00000C1A", L"00000C1A", L"00000409", L"1251", L"855", L"10007", L"Serbian (Cyrillic)",enUSPages, enUSErrorEntries, enUSStrings },
93 {L"0000081A", L"0000081A", L"00000409", L"1250", L"852", L"10029", L"Serbian (Latin)", enUSPages, enUSErrorEntries, enUSStrings },
94 {L"0000041B", L"0000041B", L"00000409", L"1250", L"852", L"10029", L"Slovak", skSKPages, skSKErrorEntries, skSKStrings },
95 {L"0000040A", L"0000040A", L"00000409", L"1252", L"850", L"10000", L"Spanish", esESPages, esESErrorEntries, esESStrings },
96 {L"00000807", L"00000807", L"00000409", L"1252", L"850", L"10000", L"Swiss (German)", enUSPages, enUSErrorEntries, enUSStrings },
97 {L"0000041D", L"0000041D", L"00000409", L"1252", L"850", L"10000", L"Swedish", svSEPages, svSEErrorEntries, svSEStrings },
98 {L"00000444", L"00000444", L"00000409", L"1251", L"866", L"10007", L"Tatar", enUSPages, enUSErrorEntries, enUSStrings },
99 {L"0000041E", L"0000041E", L"00000409", L"874", L"874", L"10021", L"Thai", enUSPages, enUSErrorEntries, enUSStrings },
100 {L"0000041F", L"0000041F", L"00000409", L"1254", L"857", L"10081", L"Turkish", enUSPages, enUSErrorEntries, enUSStrings },
101 {L"00000422", L"00000422", L"00000409", L"1251", L"866", L"10017", L"Ukrainian", ukUAPages, ukUAErrorEntries, ukUAStrings },
102 {L"00000809", L"00000809", L"00000409", L"1252", L"850", L"10000", L"United Kingdom", enUSPages, enUSErrorEntries, enUSStrings },
103 {L"00000843", L"00000843", L"00000409", L"1251", L"866", L"10007", L"Uzbek", enUSPages, enUSErrorEntries, enUSStrings },
104 {L"0000042A", L"0000042A", L"00000409", L"1258", L"1258",L"10000", L"Vietnamese", enUSPages, enUSErrorEntries, enUSStrings },
105 {NULL, NULL, NULL, NULL, NULL, NULL}
106 };
107
108 extern
109 VOID
110 PopupError(IN PCCH Text,
111 IN PCCH Status,
112 IN PINPUT_RECORD Ir,
113 IN ULONG WaitEvent);
114
115 static
116 ULONG
117 FindLanguageIndex()
118 {
119 ULONG lngIndex = 0;
120
121 if (SelectedLanguageId == NULL)
122 {
123 /* default to english */
124 return 0;
125 }
126
127 do
128 {
129 if (_wcsicmp(LanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
130 {
131 return lngIndex;
132 }
133
134 lngIndex++;
135 }while (LanguageList[lngIndex].MuiPages != NULL);
136
137 return 0;
138 }
139
140
141 static
142 const MUI_ENTRY *
143 FindMUIEntriesOfPage(IN ULONG PageNumber)
144 {
145 ULONG muiIndex = 0;
146 ULONG lngIndex;
147 const MUI_PAGE * Pages = NULL;
148
149 lngIndex = max(FindLanguageIndex(), 0);
150 Pages = LanguageList[lngIndex].MuiPages;
151
152 do
153 {
154 if (Pages[muiIndex].Number == PageNumber)
155 return Pages[muiIndex].MuiEntry;
156
157 muiIndex++;
158 }while (Pages[muiIndex].MuiEntry != NULL);
159
160 return NULL;
161 }
162
163 static
164 const MUI_ERROR *
165 FindMUIErrorEntries(VOID)
166 {
167 ULONG lngIndex = max(FindLanguageIndex(), 0);
168 return LanguageList[lngIndex].MuiErrors;
169 }
170
171 static
172 const MUI_STRING *
173 FindMUIStringEntries(VOID)
174 {
175 ULONG lngIndex = max(FindLanguageIndex(), 0);
176 return LanguageList[lngIndex].MuiStrings;
177 }
178
179 LPCWSTR
180 MUIDefaultKeyboardLayout(VOID)
181 {
182 ULONG lngIndex = max(FindLanguageIndex(), 0);
183 return LanguageList[lngIndex].LanguageKeyboardLayoutID;
184 }
185
186 VOID
187 MUIDisplayPage(IN ULONG page)
188 {
189 const MUI_ENTRY * entry;
190 int index;
191
192 entry = FindMUIEntriesOfPage(page);
193 if (!entry)
194 {
195 PopupError("Error: Failed to find translated page",
196 NULL,
197 NULL,
198 POPUP_WAIT_NONE);
199 return;
200 }
201
202 index = 0;
203 do
204 {
205 CONSOLE_SetStyledText (
206 entry[index].X,
207 entry[index].Y,
208 entry[index].Flags,
209 entry[index].Buffer);
210
211 index++;
212 }
213 while (entry[index].Buffer != NULL);
214 }
215
216 VOID
217 MUIDisplayError(IN ULONG ErrorNum, OUT PINPUT_RECORD Ir, IN ULONG WaitEvent)
218 {
219 const MUI_ERROR * entry;
220
221 if (ErrorNum >= ERROR_LAST_ERROR_CODE)
222 {
223 PopupError("Invalid error number provided",
224 "Press ENTER to continue",
225 Ir,
226 POPUP_WAIT_ENTER);
227
228 return;
229 }
230
231 entry = FindMUIErrorEntries();
232 if (!entry)
233 {
234 PopupError("Error: Failed to find translated error message",
235 NULL,
236 NULL,
237 POPUP_WAIT_NONE);
238 return;
239 }
240
241 PopupError(entry[ErrorNum].ErrorText,
242 entry[ErrorNum].ErrorStatus,
243 Ir,
244 WaitEvent);
245 }
246
247 LPSTR
248 MUIGetString(ULONG Number)
249 {
250 ULONG i;
251 const MUI_STRING * entry;
252 CHAR szErr[100];
253
254 entry = FindMUIStringEntries();
255 if (entry)
256 {
257 for (i = 0; entry[i].Number != 0; i++)
258 {
259 if (entry[i].Number == Number)
260 {
261 return entry[i].String;
262 }
263 }
264 }
265
266 sprintf(szErr, "Error: failed find string id %lu for language index %lu\n", Number, FindLanguageIndex());
267
268 PopupError(szErr,
269 NULL,
270 NULL,
271 POPUP_WAIT_NONE);
272
273 return "<nostring>";
274 }
275
276 static BOOLEAN
277 AddKbLayoutsToRegistry(IN LPCWSTR DefKbLayout, IN LPCWSTR SecKbLayout)
278 {
279 OBJECT_ATTRIBUTES ObjectAttributes;
280 UNICODE_STRING KeyName;
281 UNICODE_STRING ValueName;
282 HANDLE KeyHandle;
283 NTSTATUS Status;
284 ULONG Disposition;
285 WCHAR szKeyName[48] = L"\\Registry\\User\\.DEFAULT\\Keyboard Layout";
286
287 // Open the keyboard layout key
288 RtlInitUnicodeString(&KeyName,
289 szKeyName);
290 InitializeObjectAttributes(&ObjectAttributes,
291 &KeyName,
292 OBJ_CASE_INSENSITIVE,
293 NULL,
294 NULL);
295
296 Status = NtCreateKey(&KeyHandle,
297 KEY_ALL_ACCESS,
298 &ObjectAttributes,
299 0,
300 NULL,
301 0,
302 &Disposition);
303
304 if(NT_SUCCESS(Status))
305 NtClose(KeyHandle);
306 else
307 {
308 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
309 return FALSE;
310 }
311
312 KeyName.MaximumLength = sizeof(szKeyName);
313 Status = RtlAppendUnicodeToString(&KeyName, L"\\Preload");
314
315 if(!NT_SUCCESS(Status))
316 {
317 DPRINT1("RtlAppend failed! (%lx)\n", Status);
318 DPRINT1("String is %wZ\n", &KeyName);
319 return FALSE;
320 }
321
322 InitializeObjectAttributes(&ObjectAttributes,
323 &KeyName,
324 OBJ_CASE_INSENSITIVE,
325 NULL,
326 NULL);
327
328 Status = NtCreateKey(&KeyHandle,
329 KEY_ALL_ACCESS,
330 &ObjectAttributes,
331 0,
332 NULL,
333 0,
334 &Disposition);
335
336 if (!NT_SUCCESS(Status))
337 {
338 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
339 return FALSE;
340 }
341
342 /* Set def keyboard layout */
343 RtlInitUnicodeString(&ValueName,
344 L"1");
345
346 Status = NtSetValueKey(KeyHandle,
347 &ValueName,
348 0,
349 REG_SZ,
350 (PVOID)DefKbLayout,
351 (8 + 1) * sizeof(WCHAR));
352 if (!NT_SUCCESS(Status))
353 {
354 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
355 NtClose(KeyHandle);
356 return FALSE;
357 }
358
359 if (SecKbLayout != NULL)
360 {
361 /* Set second keyboard layout */
362 RtlInitUnicodeString(&ValueName,
363 L"2");
364
365 Status = NtSetValueKey(KeyHandle,
366 &ValueName,
367 0,
368 REG_SZ,
369 (PVOID)SecKbLayout,
370 (8 + 1) * sizeof(WCHAR));
371 if (!NT_SUCCESS(Status))
372 {
373 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
374 NtClose(KeyHandle);
375 return FALSE;
376 }
377 }
378
379 NtClose(KeyHandle);
380 return TRUE;
381 }
382
383 BOOLEAN
384 AddKeyboardLayouts(VOID)
385 {
386 ULONG lngIndex = 0;
387 do
388 {
389 if (_wcsicmp(LanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
390 {
391 return AddKbLayoutsToRegistry(LanguageList[lngIndex].LanguageKeyboardLayoutID,
392 LanguageList[lngIndex].SecondLangKbLayoutID);
393 }
394
395 lngIndex++;
396 }
397 while (LanguageList[lngIndex].MuiPages != NULL);
398
399 return FALSE;
400 }
401
402 static BOOLEAN
403 AddCodepageToRegistry(IN LPCWSTR ACPage, IN LPCWSTR OEMCPage, IN LPCWSTR MACCPage)
404 {
405 OBJECT_ATTRIBUTES ObjectAttributes;
406 UNICODE_STRING KeyName;
407 UNICODE_STRING ValueName;
408 HANDLE KeyHandle;
409 NTSTATUS Status;
410
411 // Open the nls codepage key
412 RtlInitUnicodeString(&KeyName,
413 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage");
414 InitializeObjectAttributes(&ObjectAttributes,
415 &KeyName,
416 OBJ_CASE_INSENSITIVE,
417 NULL,
418 NULL);
419 Status = NtOpenKey(&KeyHandle,
420 KEY_WRITE,
421 &ObjectAttributes);
422 if (!NT_SUCCESS(Status))
423 {
424 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
425 return FALSE;
426 }
427
428 // Set ANSI codepage
429 RtlInitUnicodeString(&ValueName, L"ACP");
430 Status = NtSetValueKey(KeyHandle,
431 &ValueName,
432 0,
433 REG_SZ,
434 (PVOID)ACPage,
435 wcslen(ACPage) * sizeof(PWCHAR));
436 if (!NT_SUCCESS(Status))
437 {
438 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
439 NtClose(KeyHandle);
440 return FALSE;
441 }
442
443 // Set OEM codepage
444 RtlInitUnicodeString(&ValueName, L"OEMCP");
445 Status = NtSetValueKey(KeyHandle,
446 &ValueName,
447 0,
448 REG_SZ,
449 (PVOID)OEMCPage,
450 wcslen(OEMCPage) * sizeof(PWCHAR));
451 if (!NT_SUCCESS(Status))
452 {
453 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
454 NtClose(KeyHandle);
455 return FALSE;
456 }
457
458 // Set MAC codepage
459 RtlInitUnicodeString(&ValueName, L"MACCP");
460 Status = NtSetValueKey(KeyHandle,
461 &ValueName,
462 0,
463 REG_SZ,
464 (PVOID)MACCPage,
465 wcslen(MACCPage) * sizeof(PWCHAR));
466 if (!NT_SUCCESS(Status))
467 {
468 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
469 NtClose(KeyHandle);
470 return FALSE;
471 }
472
473 NtClose(KeyHandle);
474
475 return TRUE;
476 }
477
478 BOOLEAN
479 AddCodePage(VOID)
480 {
481 ULONG lngIndex = 0;
482 do
483 {
484 if (_wcsicmp(LanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
485 {
486 return AddCodepageToRegistry(LanguageList[lngIndex].ACPage,
487 LanguageList[lngIndex].OEMCPage,
488 LanguageList[lngIndex].MACCPage);
489 }
490
491 lngIndex++;
492 }
493 while (LanguageList[lngIndex].MuiPages != NULL);
494
495 return FALSE;
496 }
497
498 VOID
499 SetConsoleCodePage(VOID)
500 {
501 ULONG lngIndex = 0;
502 UINT wCodePage;
503
504 do
505 {
506 if (_wcsicmp(LanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
507 {
508 wCodePage = (UINT) wcstoul(LanguageList[lngIndex].OEMCPage, NULL, 10);
509 SetConsoleOutputCP(wCodePage);
510 return;
511 }
512
513 lngIndex++;
514 }
515 while (LanguageList[lngIndex].MuiPages != NULL);
516 }
517
518 /* EOF */