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