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