Sync with trunk r63270.
[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 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 const MUI_ERROR * entry;
219
220 if (ErrorNum >= ERROR_LAST_ERROR_CODE)
221 {
222 PopupError("Invalid error number provided",
223 "Press ENTER to continue",
224 Ir,
225 POPUP_WAIT_ENTER);
226
227 return;
228 }
229
230 entry = FindMUIErrorEntries();
231 if (!entry)
232 {
233 PopupError("Error: Failed to find translated error message",
234 NULL,
235 NULL,
236 POPUP_WAIT_NONE);
237 return;
238 }
239
240 PopupError(entry[ErrorNum].ErrorText,
241 entry[ErrorNum].ErrorStatus,
242 Ir,
243 WaitEvent);
244 }
245
246
247 LPSTR
248 MUIGetString(
249 ULONG Number)
250 {
251 ULONG i;
252 const MUI_STRING * entry;
253 CHAR szErr[100];
254
255 entry = FindMUIStringEntries();
256 if (entry)
257 {
258 for (i = 0; entry[i].Number != 0; i++)
259 {
260 if (entry[i].Number == Number)
261 {
262 return entry[i].String;
263 }
264 }
265 }
266
267 sprintf(szErr, "Error: failed find string id %lu for language index %lu\n", Number, FindLanguageIndex());
268
269 PopupError(szErr,
270 NULL,
271 NULL,
272 POPUP_WAIT_NONE);
273
274 return "<nostring>";
275 }
276
277
278 static
279 BOOLEAN
280 AddHotkeySettings(
281 IN LPCWSTR Hotkey,
282 IN LPCWSTR LangHotkey,
283 IN LPCWSTR LayoutHotkey)
284 {
285 OBJECT_ATTRIBUTES ObjectAttributes;
286 UNICODE_STRING KeyName;
287 UNICODE_STRING ValueName;
288 HANDLE KeyHandle;
289 ULONG Disposition;
290 NTSTATUS Status;
291
292 RtlInitUnicodeString(&KeyName,
293 L"\\Registry\\User\\.DEFAULT\\Keyboard Layout\\Toggle");
294 InitializeObjectAttributes(&ObjectAttributes,
295 &KeyName,
296 OBJ_CASE_INSENSITIVE,
297 NULL,
298 NULL);
299
300 Status = NtCreateKey(&KeyHandle,
301 KEY_SET_VALUE,
302 &ObjectAttributes,
303 0,
304 NULL,
305 0,
306 &Disposition);
307
308 if(!NT_SUCCESS(Status))
309 {
310 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
311 return FALSE;
312 }
313
314 RtlInitUnicodeString(&ValueName,
315 L"Hotkey");
316
317 Status = NtSetValueKey(KeyHandle,
318 &ValueName,
319 0,
320 REG_SZ,
321 (PVOID)Hotkey,
322 (1 + 1) * sizeof(WCHAR));
323 if (!NT_SUCCESS(Status))
324 {
325 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
326 NtClose(KeyHandle);
327 return FALSE;
328 }
329
330 RtlInitUnicodeString(&ValueName,
331 L"Language Hotkey");
332
333 Status = NtSetValueKey(KeyHandle,
334 &ValueName,
335 0,
336 REG_SZ,
337 (PVOID)LangHotkey,
338 (1 + 1) * sizeof(WCHAR));
339 if (!NT_SUCCESS(Status))
340 {
341 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
342 NtClose(KeyHandle);
343 return FALSE;
344 }
345
346 RtlInitUnicodeString(&ValueName,
347 L"Layout Hotkey");
348
349 Status = NtSetValueKey(KeyHandle,
350 &ValueName,
351 0,
352 REG_SZ,
353 (PVOID)LayoutHotkey,
354 (1 + 1) * sizeof(WCHAR));
355 if (!NT_SUCCESS(Status))
356 {
357 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
358 NtClose(KeyHandle);
359 return FALSE;
360 }
361
362 NtClose(KeyHandle);
363 return TRUE;
364 }
365
366
367 BOOLEAN
368 AddKbLayoutsToRegistry(
369 IN const MUI_LAYOUTS *MuiLayouts)
370 {
371 OBJECT_ATTRIBUTES ObjectAttributes;
372 UNICODE_STRING KeyName;
373 UNICODE_STRING ValueName;
374 HANDLE KeyHandle;
375 HANDLE SubKeyHandle;
376 NTSTATUS Status;
377 ULONG Disposition;
378 ULONG uIndex = 0;
379 ULONG uCount = 0;
380 WCHAR szKeyName[48] = L"\\Registry\\User\\.DEFAULT\\Keyboard Layout";
381 WCHAR szValueName[3 + 1];
382 WCHAR szLangID[8 + 1];
383
384 // Open the keyboard layout key
385 RtlInitUnicodeString(&KeyName,
386 szKeyName);
387 InitializeObjectAttributes(&ObjectAttributes,
388 &KeyName,
389 OBJ_CASE_INSENSITIVE,
390 NULL,
391 NULL);
392
393 Status = NtCreateKey(&KeyHandle,
394 KEY_CREATE_SUB_KEY,
395 &ObjectAttributes,
396 0,
397 NULL,
398 0,
399 &Disposition);
400
401 if(NT_SUCCESS(Status))
402 NtClose(KeyHandle);
403 else
404 {
405 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
406 return FALSE;
407 }
408
409 KeyName.MaximumLength = sizeof(szKeyName);
410 Status = RtlAppendUnicodeToString(&KeyName, L"\\Preload");
411
412 if(!NT_SUCCESS(Status))
413 {
414 DPRINT1("RtlAppend failed! (%lx)\n", Status);
415 DPRINT1("String is %wZ\n", &KeyName);
416 return FALSE;
417 }
418
419 InitializeObjectAttributes(&ObjectAttributes,
420 &KeyName,
421 OBJ_CASE_INSENSITIVE,
422 NULL,
423 NULL);
424
425 Status = NtCreateKey(&KeyHandle,
426 KEY_SET_VALUE,
427 &ObjectAttributes,
428 0,
429 NULL,
430 0,
431 &Disposition);
432
433 if (!NT_SUCCESS(Status))
434 {
435 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
436 return FALSE;
437 }
438
439 RtlInitUnicodeString(&KeyName, L"\\Registry\\User\\.DEFAULT\\Keyboard Layout\\Substitutes");
440 InitializeObjectAttributes(&ObjectAttributes,
441 &KeyName,
442 OBJ_CASE_INSENSITIVE,
443 NULL,
444 NULL);
445
446 Status = NtCreateKey(&SubKeyHandle,
447 KEY_SET_VALUE,
448 &ObjectAttributes,
449 0,
450 NULL,
451 0,
452 &Disposition);
453
454 if(!NT_SUCCESS(Status))
455 {
456 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
457 NtClose(SubKeyHandle);
458 NtClose(KeyHandle);
459 return FALSE;
460 }
461
462 do
463 {
464 if (uIndex > 19) break;
465
466 swprintf(szValueName, L"%u", uIndex + 1);
467 RtlInitUnicodeString(&ValueName, szValueName);
468
469 swprintf(szLangID, L"0000%s", MuiLayouts[uIndex].LangID);
470
471 if (_wcsicmp(szLangID, MuiLayouts[uIndex].LayoutID) == 0)
472 {
473 Status = NtSetValueKey(KeyHandle,
474 &ValueName,
475 0,
476 REG_SZ,
477 (PVOID)MuiLayouts[uIndex].LayoutID,
478 (wcslen(MuiLayouts[uIndex].LayoutID)+1) * sizeof(WCHAR));
479 if (!NT_SUCCESS(Status))
480 {
481 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
482 NtClose(SubKeyHandle);
483 NtClose(KeyHandle);
484 return FALSE;
485 }
486 }
487 else
488 {
489 swprintf(szLangID, L"d%03lu%s", uCount, MuiLayouts[uIndex].LangID);
490 Status = NtSetValueKey(KeyHandle,
491 &ValueName,
492 0,
493 REG_SZ,
494 (PVOID)szLangID,
495 (wcslen(szLangID)+1) * sizeof(WCHAR));
496 if (!NT_SUCCESS(Status))
497 {
498 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
499 NtClose(SubKeyHandle);
500 NtClose(KeyHandle);
501 return FALSE;
502 }
503
504 RtlInitUnicodeString(&ValueName, szLangID);
505
506 Status = NtSetValueKey(SubKeyHandle,
507 &ValueName,
508 0,
509 REG_SZ,
510 (PVOID)MuiLayouts[uIndex].LayoutID,
511 (wcslen(MuiLayouts[uIndex].LayoutID)+1) * sizeof(WCHAR));
512 if (!NT_SUCCESS(Status))
513 {
514 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %u)\n", Status, uIndex);
515 NtClose(SubKeyHandle);
516 NtClose(KeyHandle);
517 return FALSE;
518 }
519
520 uCount++;
521 }
522
523 uIndex++;
524 }
525 while (MuiLayouts[uIndex].LangID != NULL);
526
527 if (uIndex > 1)
528 AddHotkeySettings(L"2", L"2", L"1");
529 else
530 AddHotkeySettings(L"3", L"3", L"3");
531
532 NtClose(SubKeyHandle);
533 NtClose(KeyHandle);
534 return TRUE;
535 }
536
537
538 BOOLEAN
539 AddKeyboardLayouts(VOID)
540 {
541 ULONG lngIndex = 0;
542
543 do
544 {
545 if (_wcsicmp(LanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
546 {
547 return AddKbLayoutsToRegistry(LanguageList[lngIndex].MuiLayouts);
548 }
549
550 lngIndex++;
551 }
552 while (LanguageList[lngIndex].MuiPages != NULL);
553
554 return FALSE;
555 }
556
557
558 static
559 BOOLEAN
560 AddCodepageToRegistry(
561 IN LPCWSTR ACPage,
562 IN LPCWSTR OEMCPage,
563 IN LPCWSTR MACCPage)
564 {
565 OBJECT_ATTRIBUTES ObjectAttributes;
566 UNICODE_STRING KeyName;
567 UNICODE_STRING ValueName;
568 HANDLE KeyHandle;
569 NTSTATUS Status;
570
571 // Open the nls codepage key
572 RtlInitUnicodeString(&KeyName,
573 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage");
574 InitializeObjectAttributes(&ObjectAttributes,
575 &KeyName,
576 OBJ_CASE_INSENSITIVE,
577 NULL,
578 NULL);
579 Status = NtOpenKey(&KeyHandle,
580 KEY_WRITE,
581 &ObjectAttributes);
582 if (!NT_SUCCESS(Status))
583 {
584 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
585 return FALSE;
586 }
587
588 // Set ANSI codepage
589 RtlInitUnicodeString(&ValueName, L"ACP");
590 Status = NtSetValueKey(KeyHandle,
591 &ValueName,
592 0,
593 REG_SZ,
594 (PVOID)ACPage,
595 (wcslen(ACPage)+1) * sizeof(WCHAR));
596 if (!NT_SUCCESS(Status))
597 {
598 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
599 NtClose(KeyHandle);
600 return FALSE;
601 }
602
603 // Set OEM codepage
604 RtlInitUnicodeString(&ValueName, L"OEMCP");
605 Status = NtSetValueKey(KeyHandle,
606 &ValueName,
607 0,
608 REG_SZ,
609 (PVOID)OEMCPage,
610 (wcslen(OEMCPage)+1) * sizeof(WCHAR));
611 if (!NT_SUCCESS(Status))
612 {
613 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
614 NtClose(KeyHandle);
615 return FALSE;
616 }
617
618 // Set MAC codepage
619 RtlInitUnicodeString(&ValueName, L"MACCP");
620 Status = NtSetValueKey(KeyHandle,
621 &ValueName,
622 0,
623 REG_SZ,
624 (PVOID)MACCPage,
625 (wcslen(MACCPage)+1) * sizeof(WCHAR));
626 if (!NT_SUCCESS(Status))
627 {
628 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
629 NtClose(KeyHandle);
630 return FALSE;
631 }
632
633 NtClose(KeyHandle);
634
635 return TRUE;
636 }
637
638
639 static
640 BOOLEAN
641 AddFontsSettingsToRegistry(
642 IN const MUI_SUBFONT * MuiSubFonts)
643 {
644 OBJECT_ATTRIBUTES ObjectAttributes;
645 UNICODE_STRING KeyName;
646 UNICODE_STRING ValueName;
647 HANDLE KeyHandle;
648 NTSTATUS Status;
649 ULONG uIndex = 0;
650
651 RtlInitUnicodeString(&KeyName,
652 L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
653 InitializeObjectAttributes(&ObjectAttributes,
654 &KeyName,
655 OBJ_CASE_INSENSITIVE,
656 NULL,
657 NULL);
658 Status = NtOpenKey(&KeyHandle,
659 KEY_WRITE,
660 &ObjectAttributes);
661 if (!NT_SUCCESS(Status))
662 {
663 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
664 return FALSE;
665 }
666
667 do
668 {
669 RtlInitUnicodeString(&ValueName, MuiSubFonts[uIndex].FontName);
670 Status = NtSetValueKey(KeyHandle,
671 &ValueName,
672 0,
673 REG_SZ,
674 (PVOID)MuiSubFonts[uIndex].SubFontName,
675 (wcslen(MuiSubFonts[uIndex].SubFontName)+1) * sizeof(WCHAR));
676 if (!NT_SUCCESS(Status))
677 {
678 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
679 NtClose(KeyHandle);
680 return FALSE;
681 }
682
683 uIndex++;
684 }
685 while (MuiSubFonts[uIndex].FontName != NULL);
686
687 NtClose(KeyHandle);
688
689 return TRUE;
690 }
691
692
693 BOOLEAN
694 AddCodePage(VOID)
695 {
696 ULONG lngIndex = 0;
697 do
698 {
699 if (_wcsicmp(LanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
700 {
701 if (AddCodepageToRegistry(LanguageList[lngIndex].ACPage,
702 LanguageList[lngIndex].OEMCPage,
703 LanguageList[lngIndex].MACCPage)&&
704 AddFontsSettingsToRegistry(LanguageList[lngIndex].MuiSubFonts))
705 {
706 return TRUE;
707 }
708 else
709 {
710 return FALSE;
711 }
712 }
713
714 lngIndex++;
715 }
716 while (LanguageList[lngIndex].MuiPages != NULL);
717
718 return FALSE;
719 }
720
721
722 VOID
723 SetConsoleCodePage(VOID)
724 {
725 ULONG lngIndex = 0;
726 UINT wCodePage;
727
728 do
729 {
730 if (_wcsicmp(LanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
731 {
732 wCodePage = (UINT) wcstoul(LanguageList[lngIndex].OEMCPage, NULL, 10);
733 SetConsoleOutputCP(wCodePage);
734 return;
735 }
736
737 lngIndex++;
738 }
739 while (LanguageList[lngIndex].MuiPages != NULL);
740 }
741
742 /* EOF */