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 PCWSTR 88 MUIDefaultKeyboardLayout( 89 IN PCWSTR LanguageId) 90 { 91 ULONG lngIndex = max(FindLanguageIndex(LanguageId), 0); 92 return MUILanguageList[lngIndex].MuiLayouts[0].LayoutID; 93 } 94 95 PCWSTR 96 MUIGetOEMCodePage( 97 IN PCWSTR LanguageId) 98 { 99 ULONG lngIndex = max(FindLanguageIndex(LanguageId), 0); 100 return MUILanguageList[lngIndex].OEMCPage; 101 } 102 103 PCWSTR 104 MUIGetGeoID( 105 IN PCWSTR LanguageId) 106 { 107 ULONG lngIndex = max(FindLanguageIndex(LanguageId), 0); 108 return MUILanguageList[lngIndex].GeoID; 109 } 110 111 const MUI_LAYOUTS* 112 MUIGetLayoutsList( 113 IN PCWSTR LanguageId) 114 { 115 ULONG lngIndex = max(FindLanguageIndex(LanguageId), 0); 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 = 0; 219 ULONG uCount = 0; 220 WCHAR szKeyName[48] = L".DEFAULT\\Keyboard Layout"; 221 WCHAR szValueName[3 + 1]; 222 WCHAR szLangID[8 + 1]; 223 224 // Open the keyboard layout key 225 RtlInitUnicodeString(&KeyName, szKeyName); 226 InitializeObjectAttributes(&ObjectAttributes, 227 &KeyName, 228 OBJ_CASE_INSENSITIVE, 229 GetRootKeyByPredefKey(HKEY_USERS, NULL), 230 NULL); 231 232 Status = NtCreateKey(&KeyHandle, 233 KEY_CREATE_SUB_KEY, 234 &ObjectAttributes, 235 0, 236 NULL, 237 REG_OPTION_NON_VOLATILE, 238 &Disposition); 239 if (!NT_SUCCESS(Status)) 240 { 241 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status); 242 return FALSE; 243 } 244 245 NtClose(KeyHandle); 246 247 KeyName.MaximumLength = sizeof(szKeyName); 248 Status = RtlAppendUnicodeToString(&KeyName, L"\\Preload"); 249 250 if (!NT_SUCCESS(Status)) 251 { 252 DPRINT1("RtlAppend failed! (%lx)\n", Status); 253 DPRINT1("String is %wZ\n", &KeyName); 254 return FALSE; 255 } 256 257 InitializeObjectAttributes(&ObjectAttributes, 258 &KeyName, 259 OBJ_CASE_INSENSITIVE, 260 GetRootKeyByPredefKey(HKEY_USERS, NULL), 261 NULL); 262 263 Status = NtCreateKey(&KeyHandle, 264 KEY_SET_VALUE, 265 &ObjectAttributes, 266 0, 267 NULL, 268 REG_OPTION_NON_VOLATILE, 269 &Disposition); 270 if (!NT_SUCCESS(Status)) 271 { 272 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status); 273 return FALSE; 274 } 275 276 RtlInitUnicodeString(&KeyName, L".DEFAULT\\Keyboard Layout\\Substitutes"); 277 InitializeObjectAttributes(&ObjectAttributes, 278 &KeyName, 279 OBJ_CASE_INSENSITIVE, 280 GetRootKeyByPredefKey(HKEY_USERS, NULL), 281 NULL); 282 283 Status = NtCreateKey(&SubKeyHandle, 284 KEY_SET_VALUE, 285 &ObjectAttributes, 286 0, 287 NULL, 288 REG_OPTION_NON_VOLATILE, 289 &Disposition); 290 if (!NT_SUCCESS(Status)) 291 { 292 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status); 293 NtClose(SubKeyHandle); 294 NtClose(KeyHandle); 295 return FALSE; 296 } 297 298 while (MuiLayouts[uIndex].LangID != NULL) 299 { 300 if (uIndex > 19) break; 301 302 RtlStringCchPrintfW(szValueName, ARRAYSIZE(szValueName), L"%u", uIndex + 1); 303 RtlInitUnicodeString(&ValueName, szValueName); 304 305 RtlStringCchPrintfW(szLangID, ARRAYSIZE(szLangID), L"0000%s", MuiLayouts[uIndex].LangID); 306 307 if (_wcsicmp(szLangID, MuiLayouts[uIndex].LayoutID) == 0) 308 { 309 Status = NtSetValueKey(KeyHandle, 310 &ValueName, 311 0, 312 REG_SZ, 313 (PVOID)MuiLayouts[uIndex].LayoutID, 314 (wcslen(MuiLayouts[uIndex].LayoutID)+1) * sizeof(WCHAR)); 315 if (!NT_SUCCESS(Status)) 316 { 317 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex); 318 NtClose(SubKeyHandle); 319 NtClose(KeyHandle); 320 return FALSE; 321 } 322 } 323 else 324 { 325 RtlStringCchPrintfW(szLangID, ARRAYSIZE(szLangID), L"d%03lu%s", uCount, MuiLayouts[uIndex].LangID); 326 Status = NtSetValueKey(KeyHandle, 327 &ValueName, 328 0, 329 REG_SZ, 330 (PVOID)szLangID, 331 (wcslen(szLangID)+1) * sizeof(WCHAR)); 332 if (!NT_SUCCESS(Status)) 333 { 334 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex); 335 NtClose(SubKeyHandle); 336 NtClose(KeyHandle); 337 return FALSE; 338 } 339 340 RtlInitUnicodeString(&ValueName, szLangID); 341 342 Status = NtSetValueKey(SubKeyHandle, 343 &ValueName, 344 0, 345 REG_SZ, 346 (PVOID)MuiLayouts[uIndex].LayoutID, 347 (wcslen(MuiLayouts[uIndex].LayoutID)+1) * sizeof(WCHAR)); 348 if (!NT_SUCCESS(Status)) 349 { 350 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %u)\n", Status, uIndex); 351 NtClose(SubKeyHandle); 352 NtClose(KeyHandle); 353 return FALSE; 354 } 355 356 uCount++; 357 } 358 359 uIndex++; 360 } 361 362 if (uIndex > 1) 363 AddHotkeySettings(L"2", L"2", L"1"); 364 else 365 AddHotkeySettings(L"3", L"3", L"3"); 366 367 NtClose(SubKeyHandle); 368 NtClose(KeyHandle); 369 return TRUE; 370 } 371 372 BOOLEAN 373 AddKeyboardLayouts( 374 IN PCWSTR LanguageId) 375 { 376 ULONG lngIndex = 0; 377 378 while (MUILanguageList[lngIndex].LanguageID != NULL) 379 { 380 if (_wcsicmp(MUILanguageList[lngIndex].LanguageID, LanguageId) == 0) 381 { 382 return AddKbLayoutsToRegistry(MUILanguageList[lngIndex].MuiLayouts); 383 } 384 385 lngIndex++; 386 } 387 388 return FALSE; 389 } 390 391 static 392 BOOLEAN 393 AddCodepageToRegistry( 394 IN PCWSTR ACPage, 395 IN PCWSTR OEMCPage, 396 IN PCWSTR MACCPage) 397 { 398 OBJECT_ATTRIBUTES ObjectAttributes; 399 UNICODE_STRING KeyName; 400 UNICODE_STRING ValueName; 401 HANDLE KeyHandle; 402 NTSTATUS Status; 403 404 // Open the nls codepage key 405 RtlInitUnicodeString(&KeyName, 406 L"SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage"); 407 InitializeObjectAttributes(&ObjectAttributes, 408 &KeyName, 409 OBJ_CASE_INSENSITIVE, 410 GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL), 411 NULL); 412 Status = NtOpenKey(&KeyHandle, 413 KEY_WRITE, 414 &ObjectAttributes); 415 if (!NT_SUCCESS(Status)) 416 { 417 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status); 418 return FALSE; 419 } 420 421 // Set ANSI codepage 422 RtlInitUnicodeString(&ValueName, L"ACP"); 423 Status = NtSetValueKey(KeyHandle, 424 &ValueName, 425 0, 426 REG_SZ, 427 (PVOID)ACPage, 428 (wcslen(ACPage)+1) * sizeof(WCHAR)); 429 if (!NT_SUCCESS(Status)) 430 { 431 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status); 432 NtClose(KeyHandle); 433 return FALSE; 434 } 435 436 // Set OEM codepage 437 RtlInitUnicodeString(&ValueName, L"OEMCP"); 438 Status = NtSetValueKey(KeyHandle, 439 &ValueName, 440 0, 441 REG_SZ, 442 (PVOID)OEMCPage, 443 (wcslen(OEMCPage)+1) * sizeof(WCHAR)); 444 if (!NT_SUCCESS(Status)) 445 { 446 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status); 447 NtClose(KeyHandle); 448 return FALSE; 449 } 450 451 // Set MAC codepage 452 RtlInitUnicodeString(&ValueName, L"MACCP"); 453 Status = NtSetValueKey(KeyHandle, 454 &ValueName, 455 0, 456 REG_SZ, 457 (PVOID)MACCPage, 458 (wcslen(MACCPage)+1) * sizeof(WCHAR)); 459 if (!NT_SUCCESS(Status)) 460 { 461 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status); 462 NtClose(KeyHandle); 463 return FALSE; 464 } 465 466 NtClose(KeyHandle); 467 468 return TRUE; 469 } 470 471 static 472 BOOLEAN 473 AddFontsSettingsToRegistry( 474 IN const MUI_SUBFONT * MuiSubFonts) 475 { 476 OBJECT_ATTRIBUTES ObjectAttributes; 477 UNICODE_STRING KeyName; 478 UNICODE_STRING ValueName; 479 HANDLE KeyHandle; 480 NTSTATUS Status; 481 ULONG uIndex = 0; 482 483 RtlInitUnicodeString(&KeyName, 484 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes"); 485 InitializeObjectAttributes(&ObjectAttributes, 486 &KeyName, 487 OBJ_CASE_INSENSITIVE, 488 GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL), 489 NULL); 490 Status = NtOpenKey(&KeyHandle, 491 KEY_WRITE, 492 &ObjectAttributes); 493 if (!NT_SUCCESS(Status)) 494 { 495 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status); 496 return FALSE; 497 } 498 499 while (MuiSubFonts[uIndex].FontName != NULL) 500 { 501 RtlInitUnicodeString(&ValueName, MuiSubFonts[uIndex].FontName); 502 if (MuiSubFonts[uIndex].SubFontName) 503 { 504 Status = NtSetValueKey(KeyHandle, 505 &ValueName, 506 0, 507 REG_SZ, 508 (PVOID)MuiSubFonts[uIndex].SubFontName, 509 (wcslen(MuiSubFonts[uIndex].SubFontName)+1) * sizeof(WCHAR)); 510 if (!NT_SUCCESS(Status)) 511 { 512 DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex); 513 NtClose(KeyHandle); 514 return FALSE; 515 } 516 } 517 else 518 { 519 Status = NtDeleteValueKey(KeyHandle, &ValueName); 520 if (!NT_SUCCESS(Status)) 521 { 522 DPRINT1("NtDeleteValueKey failed, Status = %lx\n", Status); 523 } 524 } 525 526 uIndex++; 527 } 528 529 NtClose(KeyHandle); 530 531 return TRUE; 532 } 533 534 BOOLEAN 535 AddCodePage( 536 IN PCWSTR LanguageId) 537 { 538 ULONG lngIndex = 0; 539 540 while (MUILanguageList[lngIndex].LanguageID != NULL) 541 { 542 if (_wcsicmp(MUILanguageList[lngIndex].LanguageID, LanguageId) == 0) 543 { 544 if (AddCodepageToRegistry(MUILanguageList[lngIndex].ACPage, 545 MUILanguageList[lngIndex].OEMCPage, 546 MUILanguageList[lngIndex].MACCPage) && 547 AddFontsSettingsToRegistry(MUILanguageList[lngIndex].MuiSubFonts)) 548 { 549 return TRUE; 550 } 551 else 552 { 553 return FALSE; 554 } 555 } 556 557 lngIndex++; 558 } 559 560 return FALSE; 561 } 562 563 #ifdef __REACTOS__ /* HACK */ 564 BOOL 565 DoRegistryFontFixup(PFONTSUBSTSETTINGS pSettings, LANGID LangID) 566 { 567 if (pSettings->bFoundFontMINGLIU) 568 AddFontsSettingsToRegistry(FontFixupMINGLIU); 569 if (pSettings->bFoundFontSIMSUN) 570 AddFontsSettingsToRegistry(FontFixupSIMSUN); 571 if (pSettings->bFoundFontMSSONG) 572 AddFontsSettingsToRegistry(FontFixupMSSONG); 573 if (pSettings->bFoundFontMSGOTHIC) 574 AddFontsSettingsToRegistry(FontFixupMSGOTHIC); 575 if (pSettings->bFoundFontMSMINCHO) 576 AddFontsSettingsToRegistry(FontFixupMSMINCHO); 577 if (pSettings->bFoundFontGULIM) 578 AddFontsSettingsToRegistry(FontFixupGULIM); 579 if (pSettings->bFoundFontBATANG) 580 AddFontsSettingsToRegistry(FontFixupBATANG); 581 582 switch (PRIMARYLANGID(LangID)) 583 { 584 case LANG_CHINESE: 585 if (SUBLANGID(LangID) == SUBLANG_CHINESE_SIMPLIFIED) 586 { 587 if (pSettings->bFoundFontSIMSUN) 588 AddFontsSettingsToRegistry(SimplifiedChineseFontFixup); 589 } 590 else 591 { 592 if (pSettings->bFoundFontMINGLIU) 593 AddFontsSettingsToRegistry(TraditionalChineseFontFixup); 594 } 595 break; 596 597 case LANG_JAPANESE: 598 if (pSettings->bFoundFontMSGOTHIC) 599 AddFontsSettingsToRegistry(JapaneseFontFixup); 600 break; 601 602 case LANG_KOREAN: 603 if (pSettings->bFoundFontBATANG) 604 AddFontsSettingsToRegistry(KoreanFontFixup); 605 break; 606 } 607 608 return TRUE; 609 } 610 #endif /* HACK */ 611 612 /* EOF */ 613