[MMEBUDDY] Implement support for looped wave playback (#6761)
[reactos.git] / base / setup / lib / 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: 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 */