xref: /reactos/base/setup/lib/mui.c (revision 8a978a17)
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 /* INCLUDES *****************************************************************/
28 
29 #include "precomp.h"
30 #include "mui.h"
31 #include "muifonts.h"
32 #include "muilanguages.h"
33 #include "registry.h"
34 #include "substset.h"
35 
36 #define NDEBUG
37 #include <debug.h>
38 
39 
40 /* FUNCTIONS ****************************************************************/
41 
42 static
43 ULONG
44 FindLanguageIndex(
45     IN PCWSTR LanguageId)
46 {
47     ULONG lngIndex = 0;
48 
49     if (LanguageId == NULL)
50     {
51         /* Default to en-US */
52         // return 0;   // FIXME!!
53         LanguageId = L"00000409";
54     }
55 
56     while (MUILanguageList[lngIndex].LanguageID != NULL)
57     {
58         if (_wcsicmp(MUILanguageList[lngIndex].LanguageID, LanguageId) == 0)
59         {
60             return lngIndex;
61         }
62 
63         lngIndex++;
64     }
65 
66     return 0;
67 }
68 
69 BOOLEAN
70 IsLanguageAvailable(
71     IN PCWSTR LanguageId)
72 {
73     ULONG lngIndex = 0;
74 
75     while (MUILanguageList[lngIndex].LanguageID != NULL)
76     {
77         if (_wcsicmp(MUILanguageList[lngIndex].LanguageID, LanguageId) == 0)
78             return TRUE;
79 
80         lngIndex++;
81     }
82 
83     return FALSE;
84 }
85 
86 
87 PCWSTR
88 MUIDefaultKeyboardLayout(
89     IN PCWSTR LanguageId)
90 {
91     ULONG lngIndex = max(FindLanguageIndex(LanguageId), 0);
92     return MUILanguageList[lngIndex].MuiLayouts[0].LayoutID;
93 }
94 
95 PCWSTR
96 MUIGetOEMCodePage(
97     IN PCWSTR LanguageId)
98 {
99     ULONG lngIndex = max(FindLanguageIndex(LanguageId), 0);
100     return MUILanguageList[lngIndex].OEMCPage;
101 }
102 
103 PCWSTR
104 MUIGetGeoID(
105     IN PCWSTR LanguageId)
106 {
107     ULONG lngIndex = max(FindLanguageIndex(LanguageId), 0);
108     return MUILanguageList[lngIndex].GeoID;
109 }
110 
111 const MUI_LAYOUTS*
112 MUIGetLayoutsList(
113     IN PCWSTR LanguageId)
114 {
115     ULONG lngIndex = max(FindLanguageIndex(LanguageId), 0);
116     return MUILanguageList[lngIndex].MuiLayouts;
117 }
118 
119 
120 static
121 BOOLEAN
122 AddHotkeySettings(
123     IN PCWSTR Hotkey,
124     IN PCWSTR LangHotkey,
125     IN PCWSTR LayoutHotkey)
126 {
127     OBJECT_ATTRIBUTES ObjectAttributes;
128     UNICODE_STRING KeyName;
129     UNICODE_STRING ValueName;
130     HANDLE KeyHandle;
131     ULONG Disposition;
132     NTSTATUS Status;
133 
134     RtlInitUnicodeString(&KeyName,
135                          L".DEFAULT\\Keyboard Layout\\Toggle");
136     InitializeObjectAttributes(&ObjectAttributes,
137                                &KeyName,
138                                OBJ_CASE_INSENSITIVE,
139                                GetRootKeyByPredefKey(HKEY_USERS, NULL),
140                                NULL);
141 
142     Status =  NtCreateKey(&KeyHandle,
143                           KEY_SET_VALUE,
144                           &ObjectAttributes,
145                           0,
146                           NULL,
147                           REG_OPTION_NON_VOLATILE,
148                           &Disposition);
149     if (!NT_SUCCESS(Status))
150     {
151         DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
152         return FALSE;
153     }
154 
155     RtlInitUnicodeString(&ValueName,
156                          L"Hotkey");
157 
158     Status = NtSetValueKey(KeyHandle,
159                            &ValueName,
160                            0,
161                            REG_SZ,
162                            (PVOID)Hotkey,
163                            (1 + 1) * sizeof(WCHAR));
164     if (!NT_SUCCESS(Status))
165     {
166         DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
167         NtClose(KeyHandle);
168         return FALSE;
169     }
170 
171     RtlInitUnicodeString(&ValueName,
172                          L"Language Hotkey");
173 
174     Status = NtSetValueKey(KeyHandle,
175                            &ValueName,
176                            0,
177                            REG_SZ,
178                            (PVOID)LangHotkey,
179                            (1 + 1) * sizeof(WCHAR));
180     if (!NT_SUCCESS(Status))
181     {
182         DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
183         NtClose(KeyHandle);
184         return FALSE;
185     }
186 
187     RtlInitUnicodeString(&ValueName,
188                          L"Layout Hotkey");
189 
190     Status = NtSetValueKey(KeyHandle,
191                            &ValueName,
192                            0,
193                            REG_SZ,
194                            (PVOID)LayoutHotkey,
195                            (1 + 1) * sizeof(WCHAR));
196     if (!NT_SUCCESS(Status))
197     {
198         DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
199         NtClose(KeyHandle);
200         return FALSE;
201     }
202 
203     NtClose(KeyHandle);
204     return TRUE;
205 }
206 
207 BOOLEAN
208 AddKbLayoutsToRegistry(
209     IN const MUI_LAYOUTS *MuiLayouts)
210 {
211     OBJECT_ATTRIBUTES ObjectAttributes;
212     UNICODE_STRING KeyName;
213     UNICODE_STRING ValueName;
214     HANDLE KeyHandle;
215     HANDLE SubKeyHandle;
216     NTSTATUS Status;
217     ULONG Disposition;
218     ULONG uIndex = 0;
219     ULONG uCount = 0;
220     WCHAR szKeyName[48] = L".DEFAULT\\Keyboard Layout";
221     WCHAR szValueName[3 + 1];
222     WCHAR szLangID[8 + 1];
223 
224     // Open the keyboard layout key
225     RtlInitUnicodeString(&KeyName, szKeyName);
226     InitializeObjectAttributes(&ObjectAttributes,
227                                &KeyName,
228                                OBJ_CASE_INSENSITIVE,
229                                GetRootKeyByPredefKey(HKEY_USERS, NULL),
230                                NULL);
231 
232     Status =  NtCreateKey(&KeyHandle,
233                           KEY_CREATE_SUB_KEY,
234                           &ObjectAttributes,
235                           0,
236                           NULL,
237                           REG_OPTION_NON_VOLATILE,
238                           &Disposition);
239     if (!NT_SUCCESS(Status))
240     {
241         DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
242         return FALSE;
243     }
244 
245     NtClose(KeyHandle);
246 
247     KeyName.MaximumLength = sizeof(szKeyName);
248     Status = RtlAppendUnicodeToString(&KeyName, L"\\Preload");
249 
250     if (!NT_SUCCESS(Status))
251     {
252         DPRINT1("RtlAppend failed! (%lx)\n", Status);
253         DPRINT1("String is %wZ\n", &KeyName);
254         return FALSE;
255     }
256 
257     InitializeObjectAttributes(&ObjectAttributes,
258                                &KeyName,
259                                OBJ_CASE_INSENSITIVE,
260                                GetRootKeyByPredefKey(HKEY_USERS, NULL),
261                                NULL);
262 
263     Status = NtCreateKey(&KeyHandle,
264                          KEY_SET_VALUE,
265                          &ObjectAttributes,
266                          0,
267                          NULL,
268                          REG_OPTION_NON_VOLATILE,
269                          &Disposition);
270     if (!NT_SUCCESS(Status))
271     {
272         DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
273         return FALSE;
274     }
275 
276     RtlInitUnicodeString(&KeyName, L".DEFAULT\\Keyboard Layout\\Substitutes");
277     InitializeObjectAttributes(&ObjectAttributes,
278                                &KeyName,
279                                OBJ_CASE_INSENSITIVE,
280                                GetRootKeyByPredefKey(HKEY_USERS, NULL),
281                                NULL);
282 
283     Status =  NtCreateKey(&SubKeyHandle,
284                           KEY_SET_VALUE,
285                           &ObjectAttributes,
286                           0,
287                           NULL,
288                           REG_OPTION_NON_VOLATILE,
289                           &Disposition);
290     if (!NT_SUCCESS(Status))
291     {
292         DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
293         NtClose(SubKeyHandle);
294         NtClose(KeyHandle);
295         return FALSE;
296     }
297 
298     while (MuiLayouts[uIndex].LangID != NULL)
299     {
300         if (uIndex > 19) break;
301 
302         RtlStringCchPrintfW(szValueName, ARRAYSIZE(szValueName), L"%u", uIndex + 1);
303         RtlInitUnicodeString(&ValueName, szValueName);
304 
305         RtlStringCchPrintfW(szLangID, ARRAYSIZE(szLangID), L"0000%s", MuiLayouts[uIndex].LangID);
306 
307         if (_wcsicmp(szLangID, MuiLayouts[uIndex].LayoutID) == 0)
308         {
309             Status = NtSetValueKey(KeyHandle,
310                                    &ValueName,
311                                    0,
312                                    REG_SZ,
313                                    (PVOID)MuiLayouts[uIndex].LayoutID,
314                                    (wcslen(MuiLayouts[uIndex].LayoutID)+1) * sizeof(WCHAR));
315             if (!NT_SUCCESS(Status))
316             {
317                 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
318                 NtClose(SubKeyHandle);
319                 NtClose(KeyHandle);
320                 return FALSE;
321             }
322         }
323         else
324         {
325             RtlStringCchPrintfW(szLangID, ARRAYSIZE(szLangID), L"d%03lu%s", uCount, MuiLayouts[uIndex].LangID);
326             Status = NtSetValueKey(KeyHandle,
327                                    &ValueName,
328                                    0,
329                                    REG_SZ,
330                                    (PVOID)szLangID,
331                                    (wcslen(szLangID)+1) * sizeof(WCHAR));
332             if (!NT_SUCCESS(Status))
333             {
334                 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
335                 NtClose(SubKeyHandle);
336                 NtClose(KeyHandle);
337                 return FALSE;
338             }
339 
340             RtlInitUnicodeString(&ValueName, szLangID);
341 
342             Status = NtSetValueKey(SubKeyHandle,
343                                    &ValueName,
344                                    0,
345                                    REG_SZ,
346                                    (PVOID)MuiLayouts[uIndex].LayoutID,
347                                    (wcslen(MuiLayouts[uIndex].LayoutID)+1) * sizeof(WCHAR));
348             if (!NT_SUCCESS(Status))
349             {
350                 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %u)\n", Status, uIndex);
351                 NtClose(SubKeyHandle);
352                 NtClose(KeyHandle);
353                 return FALSE;
354             }
355 
356             uCount++;
357         }
358 
359         uIndex++;
360     }
361 
362     if (uIndex > 1)
363         AddHotkeySettings(L"2", L"2", L"1");
364     else
365         AddHotkeySettings(L"3", L"3", L"3");
366 
367     NtClose(SubKeyHandle);
368     NtClose(KeyHandle);
369     return TRUE;
370 }
371 
372 BOOLEAN
373 AddKeyboardLayouts(
374     IN PCWSTR LanguageId)
375 {
376     ULONG lngIndex = 0;
377 
378     while (MUILanguageList[lngIndex].LanguageID != NULL)
379     {
380         if (_wcsicmp(MUILanguageList[lngIndex].LanguageID, LanguageId) == 0)
381         {
382             return AddKbLayoutsToRegistry(MUILanguageList[lngIndex].MuiLayouts);
383         }
384 
385         lngIndex++;
386     }
387 
388     return FALSE;
389 }
390 
391 static
392 BOOLEAN
393 AddCodepageToRegistry(
394     IN PCWSTR ACPage,
395     IN PCWSTR OEMCPage,
396     IN PCWSTR MACCPage)
397 {
398     OBJECT_ATTRIBUTES ObjectAttributes;
399     UNICODE_STRING KeyName;
400     UNICODE_STRING ValueName;
401     HANDLE KeyHandle;
402     NTSTATUS Status;
403 
404     // Open the nls codepage key
405     RtlInitUnicodeString(&KeyName,
406                          L"SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage");
407     InitializeObjectAttributes(&ObjectAttributes,
408                                &KeyName,
409                                OBJ_CASE_INSENSITIVE,
410                                GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
411                                NULL);
412     Status = NtOpenKey(&KeyHandle,
413                        KEY_WRITE,
414                        &ObjectAttributes);
415     if (!NT_SUCCESS(Status))
416     {
417         DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
418         return FALSE;
419     }
420 
421     // Set ANSI codepage
422     RtlInitUnicodeString(&ValueName, L"ACP");
423     Status = NtSetValueKey(KeyHandle,
424                            &ValueName,
425                            0,
426                            REG_SZ,
427                            (PVOID)ACPage,
428                            (wcslen(ACPage)+1) * sizeof(WCHAR));
429     if (!NT_SUCCESS(Status))
430     {
431         DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
432         NtClose(KeyHandle);
433         return FALSE;
434     }
435 
436     // Set OEM codepage
437     RtlInitUnicodeString(&ValueName, L"OEMCP");
438     Status = NtSetValueKey(KeyHandle,
439                            &ValueName,
440                            0,
441                            REG_SZ,
442                            (PVOID)OEMCPage,
443                            (wcslen(OEMCPage)+1) * sizeof(WCHAR));
444     if (!NT_SUCCESS(Status))
445     {
446         DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
447         NtClose(KeyHandle);
448         return FALSE;
449     }
450 
451     // Set MAC codepage
452     RtlInitUnicodeString(&ValueName, L"MACCP");
453     Status = NtSetValueKey(KeyHandle,
454                            &ValueName,
455                            0,
456                            REG_SZ,
457                            (PVOID)MACCPage,
458                            (wcslen(MACCPage)+1) * sizeof(WCHAR));
459     if (!NT_SUCCESS(Status))
460     {
461         DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
462         NtClose(KeyHandle);
463         return FALSE;
464     }
465 
466     NtClose(KeyHandle);
467 
468     return TRUE;
469 }
470 
471 static
472 BOOLEAN
473 AddFontsSettingsToRegistry(
474     IN const MUI_SUBFONT * MuiSubFonts)
475 {
476     OBJECT_ATTRIBUTES ObjectAttributes;
477     UNICODE_STRING KeyName;
478     UNICODE_STRING ValueName;
479     HANDLE KeyHandle;
480     NTSTATUS Status;
481     ULONG uIndex = 0;
482 
483     RtlInitUnicodeString(&KeyName,
484                          L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
485     InitializeObjectAttributes(&ObjectAttributes,
486                                &KeyName,
487                                OBJ_CASE_INSENSITIVE,
488                                GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
489                                NULL);
490     Status = NtOpenKey(&KeyHandle,
491                        KEY_WRITE,
492                        &ObjectAttributes);
493     if (!NT_SUCCESS(Status))
494     {
495         DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
496         return FALSE;
497     }
498 
499     while (MuiSubFonts[uIndex].FontName != NULL)
500     {
501         RtlInitUnicodeString(&ValueName, MuiSubFonts[uIndex].FontName);
502         if (MuiSubFonts[uIndex].SubFontName)
503         {
504             Status = NtSetValueKey(KeyHandle,
505                                    &ValueName,
506                                    0,
507                                    REG_SZ,
508                                    (PVOID)MuiSubFonts[uIndex].SubFontName,
509                                    (wcslen(MuiSubFonts[uIndex].SubFontName)+1) * sizeof(WCHAR));
510             if (!NT_SUCCESS(Status))
511             {
512                 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
513                 NtClose(KeyHandle);
514                 return FALSE;
515             }
516         }
517         else
518         {
519             Status = NtDeleteValueKey(KeyHandle, &ValueName);
520             if (!NT_SUCCESS(Status))
521             {
522                 DPRINT1("NtDeleteValueKey failed, Status = %lx\n", Status);
523             }
524         }
525 
526         uIndex++;
527     }
528 
529     NtClose(KeyHandle);
530 
531     return TRUE;
532 }
533 
534 BOOLEAN
535 AddCodePage(
536     IN PCWSTR LanguageId)
537 {
538     ULONG lngIndex = 0;
539 
540     while (MUILanguageList[lngIndex].LanguageID != NULL)
541     {
542         if (_wcsicmp(MUILanguageList[lngIndex].LanguageID, LanguageId) == 0)
543         {
544             if (AddCodepageToRegistry(MUILanguageList[lngIndex].ACPage,
545                                       MUILanguageList[lngIndex].OEMCPage,
546                                       MUILanguageList[lngIndex].MACCPage) &&
547                 AddFontsSettingsToRegistry(MUILanguageList[lngIndex].MuiSubFonts))
548             {
549                 return TRUE;
550             }
551             else
552             {
553                 return FALSE;
554             }
555         }
556 
557         lngIndex++;
558     }
559 
560     return FALSE;
561 }
562 
563 #ifdef __REACTOS__ /* HACK */
564 BOOL
565 DoRegistryFontFixup(PFONTSUBSTSETTINGS pSettings, LANGID LangID)
566 {
567     if (pSettings->bFoundFontMINGLIU)
568         AddFontsSettingsToRegistry(FontFixupMINGLIU);
569     if (pSettings->bFoundFontSIMSUN)
570         AddFontsSettingsToRegistry(FontFixupSIMSUN);
571     if (pSettings->bFoundFontMSSONG)
572         AddFontsSettingsToRegistry(FontFixupMSSONG);
573     if (pSettings->bFoundFontMSGOTHIC)
574         AddFontsSettingsToRegistry(FontFixupMSGOTHIC);
575     if (pSettings->bFoundFontMSMINCHO)
576         AddFontsSettingsToRegistry(FontFixupMSMINCHO);
577     if (pSettings->bFoundFontGULIM)
578         AddFontsSettingsToRegistry(FontFixupGULIM);
579     if (pSettings->bFoundFontBATANG)
580         AddFontsSettingsToRegistry(FontFixupBATANG);
581 
582     switch (PRIMARYLANGID(LangID))
583     {
584         case LANG_CHINESE:
585             if (SUBLANGID(LangID) == SUBLANG_CHINESE_SIMPLIFIED)
586             {
587                 if (pSettings->bFoundFontSIMSUN)
588                     AddFontsSettingsToRegistry(SimplifiedChineseFontFixup);
589             }
590             else
591             {
592                 if (pSettings->bFoundFontMINGLIU)
593                     AddFontsSettingsToRegistry(TraditionalChineseFontFixup);
594             }
595             break;
596 
597         case LANG_JAPANESE:
598             if (pSettings->bFoundFontMSGOTHIC)
599                 AddFontsSettingsToRegistry(JapaneseFontFixup);
600             break;
601 
602         case LANG_KOREAN:
603             if (pSettings->bFoundFontBATANG)
604                 AddFontsSettingsToRegistry(KoreanFontFixup);
605             break;
606     }
607 
608     return TRUE;
609 }
610 #endif /* HACK */
611 
612 /* EOF */
613