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 /* INCLUDES *****************************************************************/ 28 29 #include "precomp.h" 30 #include "mui.h" 31 #include "muifonts.h" 32 #include "muilanguages.h" 33 #include "registry.h" 34 #include "substset.h" 35 36 #define NDEBUG 37 #include <debug.h> 38 39 40 /* FUNCTIONS ****************************************************************/ 41 42 static 43 ULONG 44 FindLanguageIndex( 45 IN PCWSTR LanguageId) 46 { 47 ULONG lngIndex = 0; 48 49 if (LanguageId == NULL) 50 { 51 /* Default to en-US */ 52 // return 0; // FIXME!! 53 LanguageId = L"00000409"; 54 } 55 56 while (MUILanguageList[lngIndex].LanguageID != NULL) 57 { 58 if (_wcsicmp(MUILanguageList[lngIndex].LanguageID, LanguageId) == 0) 59 { 60 return lngIndex; 61 } 62 63 lngIndex++; 64 } 65 66 return 0; 67 } 68 69 BOOLEAN 70 IsLanguageAvailable( 71 IN PCWSTR LanguageId) 72 { 73 ULONG lngIndex = 0; 74 75 while (MUILanguageList[lngIndex].LanguageID != NULL) 76 { 77 if (_wcsicmp(MUILanguageList[lngIndex].LanguageID, LanguageId) == 0) 78 return TRUE; 79 80 lngIndex++; 81 } 82 83 return FALSE; 84 } 85 86 87 KLID 88 MUIDefaultKeyboardLayout( 89 IN PCWSTR LanguageId) 90 { 91 ULONG lngIndex = FindLanguageIndex(LanguageId); 92 return MUILanguageList[lngIndex].MuiLayouts[0].LayoutID; 93 } 94 95 UINT 96 MUIGetOEMCodePage( 97 IN PCWSTR LanguageId) 98 { 99 ULONG lngIndex = FindLanguageIndex(LanguageId); 100 return MUILanguageList[lngIndex].OEMCPage; 101 } 102 103 GEOID 104 MUIGetGeoID( 105 IN PCWSTR LanguageId) 106 { 107 ULONG lngIndex = FindLanguageIndex(LanguageId); 108 return MUILanguageList[lngIndex].GeoID; 109 } 110 111 const MUI_LAYOUTS* 112 MUIGetLayoutsList( 113 IN PCWSTR LanguageId) 114 { 115 ULONG lngIndex = FindLanguageIndex(LanguageId); 116 return MUILanguageList[lngIndex].MuiLayouts; 117 } 118 119 120 static 121 BOOLEAN 122 AddHotkeySettings( 123 IN PCWSTR Hotkey, 124 IN PCWSTR LangHotkey, 125 IN PCWSTR LayoutHotkey) 126 { 127 OBJECT_ATTRIBUTES ObjectAttributes; 128 UNICODE_STRING KeyName; 129 UNICODE_STRING ValueName; 130 HANDLE KeyHandle; 131 ULONG Disposition; 132 NTSTATUS Status; 133 134 RtlInitUnicodeString(&KeyName, 135 L".DEFAULT\\Keyboard Layout\\Toggle"); 136 InitializeObjectAttributes(&ObjectAttributes, 137 &KeyName, 138 OBJ_CASE_INSENSITIVE, 139 GetRootKeyByPredefKey(HKEY_USERS, NULL), 140 NULL); 141 142 Status = NtCreateKey(&KeyHandle, 143 KEY_SET_VALUE, 144 &ObjectAttributes, 145 0, 146 NULL, 147 REG_OPTION_NON_VOLATILE, 148 &Disposition); 149 if (!NT_SUCCESS(Status)) 150 { 151 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status); 152 return FALSE; 153 } 154 155 RtlInitUnicodeString(&ValueName, 156 L"Hotkey"); 157 158 Status = NtSetValueKey(KeyHandle, 159 &ValueName, 160 0, 161 REG_SZ, 162 (PVOID)Hotkey, 163 (1 + 1) * sizeof(WCHAR)); 164 if (!NT_SUCCESS(Status)) 165 { 166 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status); 167 NtClose(KeyHandle); 168 return FALSE; 169 } 170 171 RtlInitUnicodeString(&ValueName, 172 L"Language Hotkey"); 173 174 Status = NtSetValueKey(KeyHandle, 175 &ValueName, 176 0, 177 REG_SZ, 178 (PVOID)LangHotkey, 179 (1 + 1) * sizeof(WCHAR)); 180 if (!NT_SUCCESS(Status)) 181 { 182 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status); 183 NtClose(KeyHandle); 184 return FALSE; 185 } 186 187 RtlInitUnicodeString(&ValueName, 188 L"Layout Hotkey"); 189 190 Status = NtSetValueKey(KeyHandle, 191 &ValueName, 192 0, 193 REG_SZ, 194 (PVOID)LayoutHotkey, 195 (1 + 1) * sizeof(WCHAR)); 196 if (!NT_SUCCESS(Status)) 197 { 198 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status); 199 NtClose(KeyHandle); 200 return FALSE; 201 } 202 203 NtClose(KeyHandle); 204 return TRUE; 205 } 206 207 BOOLEAN 208 AddKbLayoutsToRegistry( 209 _In_ const MUI_LAYOUTS* MuiLayouts) 210 { 211 OBJECT_ATTRIBUTES ObjectAttributes; 212 UNICODE_STRING KeyName; 213 UNICODE_STRING ValueName; 214 HANDLE KeyHandle; 215 HANDLE SubKeyHandle; 216 NTSTATUS Status; 217 ULONG Disposition; 218 ULONG uIndex; 219 ULONG uCount; 220 WCHAR szKeyName[48] = L".DEFAULT\\Keyboard Layout"; 221 WCHAR szValueName[3 + 1]; 222 WCHAR szSubstID[8 + 1]; 223 WCHAR szLayoutID[8 + 1]; 224 225 /* Open the keyboard layout key */ 226 RtlInitUnicodeString(&KeyName, szKeyName); 227 InitializeObjectAttributes(&ObjectAttributes, 228 &KeyName, 229 OBJ_CASE_INSENSITIVE, 230 GetRootKeyByPredefKey(HKEY_USERS, NULL), 231 NULL); 232 233 Status = NtCreateKey(&KeyHandle, 234 KEY_CREATE_SUB_KEY, 235 &ObjectAttributes, 236 0, 237 NULL, 238 REG_OPTION_NON_VOLATILE, 239 &Disposition); 240 if (!NT_SUCCESS(Status)) 241 { 242 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status); 243 return FALSE; 244 } 245 246 NtClose(KeyHandle); 247 248 KeyName.MaximumLength = sizeof(szKeyName); 249 Status = RtlAppendUnicodeToString(&KeyName, L"\\Preload"); 250 if (!NT_SUCCESS(Status)) 251 { 252 DPRINT1("RtlAppend() failed (%lx), string is '%wZ'\n", Status, &KeyName); 253 return FALSE; 254 } 255 256 InitializeObjectAttributes(&ObjectAttributes, 257 &KeyName, 258 OBJ_CASE_INSENSITIVE, 259 GetRootKeyByPredefKey(HKEY_USERS, NULL), 260 NULL); 261 262 Status = NtCreateKey(&KeyHandle, 263 KEY_SET_VALUE, 264 &ObjectAttributes, 265 0, 266 NULL, 267 REG_OPTION_NON_VOLATILE, 268 &Disposition); 269 if (!NT_SUCCESS(Status)) 270 { 271 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status); 272 return FALSE; 273 } 274 275 RtlInitUnicodeString(&KeyName, L".DEFAULT\\Keyboard Layout\\Substitutes"); 276 InitializeObjectAttributes(&ObjectAttributes, 277 &KeyName, 278 OBJ_CASE_INSENSITIVE, 279 GetRootKeyByPredefKey(HKEY_USERS, NULL), 280 NULL); 281 282 Status = NtCreateKey(&SubKeyHandle, 283 KEY_SET_VALUE, 284 &ObjectAttributes, 285 0, 286 NULL, 287 REG_OPTION_NON_VOLATILE, 288 &Disposition); 289 if (!NT_SUCCESS(Status)) 290 { 291 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status); 292 goto Quit; 293 } 294 295 uCount = 0; 296 for (uIndex = 0; (uIndex <= 19) && (MuiLayouts[uIndex].LangID != 0); ++uIndex) 297 { 298 RtlStringCchPrintfW(szValueName, _countof(szValueName), L"%u", uIndex + 1); 299 RtlInitUnicodeString(&ValueName, szValueName); 300 301 RtlStringCchPrintfW(szLayoutID, _countof(szLayoutID), L"%08lx", MuiLayouts[uIndex].LayoutID); 302 303 if ((KLID)MuiLayouts[uIndex].LangID == MuiLayouts[uIndex].LayoutID) 304 { 305 /* Main keyboard layout */ 306 Status = NtSetValueKey(KeyHandle, 307 &ValueName, 308 0, 309 REG_SZ, 310 (PVOID)szLayoutID, 311 (wcslen(szLayoutID)+1) * sizeof(WCHAR)); 312 if (!NT_SUCCESS(Status)) 313 { 314 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %u)\n", Status, uIndex); 315 goto Quit; 316 } 317 } 318 else 319 { 320 /* Generate a substitute keyboard layout ID */ 321 RtlStringCchPrintfW(szSubstID, _countof(szSubstID), L"%08lx", 322 (0xD0000000/*SUBST_MASK*/ | ((USHORT)uCount << 4) | MuiLayouts[uIndex].LangID)); 323 Status = NtSetValueKey(KeyHandle, 324 &ValueName, 325 0, 326 REG_SZ, 327 (PVOID)szSubstID, 328 (wcslen(szSubstID)+1) * sizeof(WCHAR)); 329 if (!NT_SUCCESS(Status)) 330 { 331 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %u)\n", Status, uIndex); 332 goto Quit; 333 } 334 335 /* Link the substitute layout with the original one */ 336 RtlInitUnicodeString(&ValueName, szSubstID); 337 Status = NtSetValueKey(SubKeyHandle, 338 &ValueName, 339 0, 340 REG_SZ, 341 (PVOID)szLayoutID, 342 (wcslen(szLayoutID)+1) * sizeof(WCHAR)); 343 if (!NT_SUCCESS(Status)) 344 { 345 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %u)\n", Status, uIndex); 346 goto Quit; 347 } 348 349 ++uCount; 350 } 351 } 352 353 AddHotkeySettings(L"1", L"1", L"2"); 354 355 Quit: 356 NtClose(SubKeyHandle); 357 NtClose(KeyHandle); 358 return NT_SUCCESS(Status); 359 } 360 361 BOOLEAN 362 AddKeyboardLayouts( 363 IN PCWSTR LanguageId) 364 { 365 ULONG lngIndex = 0; 366 367 while (MUILanguageList[lngIndex].LanguageID != NULL) 368 { 369 if (_wcsicmp(MUILanguageList[lngIndex].LanguageID, LanguageId) == 0) 370 { 371 return AddKbLayoutsToRegistry(MUILanguageList[lngIndex].MuiLayouts); 372 } 373 374 lngIndex++; 375 } 376 377 return FALSE; 378 } 379 380 static 381 BOOLEAN 382 AddCodepageToRegistry( 383 _In_ UINT ACPage, 384 _In_ UINT OEMCPage, 385 _In_ UINT MACCPage) 386 { 387 NTSTATUS Status; 388 OBJECT_ATTRIBUTES ObjectAttributes; 389 UNICODE_STRING Name; 390 HANDLE KeyHandle; 391 /* 392 * Buffer big enough to hold the NULL-terminated string L"4294967295", 393 * corresponding to the literal 0xFFFFFFFF (MAXULONG) in decimal. 394 */ 395 WCHAR Value[sizeof("4294967295")]; 396 397 /* Open the NLS CodePage key */ 398 RtlInitUnicodeString(&Name, 399 L"SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage"); 400 InitializeObjectAttributes(&ObjectAttributes, 401 &Name, 402 OBJ_CASE_INSENSITIVE, 403 GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL), 404 NULL); 405 Status = NtOpenKey(&KeyHandle, 406 KEY_WRITE, 407 &ObjectAttributes); 408 if (!NT_SUCCESS(Status)) 409 { 410 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status); 411 return FALSE; 412 } 413 414 /* Set ANSI codepage */ 415 Status = RtlStringCchPrintfW(Value, _countof(Value), L"%lu", ACPage); 416 ASSERT(NT_SUCCESS(Status)); 417 418 RtlInitUnicodeString(&Name, L"ACP"); 419 Status = NtSetValueKey(KeyHandle, 420 &Name, 421 0, 422 REG_SZ, 423 (PVOID)Value, 424 (wcslen(Value)+1) * sizeof(WCHAR)); 425 if (!NT_SUCCESS(Status)) 426 { 427 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status); 428 goto Quit; 429 } 430 431 /* Set OEM codepage */ 432 Status = RtlStringCchPrintfW(Value, _countof(Value), L"%lu", OEMCPage); 433 ASSERT(NT_SUCCESS(Status)); 434 435 RtlInitUnicodeString(&Name, L"OEMCP"); 436 Status = NtSetValueKey(KeyHandle, 437 &Name, 438 0, 439 REG_SZ, 440 (PVOID)Value, 441 (wcslen(Value)+1) * sizeof(WCHAR)); 442 if (!NT_SUCCESS(Status)) 443 { 444 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status); 445 goto Quit; 446 } 447 448 /* Set MAC codepage */ 449 Status = RtlStringCchPrintfW(Value, _countof(Value), L"%lu", MACCPage); 450 ASSERT(NT_SUCCESS(Status)); 451 452 RtlInitUnicodeString(&Name, L"MACCP"); 453 Status = NtSetValueKey(KeyHandle, 454 &Name, 455 0, 456 REG_SZ, 457 (PVOID)Value, 458 (wcslen(Value)+1) * sizeof(WCHAR)); 459 if (!NT_SUCCESS(Status)) 460 { 461 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status); 462 goto Quit; 463 } 464 465 Quit: 466 NtClose(KeyHandle); 467 return NT_SUCCESS(Status); 468 } 469 470 static 471 BOOLEAN 472 AddFontsSettingsToRegistry( 473 IN const MUI_SUBFONT * MuiSubFonts) 474 { 475 OBJECT_ATTRIBUTES ObjectAttributes; 476 UNICODE_STRING KeyName; 477 UNICODE_STRING ValueName; 478 HANDLE KeyHandle; 479 NTSTATUS Status; 480 ULONG uIndex = 0; 481 482 RtlInitUnicodeString(&KeyName, 483 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes"); 484 InitializeObjectAttributes(&ObjectAttributes, 485 &KeyName, 486 OBJ_CASE_INSENSITIVE, 487 GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL), 488 NULL); 489 Status = NtOpenKey(&KeyHandle, 490 KEY_WRITE, 491 &ObjectAttributes); 492 if (!NT_SUCCESS(Status)) 493 { 494 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status); 495 return FALSE; 496 } 497 498 while (MuiSubFonts[uIndex].FontName != NULL) 499 { 500 RtlInitUnicodeString(&ValueName, MuiSubFonts[uIndex].FontName); 501 if (MuiSubFonts[uIndex].SubFontName) 502 { 503 Status = NtSetValueKey(KeyHandle, 504 &ValueName, 505 0, 506 REG_SZ, 507 (PVOID)MuiSubFonts[uIndex].SubFontName, 508 (wcslen(MuiSubFonts[uIndex].SubFontName)+1) * sizeof(WCHAR)); 509 if (!NT_SUCCESS(Status)) 510 { 511 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex); 512 NtClose(KeyHandle); 513 return FALSE; 514 } 515 } 516 else 517 { 518 Status = NtDeleteValueKey(KeyHandle, &ValueName); 519 if (!NT_SUCCESS(Status)) 520 { 521 DPRINT1("NtDeleteValueKey failed, Status = %lx\n", Status); 522 } 523 } 524 525 uIndex++; 526 } 527 528 NtClose(KeyHandle); 529 530 return TRUE; 531 } 532 533 BOOLEAN 534 AddCodePage( 535 IN PCWSTR LanguageId) 536 { 537 ULONG lngIndex = 0; 538 539 while (MUILanguageList[lngIndex].LanguageID != NULL) 540 { 541 if (_wcsicmp(MUILanguageList[lngIndex].LanguageID, LanguageId) == 0) 542 { 543 if (AddCodepageToRegistry(MUILanguageList[lngIndex].ACPage, 544 MUILanguageList[lngIndex].OEMCPage, 545 MUILanguageList[lngIndex].MACCPage) && 546 AddFontsSettingsToRegistry(MUILanguageList[lngIndex].MuiSubFonts)) 547 { 548 return TRUE; 549 } 550 else 551 { 552 return FALSE; 553 } 554 } 555 556 lngIndex++; 557 } 558 559 return FALSE; 560 } 561 562 #ifdef __REACTOS__ /* HACK */ 563 BOOL 564 DoRegistryFontFixup(PFONTSUBSTSETTINGS pSettings, LANGID LangID) 565 { 566 if (pSettings->bFoundFontMINGLIU) 567 AddFontsSettingsToRegistry(FontFixupMINGLIU); 568 if (pSettings->bFoundFontSIMSUN) 569 AddFontsSettingsToRegistry(FontFixupSIMSUN); 570 if (pSettings->bFoundFontMSSONG) 571 AddFontsSettingsToRegistry(FontFixupMSSONG); 572 if (pSettings->bFoundFontMSGOTHIC) 573 AddFontsSettingsToRegistry(FontFixupMSGOTHIC); 574 if (pSettings->bFoundFontMSMINCHO) 575 AddFontsSettingsToRegistry(FontFixupMSMINCHO); 576 if (pSettings->bFoundFontGULIM) 577 AddFontsSettingsToRegistry(FontFixupGULIM); 578 if (pSettings->bFoundFontBATANG) 579 AddFontsSettingsToRegistry(FontFixupBATANG); 580 581 switch (PRIMARYLANGID(LangID)) 582 { 583 case LANG_CHINESE: 584 if (SUBLANGID(LangID) == SUBLANG_CHINESE_SIMPLIFIED) 585 { 586 if (pSettings->bFoundFontSIMSUN) 587 AddFontsSettingsToRegistry(SimplifiedChineseFontFixup); 588 } 589 else 590 { 591 if (pSettings->bFoundFontMINGLIU) 592 AddFontsSettingsToRegistry(TraditionalChineseFontFixup); 593 } 594 break; 595 596 case LANG_JAPANESE: 597 if (pSettings->bFoundFontMSGOTHIC) 598 AddFontsSettingsToRegistry(JapaneseFontFixup); 599 break; 600 601 case LANG_KOREAN: 602 if (pSettings->bFoundFontBATANG) 603 AddFontsSettingsToRegistry(KoreanFontFixup); 604 break; 605 } 606 607 return TRUE; 608 } 609 #endif /* HACK */ 610 611 /* EOF */ 612