[USB-BRINGUP-TRUNK]
[reactos.git] / 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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 "muifonts.h"
29 #include "muilanguages.h"
30
31 #define NDEBUG
32 #include <debug.h>
33
34 extern
35 VOID
36 PopupError(IN PCCH Text,
37 IN PCCH Status,
38 IN PINPUT_RECORD Ir,
39 IN ULONG WaitEvent);
40
41 static
42 ULONG
43 FindLanguageIndex(VOID)
44 {
45 ULONG lngIndex = 0;
46
47 if (SelectedLanguageId == NULL)
48 {
49 /* default to english */
50 return 0;
51 }
52
53 do
54 {
55 if (_wcsicmp(LanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
56 {
57 return lngIndex;
58 }
59
60 lngIndex++;
61 }while (LanguageList[lngIndex].MuiPages != NULL);
62
63 return 0;
64 }
65
66
67 static
68 const MUI_ENTRY *
69 FindMUIEntriesOfPage(IN ULONG PageNumber)
70 {
71 ULONG muiIndex = 0;
72 ULONG lngIndex;
73 const MUI_PAGE * Pages = NULL;
74
75 lngIndex = max(FindLanguageIndex(), 0);
76 Pages = LanguageList[lngIndex].MuiPages;
77
78 do
79 {
80 if (Pages[muiIndex].Number == PageNumber)
81 return Pages[muiIndex].MuiEntry;
82
83 muiIndex++;
84 }while (Pages[muiIndex].MuiEntry != NULL);
85
86 return NULL;
87 }
88
89 static
90 const MUI_ERROR *
91 FindMUIErrorEntries(VOID)
92 {
93 ULONG lngIndex = max(FindLanguageIndex(), 0);
94 return LanguageList[lngIndex].MuiErrors;
95 }
96
97 static
98 const MUI_STRING *
99 FindMUIStringEntries(VOID)
100 {
101 ULONG lngIndex = max(FindLanguageIndex(), 0);
102 return LanguageList[lngIndex].MuiStrings;
103 }
104
105 LPCWSTR
106 MUIDefaultKeyboardLayout(VOID)
107 {
108 ULONG lngIndex = max(FindLanguageIndex(), 0);
109 return LanguageList[lngIndex].MuiLayouts[0].LayoutID;
110 }
111
112 PWCHAR
113 MUIGetGeoID(VOID)
114 {
115 ULONG lngIndex = max(FindLanguageIndex(), 0);
116 return LanguageList[lngIndex].GeoID;
117 }
118
119 const MUI_LAYOUTS *
120 MUIGetLayoutsList(VOID)
121 {
122 ULONG lngIndex = max(FindLanguageIndex(), 0);
123 return LanguageList[lngIndex].MuiLayouts;
124 }
125
126 VOID
127 MUIClearPage(IN ULONG page)
128 {
129 const MUI_ENTRY * entry;
130 int index;
131
132 entry = FindMUIEntriesOfPage(page);
133 if (!entry)
134 {
135 PopupError("Error: Failed to find translated page",
136 NULL,
137 NULL,
138 POPUP_WAIT_NONE);
139 return;
140 }
141
142 index = 0;
143 do
144 {
145 CONSOLE_ClearStyledText(entry[index].X,
146 entry[index].Y,
147 entry[index].Flags,
148 strlen(entry[index].Buffer));
149 index++;
150 }
151 while (entry[index].Buffer != NULL);
152 }
153
154 VOID
155 MUIDisplayPage(IN ULONG page)
156 {
157 const MUI_ENTRY * entry;
158 int index;
159
160 entry = FindMUIEntriesOfPage(page);
161 if (!entry)
162 {
163 PopupError("Error: Failed to find translated page",
164 NULL,
165 NULL,
166 POPUP_WAIT_NONE);
167 return;
168 }
169
170 index = 0;
171 do
172 {
173 CONSOLE_SetStyledText(entry[index].X,
174 entry[index].Y,
175 entry[index].Flags,
176 entry[index].Buffer);
177
178 index++;
179 }
180 while (entry[index].Buffer != NULL);
181 }
182
183 VOID
184 MUIDisplayError(IN ULONG ErrorNum, OUT PINPUT_RECORD Ir, IN ULONG WaitEvent)
185 {
186 const MUI_ERROR * entry;
187
188 if (ErrorNum >= ERROR_LAST_ERROR_CODE)
189 {
190 PopupError("Invalid error number provided",
191 "Press ENTER to continue",
192 Ir,
193 POPUP_WAIT_ENTER);
194
195 return;
196 }
197
198 entry = FindMUIErrorEntries();
199 if (!entry)
200 {
201 PopupError("Error: Failed to find translated error message",
202 NULL,
203 NULL,
204 POPUP_WAIT_NONE);
205 return;
206 }
207
208 PopupError(entry[ErrorNum].ErrorText,
209 entry[ErrorNum].ErrorStatus,
210 Ir,
211 WaitEvent);
212 }
213
214 LPSTR
215 MUIGetString(ULONG Number)
216 {
217 ULONG i;
218 const MUI_STRING * entry;
219 CHAR szErr[100];
220
221 entry = FindMUIStringEntries();
222 if (entry)
223 {
224 for (i = 0; entry[i].Number != 0; i++)
225 {
226 if (entry[i].Number == Number)
227 {
228 return entry[i].String;
229 }
230 }
231 }
232
233 sprintf(szErr, "Error: failed find string id %lu for language index %lu\n", Number, FindLanguageIndex());
234
235 PopupError(szErr,
236 NULL,
237 NULL,
238 POPUP_WAIT_NONE);
239
240 return "<nostring>";
241 }
242
243 static BOOLEAN
244 AddHotkeySettings(IN LPCWSTR Hotkey, IN LPCWSTR LangHotkey, IN LPCWSTR LayoutHotkey)
245 {
246 OBJECT_ATTRIBUTES ObjectAttributes;
247 UNICODE_STRING KeyName;
248 UNICODE_STRING ValueName;
249 HANDLE KeyHandle;
250 ULONG Disposition;
251 NTSTATUS Status;
252
253 RtlInitUnicodeString(&KeyName,
254 L"\\Registry\\User\\.DEFAULT\\Keyboard Layout\\Toggle");
255 InitializeObjectAttributes(&ObjectAttributes,
256 &KeyName,
257 OBJ_CASE_INSENSITIVE,
258 NULL,
259 NULL);
260
261 Status = NtCreateKey(&KeyHandle,
262 KEY_SET_VALUE,
263 &ObjectAttributes,
264 0,
265 NULL,
266 0,
267 &Disposition);
268
269 if(!NT_SUCCESS(Status))
270 {
271 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
272 return FALSE;
273 }
274
275 RtlInitUnicodeString(&ValueName,
276 L"Hotkey");
277
278 Status = NtSetValueKey(KeyHandle,
279 &ValueName,
280 0,
281 REG_SZ,
282 (PVOID)Hotkey,
283 (1 + 1) * sizeof(WCHAR));
284 if (!NT_SUCCESS(Status))
285 {
286 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
287 NtClose(KeyHandle);
288 return FALSE;
289 }
290
291 RtlInitUnicodeString(&ValueName,
292 L"Language Hotkey");
293
294 Status = NtSetValueKey(KeyHandle,
295 &ValueName,
296 0,
297 REG_SZ,
298 (PVOID)LangHotkey,
299 (1 + 1) * sizeof(WCHAR));
300 if (!NT_SUCCESS(Status))
301 {
302 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
303 NtClose(KeyHandle);
304 return FALSE;
305 }
306
307 RtlInitUnicodeString(&ValueName,
308 L"Layout Hotkey");
309
310 Status = NtSetValueKey(KeyHandle,
311 &ValueName,
312 0,
313 REG_SZ,
314 (PVOID)LayoutHotkey,
315 (1 + 1) * sizeof(WCHAR));
316 if (!NT_SUCCESS(Status))
317 {
318 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
319 NtClose(KeyHandle);
320 return FALSE;
321 }
322
323 NtClose(KeyHandle);
324 return TRUE;
325 }
326
327 BOOLEAN
328 AddKbLayoutsToRegistry(IN const MUI_LAYOUTS * MuiLayouts)
329 {
330 OBJECT_ATTRIBUTES ObjectAttributes;
331 UNICODE_STRING KeyName;
332 UNICODE_STRING ValueName;
333 HANDLE KeyHandle;
334 HANDLE SubKeyHandle;
335 NTSTATUS Status;
336 ULONG Disposition;
337 ULONG uIndex = 0;
338 ULONG uCount = 0;
339 WCHAR szKeyName[48] = L"\\Registry\\User\\.DEFAULT\\Keyboard Layout";
340 WCHAR szValueName[3 + 1];
341 WCHAR szLangID[8 + 1];
342
343 // Open the keyboard layout key
344 RtlInitUnicodeString(&KeyName,
345 szKeyName);
346 InitializeObjectAttributes(&ObjectAttributes,
347 &KeyName,
348 OBJ_CASE_INSENSITIVE,
349 NULL,
350 NULL);
351
352 Status = NtCreateKey(&KeyHandle,
353 KEY_CREATE_SUB_KEY,
354 &ObjectAttributes,
355 0,
356 NULL,
357 0,
358 &Disposition);
359
360 if(NT_SUCCESS(Status))
361 NtClose(KeyHandle);
362 else
363 {
364 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
365 return FALSE;
366 }
367
368 KeyName.MaximumLength = sizeof(szKeyName);
369 Status = RtlAppendUnicodeToString(&KeyName, L"\\Preload");
370
371 if(!NT_SUCCESS(Status))
372 {
373 DPRINT1("RtlAppend failed! (%lx)\n", Status);
374 DPRINT1("String is %wZ\n", &KeyName);
375 return FALSE;
376 }
377
378 InitializeObjectAttributes(&ObjectAttributes,
379 &KeyName,
380 OBJ_CASE_INSENSITIVE,
381 NULL,
382 NULL);
383
384 Status = NtCreateKey(&KeyHandle,
385 KEY_SET_VALUE,
386 &ObjectAttributes,
387 0,
388 NULL,
389 0,
390 &Disposition);
391
392 if (!NT_SUCCESS(Status))
393 {
394 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
395 return FALSE;
396 }
397
398 RtlInitUnicodeString(&KeyName, L"\\Registry\\User\\.DEFAULT\\Keyboard Layout\\Substitutes");
399 InitializeObjectAttributes(&ObjectAttributes,
400 &KeyName,
401 OBJ_CASE_INSENSITIVE,
402 NULL,
403 NULL);
404
405 Status = NtCreateKey(&SubKeyHandle,
406 KEY_SET_VALUE,
407 &ObjectAttributes,
408 0,
409 NULL,
410 0,
411 &Disposition);
412
413 if(!NT_SUCCESS(Status))
414 {
415 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
416 NtClose(SubKeyHandle);
417 NtClose(KeyHandle);
418 return FALSE;
419 }
420
421 do
422 {
423 if (uIndex > 19) break;
424
425 swprintf(szValueName, L"%u", uIndex + 1);
426 RtlInitUnicodeString(&ValueName, szValueName);
427
428 swprintf(szLangID, L"0000%s", MuiLayouts[uIndex].LangID);
429
430 if (_wcsicmp(szLangID, MuiLayouts[uIndex].LayoutID) == 0)
431 {
432 Status = NtSetValueKey(KeyHandle,
433 &ValueName,
434 0,
435 REG_SZ,
436 (PVOID)MuiLayouts[uIndex].LayoutID,
437 (wcslen(MuiLayouts[uIndex].LayoutID)+1) * sizeof(WCHAR));
438 if (!NT_SUCCESS(Status))
439 {
440 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
441 NtClose(SubKeyHandle);
442 NtClose(KeyHandle);
443 return FALSE;
444 }
445 }
446 else
447 {
448 swprintf(szLangID, L"d%03u%s", uCount, MuiLayouts[uIndex].LangID);
449 Status = NtSetValueKey(KeyHandle,
450 &ValueName,
451 0,
452 REG_SZ,
453 (PVOID)szLangID,
454 (wcslen(szLangID)+1) * sizeof(WCHAR));
455 if (!NT_SUCCESS(Status))
456 {
457 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
458 NtClose(SubKeyHandle);
459 NtClose(KeyHandle);
460 return FALSE;
461 }
462
463 RtlInitUnicodeString(&ValueName, szLangID);
464
465 Status = NtSetValueKey(SubKeyHandle,
466 &ValueName,
467 0,
468 REG_SZ,
469 (PVOID)MuiLayouts[uIndex].LayoutID,
470 (wcslen(MuiLayouts[uIndex].LayoutID)+1) * sizeof(WCHAR));
471 if (!NT_SUCCESS(Status))
472 {
473 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %u)\n", Status, uIndex);
474 NtClose(SubKeyHandle);
475 NtClose(KeyHandle);
476 return FALSE;
477 }
478
479 uCount++;
480 }
481
482 uIndex++;
483 }
484 while (MuiLayouts[uIndex].LangID != NULL);
485
486 if (uIndex > 1)
487 AddHotkeySettings(L"2", L"2", L"1");
488 else
489 AddHotkeySettings(L"3", L"3", L"3");
490
491 NtClose(SubKeyHandle);
492 NtClose(KeyHandle);
493 return TRUE;
494 }
495
496 BOOLEAN
497 AddKeyboardLayouts(VOID)
498 {
499 ULONG lngIndex = 0;
500 do
501 {
502 if (_wcsicmp(LanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
503 {
504 return AddKbLayoutsToRegistry(LanguageList[lngIndex].MuiLayouts);
505 }
506
507 lngIndex++;
508 }
509 while (LanguageList[lngIndex].MuiPages != NULL);
510
511 return FALSE;
512 }
513
514 static BOOLEAN
515 AddCodepageToRegistry(IN LPCWSTR ACPage, IN LPCWSTR OEMCPage, IN LPCWSTR MACCPage)
516 {
517 OBJECT_ATTRIBUTES ObjectAttributes;
518 UNICODE_STRING KeyName;
519 UNICODE_STRING ValueName;
520 HANDLE KeyHandle;
521 NTSTATUS Status;
522
523 // Open the nls codepage key
524 RtlInitUnicodeString(&KeyName,
525 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage");
526 InitializeObjectAttributes(&ObjectAttributes,
527 &KeyName,
528 OBJ_CASE_INSENSITIVE,
529 NULL,
530 NULL);
531 Status = NtOpenKey(&KeyHandle,
532 KEY_WRITE,
533 &ObjectAttributes);
534 if (!NT_SUCCESS(Status))
535 {
536 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
537 return FALSE;
538 }
539
540 // Set ANSI codepage
541 RtlInitUnicodeString(&ValueName, L"ACP");
542 Status = NtSetValueKey(KeyHandle,
543 &ValueName,
544 0,
545 REG_SZ,
546 (PVOID)ACPage,
547 (wcslen(ACPage)+1) * sizeof(WCHAR));
548 if (!NT_SUCCESS(Status))
549 {
550 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
551 NtClose(KeyHandle);
552 return FALSE;
553 }
554
555 // Set OEM codepage
556 RtlInitUnicodeString(&ValueName, L"OEMCP");
557 Status = NtSetValueKey(KeyHandle,
558 &ValueName,
559 0,
560 REG_SZ,
561 (PVOID)OEMCPage,
562 (wcslen(OEMCPage)+1) * sizeof(WCHAR));
563 if (!NT_SUCCESS(Status))
564 {
565 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
566 NtClose(KeyHandle);
567 return FALSE;
568 }
569
570 // Set MAC codepage
571 RtlInitUnicodeString(&ValueName, L"MACCP");
572 Status = NtSetValueKey(KeyHandle,
573 &ValueName,
574 0,
575 REG_SZ,
576 (PVOID)MACCPage,
577 (wcslen(MACCPage)+1) * sizeof(WCHAR));
578 if (!NT_SUCCESS(Status))
579 {
580 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
581 NtClose(KeyHandle);
582 return FALSE;
583 }
584
585 NtClose(KeyHandle);
586
587 return TRUE;
588 }
589
590 static BOOLEAN
591 AddFontsSettingsToRegistry(IN const MUI_SUBFONT * MuiSubFonts)
592 {
593 OBJECT_ATTRIBUTES ObjectAttributes;
594 UNICODE_STRING KeyName;
595 UNICODE_STRING ValueName;
596 HANDLE KeyHandle;
597 NTSTATUS Status;
598 ULONG uIndex = 0;
599
600 RtlInitUnicodeString(&KeyName,
601 L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SysFontSubstitutes");
602 InitializeObjectAttributes(&ObjectAttributes,
603 &KeyName,
604 OBJ_CASE_INSENSITIVE,
605 NULL,
606 NULL);
607 Status = NtOpenKey(&KeyHandle,
608 KEY_WRITE,
609 &ObjectAttributes);
610 if (!NT_SUCCESS(Status))
611 {
612 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
613 return FALSE;
614 }
615
616 do
617 {
618 RtlInitUnicodeString(&ValueName, MuiSubFonts[uIndex].FontName);
619 Status = NtSetValueKey(KeyHandle,
620 &ValueName,
621 0,
622 REG_SZ,
623 (PVOID)MuiSubFonts[uIndex].SubFontName,
624 (wcslen(MuiSubFonts[uIndex].SubFontName)+1) * sizeof(WCHAR));
625 if (!NT_SUCCESS(Status))
626 {
627 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
628 NtClose(KeyHandle);
629 return FALSE;
630 }
631
632 uIndex++;
633 }
634 while (MuiSubFonts[uIndex].FontName != NULL);
635
636 NtClose(KeyHandle);
637
638 return TRUE;
639 }
640
641 BOOLEAN
642 AddCodePage(VOID)
643 {
644 ULONG lngIndex = 0;
645 do
646 {
647 if (_wcsicmp(LanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
648 {
649 if (AddCodepageToRegistry(LanguageList[lngIndex].ACPage,
650 LanguageList[lngIndex].OEMCPage,
651 LanguageList[lngIndex].MACCPage)&&
652 AddFontsSettingsToRegistry(LanguageList[lngIndex].MuiSubFonts))
653 {
654 return TRUE;
655 }
656 else
657 {
658 return FALSE;
659 }
660 }
661
662 lngIndex++;
663 }
664 while (LanguageList[lngIndex].MuiPages != NULL);
665
666 return FALSE;
667 }
668
669 VOID
670 SetConsoleCodePage(VOID)
671 {
672 ULONG lngIndex = 0;
673 UINT wCodePage;
674
675 do
676 {
677 if (_wcsicmp(LanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
678 {
679 wCodePage = (UINT) wcstoul(LanguageList[lngIndex].OEMCPage, NULL, 10);
680 SetConsoleOutputCP(wCodePage);
681 return;
682 }
683
684 lngIndex++;
685 }
686 while (LanguageList[lngIndex].MuiPages != NULL);
687 }
688
689 /* EOF */