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