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