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