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
FindLanguageIndex(IN PCWSTR LanguageId)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
IsLanguageAvailable(IN PCWSTR LanguageId)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 KLID
MUIDefaultKeyboardLayout(IN PCWSTR LanguageId)88 MUIDefaultKeyboardLayout(
89 IN PCWSTR LanguageId)
90 {
91 ULONG lngIndex = FindLanguageIndex(LanguageId);
92 return MUILanguageList[lngIndex].MuiLayouts[0].LayoutID;
93 }
94
95 UINT
MUIGetOEMCodePage(IN PCWSTR LanguageId)96 MUIGetOEMCodePage(
97 IN PCWSTR LanguageId)
98 {
99 ULONG lngIndex = FindLanguageIndex(LanguageId);
100 return MUILanguageList[lngIndex].OEMCPage;
101 }
102
103 GEOID
MUIGetGeoID(IN PCWSTR LanguageId)104 MUIGetGeoID(
105 IN PCWSTR LanguageId)
106 {
107 ULONG lngIndex = FindLanguageIndex(LanguageId);
108 return MUILanguageList[lngIndex].GeoID;
109 }
110
111 const MUI_LAYOUTS*
MUIGetLayoutsList(IN PCWSTR LanguageId)112 MUIGetLayoutsList(
113 IN PCWSTR LanguageId)
114 {
115 ULONG lngIndex = FindLanguageIndex(LanguageId);
116 return MUILanguageList[lngIndex].MuiLayouts;
117 }
118
119
120 static
121 BOOLEAN
AddHotkeySettings(IN PCWSTR Hotkey,IN PCWSTR LangHotkey,IN PCWSTR LayoutHotkey)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
AddKbLayoutsToRegistry(_In_ const MUI_LAYOUTS * MuiLayouts)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;
219 ULONG uCount;
220 WCHAR szKeyName[48] = L".DEFAULT\\Keyboard Layout";
221 WCHAR szValueName[3 + 1];
222 WCHAR szSubstID[8 + 1];
223 WCHAR szLayoutID[8 + 1];
224
225 /* Open the keyboard layout key */
226 RtlInitUnicodeString(&KeyName, szKeyName);
227 InitializeObjectAttributes(&ObjectAttributes,
228 &KeyName,
229 OBJ_CASE_INSENSITIVE,
230 GetRootKeyByPredefKey(HKEY_USERS, NULL),
231 NULL);
232
233 Status = NtCreateKey(&KeyHandle,
234 KEY_CREATE_SUB_KEY,
235 &ObjectAttributes,
236 0,
237 NULL,
238 REG_OPTION_NON_VOLATILE,
239 &Disposition);
240 if (!NT_SUCCESS(Status))
241 {
242 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
243 return FALSE;
244 }
245
246 NtClose(KeyHandle);
247
248 KeyName.MaximumLength = sizeof(szKeyName);
249 Status = RtlAppendUnicodeToString(&KeyName, L"\\Preload");
250 if (!NT_SUCCESS(Status))
251 {
252 DPRINT1("RtlAppend() failed (%lx), string is '%wZ'\n", Status, &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 goto Quit;
293 }
294
295 uCount = 0;
296 for (uIndex = 0; (uIndex <= 19) && (MuiLayouts[uIndex].LangID != 0); ++uIndex)
297 {
298 RtlStringCchPrintfW(szValueName, _countof(szValueName), L"%u", uIndex + 1);
299 RtlInitUnicodeString(&ValueName, szValueName);
300
301 RtlStringCchPrintfW(szLayoutID, _countof(szLayoutID), L"%08lx", MuiLayouts[uIndex].LayoutID);
302
303 if ((KLID)MuiLayouts[uIndex].LangID == MuiLayouts[uIndex].LayoutID)
304 {
305 /* Main keyboard layout */
306 Status = NtSetValueKey(KeyHandle,
307 &ValueName,
308 0,
309 REG_SZ,
310 (PVOID)szLayoutID,
311 (wcslen(szLayoutID)+1) * sizeof(WCHAR));
312 if (!NT_SUCCESS(Status))
313 {
314 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %u)\n", Status, uIndex);
315 goto Quit;
316 }
317 }
318 else
319 {
320 /* Generate a substitute keyboard layout ID */
321 RtlStringCchPrintfW(szSubstID, _countof(szSubstID), L"%08lx",
322 (0xD0000000/*SUBST_MASK*/ | ((USHORT)uCount << 4) | MuiLayouts[uIndex].LangID));
323 Status = NtSetValueKey(KeyHandle,
324 &ValueName,
325 0,
326 REG_SZ,
327 (PVOID)szSubstID,
328 (wcslen(szSubstID)+1) * sizeof(WCHAR));
329 if (!NT_SUCCESS(Status))
330 {
331 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %u)\n", Status, uIndex);
332 goto Quit;
333 }
334
335 /* Link the substitute layout with the original one */
336 RtlInitUnicodeString(&ValueName, szSubstID);
337 Status = NtSetValueKey(SubKeyHandle,
338 &ValueName,
339 0,
340 REG_SZ,
341 (PVOID)szLayoutID,
342 (wcslen(szLayoutID)+1) * sizeof(WCHAR));
343 if (!NT_SUCCESS(Status))
344 {
345 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %u)\n", Status, uIndex);
346 goto Quit;
347 }
348
349 ++uCount;
350 }
351 }
352
353 AddHotkeySettings(L"1", L"1", L"2");
354
355 Quit:
356 NtClose(SubKeyHandle);
357 NtClose(KeyHandle);
358 return NT_SUCCESS(Status);
359 }
360
361 BOOLEAN
AddKeyboardLayouts(IN PCWSTR LanguageId)362 AddKeyboardLayouts(
363 IN PCWSTR LanguageId)
364 {
365 ULONG lngIndex = 0;
366
367 while (MUILanguageList[lngIndex].LanguageID != NULL)
368 {
369 if (_wcsicmp(MUILanguageList[lngIndex].LanguageID, LanguageId) == 0)
370 {
371 return AddKbLayoutsToRegistry(MUILanguageList[lngIndex].MuiLayouts);
372 }
373
374 lngIndex++;
375 }
376
377 return FALSE;
378 }
379
380 static
381 BOOLEAN
AddCodepageToRegistry(_In_ UINT ACPage,_In_ UINT OEMCPage,_In_ UINT MACCPage)382 AddCodepageToRegistry(
383 _In_ UINT ACPage,
384 _In_ UINT OEMCPage,
385 _In_ UINT MACCPage)
386 {
387 NTSTATUS Status;
388 OBJECT_ATTRIBUTES ObjectAttributes;
389 UNICODE_STRING Name;
390 HANDLE KeyHandle;
391 /*
392 * Buffer big enough to hold the NULL-terminated string L"4294967295",
393 * corresponding to the literal 0xFFFFFFFF (MAXULONG) in decimal.
394 */
395 WCHAR Value[sizeof("4294967295")];
396
397 /* Open the NLS CodePage key */
398 RtlInitUnicodeString(&Name,
399 L"SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage");
400 InitializeObjectAttributes(&ObjectAttributes,
401 &Name,
402 OBJ_CASE_INSENSITIVE,
403 GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
404 NULL);
405 Status = NtOpenKey(&KeyHandle,
406 KEY_WRITE,
407 &ObjectAttributes);
408 if (!NT_SUCCESS(Status))
409 {
410 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
411 return FALSE;
412 }
413
414 /* Set ANSI codepage */
415 Status = RtlStringCchPrintfW(Value, _countof(Value), L"%lu", ACPage);
416 ASSERT(NT_SUCCESS(Status));
417
418 RtlInitUnicodeString(&Name, L"ACP");
419 Status = NtSetValueKey(KeyHandle,
420 &Name,
421 0,
422 REG_SZ,
423 (PVOID)Value,
424 (wcslen(Value)+1) * sizeof(WCHAR));
425 if (!NT_SUCCESS(Status))
426 {
427 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
428 goto Quit;
429 }
430
431 /* Set OEM codepage */
432 Status = RtlStringCchPrintfW(Value, _countof(Value), L"%lu", OEMCPage);
433 ASSERT(NT_SUCCESS(Status));
434
435 RtlInitUnicodeString(&Name, L"OEMCP");
436 Status = NtSetValueKey(KeyHandle,
437 &Name,
438 0,
439 REG_SZ,
440 (PVOID)Value,
441 (wcslen(Value)+1) * sizeof(WCHAR));
442 if (!NT_SUCCESS(Status))
443 {
444 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
445 goto Quit;
446 }
447
448 /* Set MAC codepage */
449 Status = RtlStringCchPrintfW(Value, _countof(Value), L"%lu", MACCPage);
450 ASSERT(NT_SUCCESS(Status));
451
452 RtlInitUnicodeString(&Name, L"MACCP");
453 Status = NtSetValueKey(KeyHandle,
454 &Name,
455 0,
456 REG_SZ,
457 (PVOID)Value,
458 (wcslen(Value)+1) * sizeof(WCHAR));
459 if (!NT_SUCCESS(Status))
460 {
461 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
462 goto Quit;
463 }
464
465 Quit:
466 NtClose(KeyHandle);
467 return NT_SUCCESS(Status);
468 }
469
470 static
471 BOOLEAN
AddFontsSettingsToRegistry(IN const MUI_SUBFONT * MuiSubFonts)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 if (MuiSubFonts[uIndex].SubFontName)
502 {
503 Status = NtSetValueKey(KeyHandle,
504 &ValueName,
505 0,
506 REG_SZ,
507 (PVOID)MuiSubFonts[uIndex].SubFontName,
508 (wcslen(MuiSubFonts[uIndex].SubFontName)+1) * sizeof(WCHAR));
509 if (!NT_SUCCESS(Status))
510 {
511 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
512 NtClose(KeyHandle);
513 return FALSE;
514 }
515 }
516 else
517 {
518 Status = NtDeleteValueKey(KeyHandle, &ValueName);
519 if (!NT_SUCCESS(Status))
520 {
521 DPRINT1("NtDeleteValueKey failed, Status = %lx\n", Status);
522 }
523 }
524
525 uIndex++;
526 }
527
528 NtClose(KeyHandle);
529
530 return TRUE;
531 }
532
533 BOOLEAN
AddCodePage(IN PCWSTR LanguageId)534 AddCodePage(
535 IN PCWSTR LanguageId)
536 {
537 ULONG lngIndex = 0;
538
539 while (MUILanguageList[lngIndex].LanguageID != NULL)
540 {
541 if (_wcsicmp(MUILanguageList[lngIndex].LanguageID, LanguageId) == 0)
542 {
543 if (AddCodepageToRegistry(MUILanguageList[lngIndex].ACPage,
544 MUILanguageList[lngIndex].OEMCPage,
545 MUILanguageList[lngIndex].MACCPage) &&
546 AddFontsSettingsToRegistry(MUILanguageList[lngIndex].MuiSubFonts))
547 {
548 return TRUE;
549 }
550 else
551 {
552 return FALSE;
553 }
554 }
555
556 lngIndex++;
557 }
558
559 return FALSE;
560 }
561
562 #ifdef __REACTOS__ /* HACK */
563 BOOL
DoRegistryFontFixup(PFONTSUBSTSETTINGS pSettings,LANGID LangID)564 DoRegistryFontFixup(PFONTSUBSTSETTINGS pSettings, LANGID LangID)
565 {
566 if (pSettings->bFoundFontMINGLIU)
567 AddFontsSettingsToRegistry(FontFixupMINGLIU);
568 if (pSettings->bFoundFontSIMSUN)
569 AddFontsSettingsToRegistry(FontFixupSIMSUN);
570 if (pSettings->bFoundFontMSSONG)
571 AddFontsSettingsToRegistry(FontFixupMSSONG);
572 if (pSettings->bFoundFontMSGOTHIC)
573 AddFontsSettingsToRegistry(FontFixupMSGOTHIC);
574 if (pSettings->bFoundFontMSMINCHO)
575 AddFontsSettingsToRegistry(FontFixupMSMINCHO);
576 if (pSettings->bFoundFontGULIM)
577 AddFontsSettingsToRegistry(FontFixupGULIM);
578 if (pSettings->bFoundFontBATANG)
579 AddFontsSettingsToRegistry(FontFixupBATANG);
580
581 switch (PRIMARYLANGID(LangID))
582 {
583 case LANG_CHINESE:
584 if (SUBLANGID(LangID) == SUBLANG_CHINESE_SIMPLIFIED)
585 {
586 if (pSettings->bFoundFontSIMSUN)
587 AddFontsSettingsToRegistry(SimplifiedChineseFontFixup);
588 }
589 else
590 {
591 if (pSettings->bFoundFontMINGLIU)
592 AddFontsSettingsToRegistry(TraditionalChineseFontFixup);
593 }
594 break;
595
596 case LANG_JAPANESE:
597 if (pSettings->bFoundFontMSGOTHIC)
598 AddFontsSettingsToRegistry(JapaneseFontFixup);
599 break;
600
601 case LANG_KOREAN:
602 if (pSettings->bFoundFontBATANG)
603 AddFontsSettingsToRegistry(KoreanFontFixup);
604 break;
605 }
606
607 return TRUE;
608 }
609 #endif /* HACK */
610
611 /* EOF */
612