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