xref: /reactos/base/setup/usetup/mui.c (revision c2c66aff)
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:            base/setup/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[128];
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 */
750