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 "muilanguages.h" 29 30 #define NDEBUG 31 #include <debug.h> 32 33 /* Special characters */ 34 CHAR CharBullet = 0x07; /* bullet */ 35 CHAR CharBlock = 0xDB; /* block */ 36 CHAR CharHalfBlock = 0xDD; /* half-left block */ 37 CHAR CharUpArrow = 0x18; /* up arrow */ 38 CHAR CharDownArrow = 0x19; /* down arrow */ 39 CHAR CharHorizontalLine = 0xC4; /* horizontal line */ 40 CHAR CharVerticalLine = 0xB3; /* vertical line */ 41 CHAR CharUpperLeftCorner = 0xDA; /* upper left corner */ 42 CHAR CharUpperRightCorner = 0xBF; /* upper right corner */ 43 CHAR CharLowerLeftCorner = 0xC0; /* lower left corner */ 44 CHAR CharLowerRightCorner = 0xD9; /* lower right corner */ 45 CHAR CharVertLineAndRightHorizLine = 0xC3; /* |- (vertical line and right horizontal line) */ 46 CHAR CharLeftHorizLineAndVertLine = 0xB4; /* -| (left horizontal line and vertical line) */ 47 CHAR CharDoubleHorizontalLine = 0xCD; /* double horizontal line (and underline) */ 48 CHAR CharDoubleVerticalLine = 0xBA; /* double vertical line */ 49 CHAR CharDoubleUpperLeftCorner = 0xC9; /* double upper left corner */ 50 CHAR CharDoubleUpperRightCorner = 0xBB; /* double upper right corner */ 51 CHAR CharDoubleLowerLeftCorner = 0xC8; /* double lower left corner */ 52 CHAR CharDoubleLowerRightCorner = 0xBC; /* double lower right corner */ 53 54 static 55 ULONG 56 FindLanguageIndex(VOID) 57 { 58 ULONG lngIndex = 0; 59 60 if (SelectedLanguageId == NULL) 61 { 62 /* Default to en-US */ 63 return 0; // FIXME!! 64 // SelectedLanguageId = L"00000409"; 65 } 66 67 while (ResourceList[lngIndex].MuiPages != NULL) 68 { 69 if (_wcsicmp(ResourceList[lngIndex].LanguageID, SelectedLanguageId) == 0) 70 { 71 return lngIndex; 72 } 73 74 lngIndex++; 75 } 76 77 return 0; 78 } 79 80 81 #if 0 82 BOOLEAN 83 IsLanguageAvailable( 84 PWCHAR LanguageId) 85 { 86 ULONG lngIndex = 0; 87 88 while (ResourceList[lngIndex].MuiPages != NULL) 89 { 90 if (_wcsicmp(ResourceList[lngIndex].LanguageID, LanguageId) == 0) 91 return TRUE; 92 93 lngIndex++; 94 } 95 96 return FALSE; 97 } 98 #endif 99 100 101 static 102 const MUI_ENTRY * 103 FindMUIEntriesOfPage( 104 IN ULONG PageNumber) 105 { 106 ULONG muiIndex = 0; 107 ULONG lngIndex; 108 const MUI_PAGE * Pages = NULL; 109 110 lngIndex = max(FindLanguageIndex(), 0); 111 Pages = ResourceList[lngIndex].MuiPages; 112 113 while (Pages[muiIndex].MuiEntry != NULL) 114 { 115 if (Pages[muiIndex].Number == PageNumber) 116 return Pages[muiIndex].MuiEntry; 117 118 muiIndex++; 119 } 120 121 return NULL; 122 } 123 124 static 125 const MUI_ERROR * 126 FindMUIErrorEntries(VOID) 127 { 128 ULONG lngIndex = max(FindLanguageIndex(), 0); 129 return ResourceList[lngIndex].MuiErrors; 130 } 131 132 static 133 const MUI_STRING * 134 FindMUIStringEntries(VOID) 135 { 136 ULONG lngIndex = max(FindLanguageIndex(), 0); 137 return ResourceList[lngIndex].MuiStrings; 138 } 139 140 141 VOID 142 MUIClearPage( 143 IN ULONG page) 144 { 145 const MUI_ENTRY * entry; 146 ULONG index; 147 148 entry = FindMUIEntriesOfPage(page); 149 if (!entry) 150 { 151 PopupError("Error: Failed to find translated page", 152 NULL, 153 NULL, 154 POPUP_WAIT_NONE); 155 return; 156 } 157 158 index = 0; 159 while (entry[index].Buffer != NULL) 160 { 161 CONSOLE_ClearStyledText(entry[index].X, 162 entry[index].Y, 163 entry[index].Flags, 164 (USHORT)strlen(entry[index].Buffer)); 165 index++; 166 } 167 } 168 169 VOID 170 MUIDisplayPage( 171 IN ULONG page) 172 { 173 const MUI_ENTRY * entry; 174 ULONG index; 175 176 entry = FindMUIEntriesOfPage(page); 177 if (!entry) 178 { 179 PopupError("Error: Failed to find translated page", 180 NULL, 181 NULL, 182 POPUP_WAIT_NONE); 183 return; 184 } 185 186 index = 0; 187 while (entry[index].Buffer != NULL) 188 { 189 CONSOLE_SetStyledText(entry[index].X, 190 entry[index].Y, 191 entry[index].Flags, 192 entry[index].Buffer); 193 194 index++; 195 } 196 } 197 198 VOID 199 MUIDisplayErrorV( 200 IN ULONG ErrorNum, 201 OUT PINPUT_RECORD Ir, 202 IN ULONG WaitEvent, 203 IN va_list args) 204 { 205 const MUI_ERROR* entry; 206 CHAR Buffer[2048]; 207 208 if (ErrorNum >= ERROR_LAST_ERROR_CODE) 209 { 210 PopupError("Invalid error number provided", 211 "Press ENTER to continue", 212 Ir, 213 POPUP_WAIT_ENTER); 214 return; 215 } 216 217 entry = FindMUIErrorEntries(); 218 if (!entry) 219 { 220 PopupError("Error: Failed to find translated error message", 221 NULL, 222 NULL, 223 POPUP_WAIT_NONE); 224 return; 225 } 226 227 vsprintf(Buffer, entry[ErrorNum].ErrorText, args); 228 229 PopupError(Buffer, 230 entry[ErrorNum].ErrorStatus, 231 Ir, 232 WaitEvent); 233 } 234 235 VOID 236 __cdecl 237 MUIDisplayError( 238 IN ULONG ErrorNum, 239 OUT PINPUT_RECORD Ir, 240 IN ULONG WaitEvent, 241 ...) 242 { 243 va_list arg_ptr; 244 245 va_start(arg_ptr, WaitEvent); 246 MUIDisplayErrorV(ErrorNum, Ir, WaitEvent, arg_ptr); 247 va_end(arg_ptr); 248 } 249 250 PCSTR 251 MUIGetString( 252 ULONG Number) 253 { 254 ULONG i; 255 const MUI_STRING * entry; 256 CHAR szErr[128]; 257 258 entry = FindMUIStringEntries(); 259 if (entry) 260 { 261 for (i = 0; entry[i].Number != 0; i++) 262 { 263 if (entry[i].Number == Number) 264 { 265 return entry[i].String; 266 } 267 } 268 } 269 270 sprintf(szErr, "Error: failed find string id %lu for language index %lu\n", Number, FindLanguageIndex()); 271 272 PopupError(szErr, 273 NULL, 274 NULL, 275 POPUP_WAIT_NONE); 276 277 return "<nostring>"; 278 } 279 280 /** 281 * @MUIGetEntry 282 * 283 * Retrieves a MUI entry of a page, given the page number and the text ID. 284 * 285 * @param[in] Page 286 * The MUI (Multilingual User Interface) entry page number, as a unsigned long integer. 287 * 288 * @param[in] TextID 289 * The text identification number (ID), as a unsigned integer. The parameter is used to identify 290 * its MUI properties like the coordinates, text style flag and its buffer content. 291 * 292 * @return 293 * Returns a constant MUI entry. 294 * 295 */ 296 const MUI_ENTRY * 297 MUIGetEntry( 298 IN ULONG Page, 299 IN INT TextID) 300 { 301 const MUI_ENTRY * entry; 302 ULONG index; 303 304 /* Retrieve the entries of a MUI page */ 305 entry = FindMUIEntriesOfPage(Page); 306 if (!entry) 307 { 308 DPRINT("MUIGetEntryData(): Failed to get the translated entry page!\n"); 309 return NULL; 310 } 311 312 /* Loop over the ID entries and check if it matches with one of them */ 313 for (index = 0; entry[index].Buffer != NULL; index++) 314 { 315 if (entry[index].TextID == TextID) 316 { 317 /* They match so return the MUI entry */ 318 return &entry[index]; 319 } 320 } 321 322 /* Page number or ID are incorrect so in this case bail out */ 323 DPRINT("Couldn't get the MUI entry field from the page!\n"); 324 return NULL; 325 } 326 327 /** 328 * @MUIClearText 329 * 330 * Clears a portion of text from the console output. 331 * 332 * @param[in] Page 333 * The MUI (Multilingual User Interface) entry page number, as a unsigned long integer. 334 * 335 * @param[in] TextID 336 * The text identification number (ID), as an integer. The parameter is used to identify 337 * its MUI properties like the coordinates, text style flag and its buffer content. 338 * 339 * @return 340 * Nothing. 341 * 342 */ 343 VOID 344 MUIClearText( 345 IN ULONG Page, 346 IN INT TextID) 347 { 348 const MUI_ENTRY * entry; 349 ULONG Index = 0; 350 351 /* Get the MUI entry */ 352 entry = MUIGetEntry(Page, TextID); 353 354 if (!entry) 355 return; 356 357 /* Ensure that the text string given by the text ID and page is not NULL */ 358 while (entry[Index].Buffer != NULL) 359 { 360 /* If text ID is not correct, skip the entry */ 361 if (entry[Index].TextID != TextID) 362 { 363 Index++; 364 continue; 365 } 366 367 /* Remove the text by using CONSOLE_ClearTextXY() */ 368 CONSOLE_ClearTextXY( 369 entry[Index].X, 370 entry[Index].Y, 371 (USHORT)strlen(entry[Index].Buffer)); 372 373 /* Increment the index and loop over next entires with the same ID */ 374 Index++; 375 } 376 } 377 378 /** 379 * @MUIClearStyledText 380 * 381 * Clears a portion of text from the console output, given the actual state style flag of the text. 382 * 383 * @param[in] Page 384 * The MUI (Multilingual User Interface) entry page number, as a unsigned long integer. 385 * 386 * @param[in] TextID 387 * The text identification number (ID), as an integer. The parameter is used to identify 388 * its MUI properties like the coordinates, text style flag and its buffer content. 389 * 390 * @param[in] Flags 391 * The text style flag, as an integer. The flag determines the style of the text, such 392 * as being highlighted, underlined, high padding and so on. 393 * 394 * @return 395 * Nothing. 396 * 397 */ 398 VOID 399 MUIClearStyledText( 400 IN ULONG Page, 401 IN INT TextID, 402 IN INT Flags) 403 { 404 const MUI_ENTRY * entry; 405 ULONG Index = 0; 406 407 /* Get the MUI entry */ 408 entry = MUIGetEntry(Page, TextID); 409 410 if (!entry) 411 return; 412 413 /* Ensure that the text string given by the text ID and page is not NULL */ 414 while (entry[Index].Buffer != NULL) 415 { 416 /* If text ID is not correct, skip the entry */ 417 if (entry[Index].TextID != TextID) 418 { 419 Index++; 420 continue; 421 } 422 423 /* Now, begin removing the text by calling CONSOLE_ClearStyledText() */ 424 CONSOLE_ClearStyledText( 425 entry[Index].X, 426 entry[Index].Y, 427 Flags, 428 (USHORT)strlen(entry[Index].Buffer)); 429 430 /* Increment the index and loop over next entires with the same ID */ 431 Index++; 432 } 433 } 434 435 /** 436 * @MUISetText 437 * 438 * Prints a text to the console output. 439 * 440 * @param[in] Page 441 * The MUI (Multilingual User Interface) entry page number, as a unsigned long integer. 442 * 443 * @param[in] TextID 444 * The text identification number (ID), as an integer. The parameter is used to identify 445 * its MUI properties like the coordinates, text style flag and its buffer content. 446 * 447 * @return 448 * Nothing. 449 * 450 */ 451 VOID 452 MUISetText( 453 IN ULONG Page, 454 IN INT TextID) 455 { 456 const MUI_ENTRY * entry; 457 ULONG Index = 0; 458 459 /* Get the MUI entry */ 460 entry = MUIGetEntry(Page, TextID); 461 462 if (!entry) 463 return; 464 465 /* Ensure that the text string given by the text ID and page is not NULL */ 466 while (entry[Index].Buffer != NULL) 467 { 468 /* If text ID is not correct, skip the entry */ 469 if (entry[Index].TextID != TextID) 470 { 471 Index++; 472 continue; 473 } 474 475 /* Print the text to the console output by calling CONSOLE_SetTextXY() */ 476 CONSOLE_SetTextXY(entry[Index].X, entry[Index].Y, entry[Index].Buffer); 477 478 /* Increment the index and loop over next entires with the same ID */ 479 Index++; 480 } 481 } 482 483 /** 484 * @MUISetStyledText 485 * 486 * Prints a text to the console output, with a style for it. 487 * 488 * @param[in] Page 489 * The MUI (Multilingual User Interface) entry page number, as a unsigned long integer. 490 * 491 * @param[in] TextID 492 * The text identification number (ID), as an integer. The parameter is used to identify 493 * its MUI properties like the coordinates, text style flag and its buffer content. 494 * 495 * @param[in] Flags 496 * The text style flag, as an integer. The flag determines the style of the text, such 497 * as being highlighted, underlined, high padding and so on. 498 * 499 * @return 500 * Nothing. 501 * 502 */ 503 VOID 504 MUISetStyledText( 505 IN ULONG Page, 506 IN INT TextID, 507 IN INT Flags) 508 { 509 const MUI_ENTRY * entry; 510 ULONG Index = 0; 511 512 /* Get the MUI entry */ 513 entry = MUIGetEntry(Page, TextID); 514 515 if (!entry) 516 return; 517 518 /* Ensure that the text string given by the text ID and page is not NULL */ 519 while (entry[Index].Buffer != NULL) 520 { 521 /* If text ID is not correct, skip the entry */ 522 if (entry[Index].TextID != TextID) 523 { 524 Index++; 525 continue; 526 } 527 528 /* Print the text to the console output by calling CONSOLE_SetStyledText() */ 529 CONSOLE_SetStyledText(entry[Index].X, entry[Index].Y, Flags, entry[Index].Buffer); 530 531 /* Increment the index and loop over next entires with the same ID */ 532 Index++; 533 } 534 } 535 536 VOID 537 SetConsoleCodePage(VOID) 538 { 539 UINT wCodePage; 540 541 #if 0 542 ULONG lngIndex = 0; 543 544 while (ResourceList[lngIndex].MuiPages != NULL) 545 { 546 if (_wcsicmp(ResourceList[lngIndex].LanguageID, SelectedLanguageId) == 0) 547 { 548 wCodePage = ResourceList[lngIndex].OEMCPage; 549 SetConsoleOutputCP(wCodePage); 550 return; 551 } 552 553 lngIndex++; 554 } 555 #else 556 wCodePage = MUIGetOEMCodePage(SelectedLanguageId); 557 SetConsoleOutputCP(wCodePage); 558 #endif 559 560 switch (wCodePage) 561 { 562 case 28606: /* Romanian */ 563 case 932: /* Japanese */ 564 /* Set special characters */ 565 CharBullet = 0x07; 566 CharBlock = 0x01; 567 CharHalfBlock = 0x02; 568 CharUpArrow = 0x03; 569 CharDownArrow = 0x04; 570 CharHorizontalLine = 0x05; 571 CharVerticalLine = 0x06; 572 CharUpperLeftCorner = 0x08; 573 CharUpperRightCorner = 0x09; 574 CharLowerLeftCorner = 0x0B; 575 CharLowerRightCorner = 0x0C; 576 CharVertLineAndRightHorizLine = 0x0E; 577 CharLeftHorizLineAndVertLine = 0x0F; 578 CharDoubleHorizontalLine = 0x10; 579 CharDoubleVerticalLine = 0x11; 580 CharDoubleUpperLeftCorner = 0x12; 581 CharDoubleUpperRightCorner = 0x13; 582 CharDoubleLowerLeftCorner = 0x14; 583 CharDoubleLowerRightCorner = 0x15; 584 585 /* FIXME: Enter 640x400 video mode */ 586 break; 587 588 default: /* Other codepages */ 589 /* Set special characters */ 590 CharBullet = 0x07; 591 CharBlock = 0xDB; 592 CharHalfBlock = 0xDD; 593 CharUpArrow = 0x18; 594 CharDownArrow = 0x19; 595 CharHorizontalLine = 0xC4; 596 CharVerticalLine = 0xB3; 597 CharUpperLeftCorner = 0xDA; 598 CharUpperRightCorner = 0xBF; 599 CharLowerLeftCorner = 0xC0; 600 CharLowerRightCorner = 0xD9; 601 CharVertLineAndRightHorizLine = 0xC3; 602 CharLeftHorizLineAndVertLine = 0xB4; 603 CharDoubleHorizontalLine = 0xCD; 604 CharDoubleVerticalLine = 0xBA; 605 CharDoubleUpperLeftCorner = 0xC9; 606 CharDoubleUpperRightCorner = 0xBB; 607 CharDoubleLowerLeftCorner = 0xC8; 608 CharDoubleLowerRightCorner = 0xBC; 609 610 /* FIXME: Enter 720x400 video mode */ 611 break; 612 } 613 } 614