Branching for 0.3.15 release after two days of no response from a certain sphere...
[reactos.git] / base / setup / usetup / 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: subsys/system/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 BOOLEAN
67 IsLanguageAvailable(PWCHAR LanguageId)
68 {
69 ULONG lngIndex = 0;
70
71 do
72 {
73 if (_wcsicmp(LanguageList[lngIndex].LanguageID , LanguageId) == 0)
74 return TRUE;
75
76 lngIndex++;
77 }while (LanguageList[lngIndex].MuiPages != NULL);
78
79 return FALSE;
80 }
81
82
83 static
84 const MUI_ENTRY *
85 FindMUIEntriesOfPage(IN ULONG PageNumber)
86 {
87 ULONG muiIndex = 0;
88 ULONG lngIndex;
89 const MUI_PAGE * Pages = NULL;
90
91 lngIndex = max(FindLanguageIndex(), 0);
92 Pages = LanguageList[lngIndex].MuiPages;
93
94 do
95 {
96 if (Pages[muiIndex].Number == PageNumber)
97 return Pages[muiIndex].MuiEntry;
98
99 muiIndex++;
100 }while (Pages[muiIndex].MuiEntry != NULL);
101
102 return NULL;
103 }
104
105 static
106 const MUI_ERROR *
107 FindMUIErrorEntries(VOID)
108 {
109 ULONG lngIndex = max(FindLanguageIndex(), 0);
110 return LanguageList[lngIndex].MuiErrors;
111 }
112
113 static
114 const MUI_STRING *
115 FindMUIStringEntries(VOID)
116 {
117 ULONG lngIndex = max(FindLanguageIndex(), 0);
118 return LanguageList[lngIndex].MuiStrings;
119 }
120
121 LPCWSTR
122 MUIDefaultKeyboardLayout(VOID)
123 {
124 ULONG lngIndex = max(FindLanguageIndex(), 0);
125 return LanguageList[lngIndex].MuiLayouts[0].LayoutID;
126 }
127
128 PWCHAR
129 MUIGetGeoID(VOID)
130 {
131 ULONG lngIndex = max(FindLanguageIndex(), 0);
132 return LanguageList[lngIndex].GeoID;
133 }
134
135 const MUI_LAYOUTS *
136 MUIGetLayoutsList(VOID)
137 {
138 ULONG lngIndex = max(FindLanguageIndex(), 0);
139 return LanguageList[lngIndex].MuiLayouts;
140 }
141
142 VOID
143 MUIClearPage(IN ULONG page)
144 {
145 const MUI_ENTRY * entry;
146 int index;
147
148 entry = FindMUIEntriesOfPage(page);
149 if (!entry)
150 {
151 PopupError("Error: Failed to find translated page",
152 NULL,
153 NULL,
154 POPUP_WAIT_NONE);
155 return;
156 }
157
158 index = 0;
159 do
160 {
161 CONSOLE_ClearStyledText(entry[index].X,
162 entry[index].Y,
163 entry[index].Flags,
164 strlen(entry[index].Buffer));
165 index++;
166 }
167 while (entry[index].Buffer != NULL);
168 }
169
170 VOID
171 MUIDisplayPage(IN ULONG page)
172 {
173 const MUI_ENTRY * entry;
174 int index;
175
176 entry = FindMUIEntriesOfPage(page);
177 if (!entry)
178 {
179 PopupError("Error: Failed to find translated page",
180 NULL,
181 NULL,
182 POPUP_WAIT_NONE);
183 return;
184 }
185
186 index = 0;
187 do
188 {
189 CONSOLE_SetStyledText(entry[index].X,
190 entry[index].Y,
191 entry[index].Flags,
192 entry[index].Buffer);
193
194 index++;
195 }
196 while (entry[index].Buffer != NULL);
197 }
198
199 VOID
200 MUIDisplayError(IN ULONG ErrorNum, OUT PINPUT_RECORD Ir, IN ULONG WaitEvent)
201 {
202 const MUI_ERROR * entry;
203
204 if (ErrorNum >= ERROR_LAST_ERROR_CODE)
205 {
206 PopupError("Invalid error number provided",
207 "Press ENTER to continue",
208 Ir,
209 POPUP_WAIT_ENTER);
210
211 return;
212 }
213
214 entry = FindMUIErrorEntries();
215 if (!entry)
216 {
217 PopupError("Error: Failed to find translated error message",
218 NULL,
219 NULL,
220 POPUP_WAIT_NONE);
221 return;
222 }
223
224 PopupError(entry[ErrorNum].ErrorText,
225 entry[ErrorNum].ErrorStatus,
226 Ir,
227 WaitEvent);
228 }
229
230 LPSTR
231 MUIGetString(ULONG Number)
232 {
233 ULONG i;
234 const MUI_STRING * entry;
235 CHAR szErr[100];
236
237 entry = FindMUIStringEntries();
238 if (entry)
239 {
240 for (i = 0; entry[i].Number != 0; i++)
241 {
242 if (entry[i].Number == Number)
243 {
244 return entry[i].String;
245 }
246 }
247 }
248
249 sprintf(szErr, "Error: failed find string id %lu for language index %lu\n", Number, FindLanguageIndex());
250
251 PopupError(szErr,
252 NULL,
253 NULL,
254 POPUP_WAIT_NONE);
255
256 return "<nostring>";
257 }
258
259 static BOOLEAN
260 AddHotkeySettings(IN LPCWSTR Hotkey, IN LPCWSTR LangHotkey, IN LPCWSTR LayoutHotkey)
261 {
262 OBJECT_ATTRIBUTES ObjectAttributes;
263 UNICODE_STRING KeyName;
264 UNICODE_STRING ValueName;
265 HANDLE KeyHandle;
266 ULONG Disposition;
267 NTSTATUS Status;
268
269 RtlInitUnicodeString(&KeyName,
270 L"\\Registry\\User\\.DEFAULT\\Keyboard Layout\\Toggle");
271 InitializeObjectAttributes(&ObjectAttributes,
272 &KeyName,
273 OBJ_CASE_INSENSITIVE,
274 NULL,
275 NULL);
276
277 Status = NtCreateKey(&KeyHandle,
278 KEY_SET_VALUE,
279 &ObjectAttributes,
280 0,
281 NULL,
282 0,
283 &Disposition);
284
285 if(!NT_SUCCESS(Status))
286 {
287 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
288 return FALSE;
289 }
290
291 RtlInitUnicodeString(&ValueName,
292 L"Hotkey");
293
294 Status = NtSetValueKey(KeyHandle,
295 &ValueName,
296 0,
297 REG_SZ,
298 (PVOID)Hotkey,
299 (1 + 1) * sizeof(WCHAR));
300 if (!NT_SUCCESS(Status))
301 {
302 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
303 NtClose(KeyHandle);
304 return FALSE;
305 }
306
307 RtlInitUnicodeString(&ValueName,
308 L"Language Hotkey");
309
310 Status = NtSetValueKey(KeyHandle,
311 &ValueName,
312 0,
313 REG_SZ,
314 (PVOID)LangHotkey,
315 (1 + 1) * sizeof(WCHAR));
316 if (!NT_SUCCESS(Status))
317 {
318 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
319 NtClose(KeyHandle);
320 return FALSE;
321 }
322
323 RtlInitUnicodeString(&ValueName,
324 L"Layout Hotkey");
325
326 Status = NtSetValueKey(KeyHandle,
327 &ValueName,
328 0,
329 REG_SZ,
330 (PVOID)LayoutHotkey,
331 (1 + 1) * sizeof(WCHAR));
332 if (!NT_SUCCESS(Status))
333 {
334 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
335 NtClose(KeyHandle);
336 return FALSE;
337 }
338
339 NtClose(KeyHandle);
340 return TRUE;
341 }
342
343 BOOLEAN
344 AddKbLayoutsToRegistry(IN const MUI_LAYOUTS * MuiLayouts)
345 {
346 OBJECT_ATTRIBUTES ObjectAttributes;
347 UNICODE_STRING KeyName;
348 UNICODE_STRING ValueName;
349 HANDLE KeyHandle;
350 HANDLE SubKeyHandle;
351 NTSTATUS Status;
352 ULONG Disposition;
353 ULONG uIndex = 0;
354 ULONG uCount = 0;
355 WCHAR szKeyName[48] = L"\\Registry\\User\\.DEFAULT\\Keyboard Layout";
356 WCHAR szValueName[3 + 1];
357 WCHAR szLangID[8 + 1];
358
359 // Open the keyboard layout key
360 RtlInitUnicodeString(&KeyName,
361 szKeyName);
362 InitializeObjectAttributes(&ObjectAttributes,
363 &KeyName,
364 OBJ_CASE_INSENSITIVE,
365 NULL,
366 NULL);
367
368 Status = NtCreateKey(&KeyHandle,
369 KEY_CREATE_SUB_KEY,
370 &ObjectAttributes,
371 0,
372 NULL,
373 0,
374 &Disposition);
375
376 if(NT_SUCCESS(Status))
377 NtClose(KeyHandle);
378 else
379 {
380 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
381 return FALSE;
382 }
383
384 KeyName.MaximumLength = sizeof(szKeyName);
385 Status = RtlAppendUnicodeToString(&KeyName, L"\\Preload");
386
387 if(!NT_SUCCESS(Status))
388 {
389 DPRINT1("RtlAppend failed! (%lx)\n", Status);
390 DPRINT1("String is %wZ\n", &KeyName);
391 return FALSE;
392 }
393
394 InitializeObjectAttributes(&ObjectAttributes,
395 &KeyName,
396 OBJ_CASE_INSENSITIVE,
397 NULL,
398 NULL);
399
400 Status = NtCreateKey(&KeyHandle,
401 KEY_SET_VALUE,
402 &ObjectAttributes,
403 0,
404 NULL,
405 0,
406 &Disposition);
407
408 if (!NT_SUCCESS(Status))
409 {
410 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
411 return FALSE;
412 }
413
414 RtlInitUnicodeString(&KeyName, L"\\Registry\\User\\.DEFAULT\\Keyboard Layout\\Substitutes");
415 InitializeObjectAttributes(&ObjectAttributes,
416 &KeyName,
417 OBJ_CASE_INSENSITIVE,
418 NULL,
419 NULL);
420
421 Status = NtCreateKey(&SubKeyHandle,
422 KEY_SET_VALUE,
423 &ObjectAttributes,
424 0,
425 NULL,
426 0,
427 &Disposition);
428
429 if(!NT_SUCCESS(Status))
430 {
431 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
432 NtClose(SubKeyHandle);
433 NtClose(KeyHandle);
434 return FALSE;
435 }
436
437 do
438 {
439 if (uIndex > 19) break;
440
441 swprintf(szValueName, L"%u", uIndex + 1);
442 RtlInitUnicodeString(&ValueName, szValueName);
443
444 swprintf(szLangID, L"0000%s", MuiLayouts[uIndex].LangID);
445
446 if (_wcsicmp(szLangID, MuiLayouts[uIndex].LayoutID) == 0)
447 {
448 Status = NtSetValueKey(KeyHandle,
449 &ValueName,
450 0,
451 REG_SZ,
452 (PVOID)MuiLayouts[uIndex].LayoutID,
453 (wcslen(MuiLayouts[uIndex].LayoutID)+1) * sizeof(WCHAR));
454 if (!NT_SUCCESS(Status))
455 {
456 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
457 NtClose(SubKeyHandle);
458 NtClose(KeyHandle);
459 return FALSE;
460 }
461 }
462 else
463 {
464 swprintf(szLangID, L"d%03u%s", uCount, MuiLayouts[uIndex].LangID);
465 Status = NtSetValueKey(KeyHandle,
466 &ValueName,
467 0,
468 REG_SZ,
469 (PVOID)szLangID,
470 (wcslen(szLangID)+1) * sizeof(WCHAR));
471 if (!NT_SUCCESS(Status))
472 {
473 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
474 NtClose(SubKeyHandle);
475 NtClose(KeyHandle);
476 return FALSE;
477 }
478
479 RtlInitUnicodeString(&ValueName, szLangID);
480
481 Status = NtSetValueKey(SubKeyHandle,
482 &ValueName,
483 0,
484 REG_SZ,
485 (PVOID)MuiLayouts[uIndex].LayoutID,
486 (wcslen(MuiLayouts[uIndex].LayoutID)+1) * sizeof(WCHAR));
487 if (!NT_SUCCESS(Status))
488 {
489 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %u)\n", Status, uIndex);
490 NtClose(SubKeyHandle);
491 NtClose(KeyHandle);
492 return FALSE;
493 }
494
495 uCount++;
496 }
497
498 uIndex++;
499 }
500 while (MuiLayouts[uIndex].LangID != NULL);
501
502 if (uIndex > 1)
503 AddHotkeySettings(L"2", L"2", L"1");
504 else
505 AddHotkeySettings(L"3", L"3", L"3");
506
507 NtClose(SubKeyHandle);
508 NtClose(KeyHandle);
509 return TRUE;
510 }
511
512 BOOLEAN
513 AddKeyboardLayouts(VOID)
514 {
515 ULONG lngIndex = 0;
516 do
517 {
518 if (_wcsicmp(LanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
519 {
520 return AddKbLayoutsToRegistry(LanguageList[lngIndex].MuiLayouts);
521 }
522
523 lngIndex++;
524 }
525 while (LanguageList[lngIndex].MuiPages != NULL);
526
527 return FALSE;
528 }
529
530 static BOOLEAN
531 AddCodepageToRegistry(IN LPCWSTR ACPage, IN LPCWSTR OEMCPage, IN LPCWSTR MACCPage)
532 {
533 OBJECT_ATTRIBUTES ObjectAttributes;
534 UNICODE_STRING KeyName;
535 UNICODE_STRING ValueName;
536 HANDLE KeyHandle;
537 NTSTATUS Status;
538
539 // Open the nls codepage key
540 RtlInitUnicodeString(&KeyName,
541 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage");
542 InitializeObjectAttributes(&ObjectAttributes,
543 &KeyName,
544 OBJ_CASE_INSENSITIVE,
545 NULL,
546 NULL);
547 Status = NtOpenKey(&KeyHandle,
548 KEY_WRITE,
549 &ObjectAttributes);
550 if (!NT_SUCCESS(Status))
551 {
552 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
553 return FALSE;
554 }
555
556 // Set ANSI codepage
557 RtlInitUnicodeString(&ValueName, L"ACP");
558 Status = NtSetValueKey(KeyHandle,
559 &ValueName,
560 0,
561 REG_SZ,
562 (PVOID)ACPage,
563 (wcslen(ACPage)+1) * sizeof(WCHAR));
564 if (!NT_SUCCESS(Status))
565 {
566 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
567 NtClose(KeyHandle);
568 return FALSE;
569 }
570
571 // Set OEM codepage
572 RtlInitUnicodeString(&ValueName, L"OEMCP");
573 Status = NtSetValueKey(KeyHandle,
574 &ValueName,
575 0,
576 REG_SZ,
577 (PVOID)OEMCPage,
578 (wcslen(OEMCPage)+1) * sizeof(WCHAR));
579 if (!NT_SUCCESS(Status))
580 {
581 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
582 NtClose(KeyHandle);
583 return FALSE;
584 }
585
586 // Set MAC codepage
587 RtlInitUnicodeString(&ValueName, L"MACCP");
588 Status = NtSetValueKey(KeyHandle,
589 &ValueName,
590 0,
591 REG_SZ,
592 (PVOID)MACCPage,
593 (wcslen(MACCPage)+1) * sizeof(WCHAR));
594 if (!NT_SUCCESS(Status))
595 {
596 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
597 NtClose(KeyHandle);
598 return FALSE;
599 }
600
601 NtClose(KeyHandle);
602
603 return TRUE;
604 }
605
606 static BOOLEAN
607 AddFontsSettingsToRegistry(IN const MUI_SUBFONT * MuiSubFonts)
608 {
609 OBJECT_ATTRIBUTES ObjectAttributes;
610 UNICODE_STRING KeyName;
611 UNICODE_STRING ValueName;
612 HANDLE KeyHandle;
613 NTSTATUS Status;
614 ULONG uIndex = 0;
615
616 RtlInitUnicodeString(&KeyName,
617 L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
618 InitializeObjectAttributes(&ObjectAttributes,
619 &KeyName,
620 OBJ_CASE_INSENSITIVE,
621 NULL,
622 NULL);
623 Status = NtOpenKey(&KeyHandle,
624 KEY_WRITE,
625 &ObjectAttributes);
626 if (!NT_SUCCESS(Status))
627 {
628 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
629 return FALSE;
630 }
631
632 do
633 {
634 RtlInitUnicodeString(&ValueName, MuiSubFonts[uIndex].FontName);
635 Status = NtSetValueKey(KeyHandle,
636 &ValueName,
637 0,
638 REG_SZ,
639 (PVOID)MuiSubFonts[uIndex].SubFontName,
640 (wcslen(MuiSubFonts[uIndex].SubFontName)+1) * sizeof(WCHAR));
641 if (!NT_SUCCESS(Status))
642 {
643 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
644 NtClose(KeyHandle);
645 return FALSE;
646 }
647
648 uIndex++;
649 }
650 while (MuiSubFonts[uIndex].FontName != NULL);
651
652 NtClose(KeyHandle);
653
654 return TRUE;
655 }
656
657 BOOLEAN
658 AddCodePage(VOID)
659 {
660 ULONG lngIndex = 0;
661 do
662 {
663 if (_wcsicmp(LanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
664 {
665 if (AddCodepageToRegistry(LanguageList[lngIndex].ACPage,
666 LanguageList[lngIndex].OEMCPage,
667 LanguageList[lngIndex].MACCPage)&&
668 AddFontsSettingsToRegistry(LanguageList[lngIndex].MuiSubFonts))
669 {
670 return TRUE;
671 }
672 else
673 {
674 return FALSE;
675 }
676 }
677
678 lngIndex++;
679 }
680 while (LanguageList[lngIndex].MuiPages != NULL);
681
682 return FALSE;
683 }
684
685 VOID
686 SetConsoleCodePage(VOID)
687 {
688 ULONG lngIndex = 0;
689 UINT wCodePage;
690
691 do
692 {
693 if (_wcsicmp(LanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
694 {
695 wCodePage = (UINT) wcstoul(LanguageList[lngIndex].OEMCPage, NULL, 10);
696 SetConsoleOutputCP(wCodePage);
697 return;
698 }
699
700 lngIndex++;
701 }
702 while (LanguageList[lngIndex].MuiPages != NULL);
703 }
704
705 /* EOF */