1 /* 2 * ReactOS kernel 3 * Copyright (C) 2002 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/console.c 23 * PURPOSE: Console support functions 24 * PROGRAMMER: 25 */ 26 27 /* INCLUDES ******************************************************************/ 28 29 #include <usetup.h> 30 /* Blue Driver Header */ 31 #include <blue/ntddblue.h> 32 #include "keytrans.h" 33 34 #define NDEBUG 35 #include <debug.h> 36 37 /* DATA **********************************************************************/ 38 39 static BOOLEAN InputQueueEmpty; 40 static BOOLEAN WaitForInput; 41 static KEYBOARD_INPUT_DATA InputDataQueue; // Only one element! 42 static IO_STATUS_BLOCK InputIosb; 43 static UINT LastLoadedCodepage; 44 45 /* FUNCTIONS *****************************************************************/ 46 47 typedef struct _CONSOLE_CABINET_CONTEXT 48 { 49 CABINET_CONTEXT CabinetContext; 50 PVOID Data; 51 ULONG Size; 52 } CONSOLE_CABINET_CONTEXT, *PCONSOLE_CABINET_CONTEXT; 53 54 static PVOID 55 ConsoleCreateFileHandler( 56 IN PCABINET_CONTEXT CabinetContext, 57 IN ULONG FileSize) 58 { 59 PCONSOLE_CABINET_CONTEXT ConsoleCabinetContext; 60 61 ConsoleCabinetContext = (PCONSOLE_CABINET_CONTEXT)CabinetContext; 62 ConsoleCabinetContext->Data = RtlAllocateHeap(ProcessHeap, 0, FileSize); 63 if (!ConsoleCabinetContext->Data) 64 { 65 DPRINT("Failed to allocate %d bytes\n", FileSize); 66 return NULL; 67 } 68 ConsoleCabinetContext->Size = FileSize; 69 return ConsoleCabinetContext->Data; 70 } 71 72 BOOL 73 WINAPI 74 AllocConsole(VOID) 75 { 76 NTSTATUS Status; 77 UNICODE_STRING ScreenName = RTL_CONSTANT_STRING(L"\\??\\BlueScreen"); 78 UNICODE_STRING KeyboardName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardClass0"); 79 OBJECT_ATTRIBUTES ObjectAttributes; 80 IO_STATUS_BLOCK IoStatusBlock; 81 ULONG Enable; 82 83 /* Open the screen */ 84 InitializeObjectAttributes(&ObjectAttributes, 85 &ScreenName, 86 0, 87 NULL, 88 NULL); 89 Status = NtOpenFile(&StdOutput, 90 FILE_ALL_ACCESS, 91 &ObjectAttributes, 92 &IoStatusBlock, 93 FILE_OPEN, 94 FILE_SYNCHRONOUS_IO_ALERT); 95 if (!NT_SUCCESS(Status)) 96 return FALSE; 97 98 /* Enable it */ 99 Enable = TRUE; 100 Status = NtDeviceIoControlFile(StdOutput, 101 NULL, 102 NULL, 103 NULL, 104 &IoStatusBlock, 105 IOCTL_CONSOLE_RESET_SCREEN, 106 &Enable, 107 sizeof(Enable), 108 NULL, 109 0); 110 if (!NT_SUCCESS(Status)) 111 { 112 NtClose(StdOutput); 113 return FALSE; 114 } 115 116 /* Open the keyboard */ 117 InitializeObjectAttributes(&ObjectAttributes, 118 &KeyboardName, 119 0, 120 NULL, 121 NULL); 122 Status = NtOpenFile(&StdInput, 123 FILE_ALL_ACCESS, 124 &ObjectAttributes, 125 &IoStatusBlock, 126 FILE_OPEN, 127 0); 128 if (!NT_SUCCESS(Status)) 129 { 130 NtClose(StdOutput); 131 return FALSE; 132 } 133 134 /* Reset the queue state */ 135 InputQueueEmpty = TRUE; 136 WaitForInput = FALSE; 137 138 return TRUE; 139 } 140 141 142 BOOL 143 WINAPI 144 AttachConsole( 145 IN DWORD dwProcessId) 146 { 147 return FALSE; 148 } 149 150 151 BOOL 152 WINAPI 153 FreeConsole(VOID) 154 { 155 /* Reset the queue state */ 156 InputQueueEmpty = TRUE; 157 WaitForInput = FALSE; 158 159 if (StdInput != INVALID_HANDLE_VALUE) 160 NtClose(StdInput); 161 162 if (StdOutput != INVALID_HANDLE_VALUE) 163 NtClose(StdOutput); 164 165 return TRUE; 166 } 167 168 169 BOOL 170 WINAPI 171 WriteConsole( 172 IN HANDLE hConsoleOutput, 173 IN const VOID *lpBuffer, 174 IN DWORD nNumberOfCharsToWrite, 175 OUT LPDWORD lpNumberOfCharsWritten, 176 IN LPVOID lpReserved) 177 { 178 IO_STATUS_BLOCK IoStatusBlock; 179 NTSTATUS Status; 180 181 Status = NtWriteFile(hConsoleOutput, 182 NULL, 183 NULL, 184 NULL, 185 &IoStatusBlock, 186 (PVOID)lpBuffer, 187 nNumberOfCharsToWrite, 188 NULL, 189 NULL); 190 if (!NT_SUCCESS(Status)) 191 return FALSE; 192 193 *lpNumberOfCharsWritten = IoStatusBlock.Information; 194 return TRUE; 195 } 196 197 198 HANDLE 199 WINAPI 200 GetStdHandle( 201 IN DWORD nStdHandle) 202 { 203 switch (nStdHandle) 204 { 205 case STD_INPUT_HANDLE: 206 return StdInput; 207 case STD_OUTPUT_HANDLE: 208 return StdOutput; 209 default: 210 return INVALID_HANDLE_VALUE; 211 } 212 } 213 214 215 BOOL 216 WINAPI 217 FlushConsoleInputBuffer( 218 IN HANDLE hConsoleInput) 219 { 220 NTSTATUS Status; 221 LARGE_INTEGER Offset, Timeout; 222 IO_STATUS_BLOCK IoStatusBlock; 223 KEYBOARD_INPUT_DATA InputData; 224 225 /* Cancel any pending read */ 226 if (WaitForInput) 227 NtCancelIoFile(hConsoleInput, &IoStatusBlock); 228 229 /* Reset the queue state */ 230 InputQueueEmpty = TRUE; 231 WaitForInput = FALSE; 232 233 /* Flush the keyboard buffer */ 234 do 235 { 236 Offset.QuadPart = 0; 237 Status = NtReadFile(hConsoleInput, 238 NULL, 239 NULL, 240 NULL, 241 &IoStatusBlock, 242 &InputData, 243 sizeof(InputData), 244 &Offset, 245 NULL); 246 if (Status == STATUS_PENDING) 247 { 248 Timeout.QuadPart = -100; 249 Status = NtWaitForSingleObject(hConsoleInput, FALSE, &Timeout); 250 if (Status == STATUS_TIMEOUT) 251 { 252 NtCancelIoFile(hConsoleInput, &IoStatusBlock); 253 return TRUE; 254 } 255 } 256 } while (NT_SUCCESS(Status)); 257 return FALSE; 258 } 259 260 261 BOOL 262 WINAPI 263 PeekConsoleInput( 264 IN HANDLE hConsoleInput, 265 OUT PINPUT_RECORD lpBuffer, 266 IN DWORD nLength, 267 OUT LPDWORD lpNumberOfEventsRead) 268 { 269 NTSTATUS Status; 270 LARGE_INTEGER Offset, Timeout; 271 KEYBOARD_INPUT_DATA InputData; 272 273 if (InputQueueEmpty) 274 { 275 /* Read the keyboard for an event, without waiting */ 276 if (!WaitForInput) 277 { 278 Offset.QuadPart = 0; 279 Status = NtReadFile(hConsoleInput, 280 NULL, 281 NULL, 282 NULL, 283 &InputIosb, 284 &InputDataQueue, 285 sizeof(InputDataQueue), 286 &Offset, 287 NULL); 288 if (!NT_SUCCESS(Status)) 289 return FALSE; 290 if (Status == STATUS_PENDING) 291 { 292 /* No input yet, we will have to wait next time */ 293 *lpNumberOfEventsRead = 0; 294 WaitForInput = TRUE; 295 return TRUE; 296 } 297 } 298 else 299 { 300 /* 301 * We already tried to read from the keyboard and are 302 * waiting for data, check whether something showed up. 303 */ 304 Timeout.QuadPart = -100; // Wait just a little bit. 305 Status = NtWaitForSingleObject(hConsoleInput, FALSE, &Timeout); 306 if (Status == STATUS_TIMEOUT) 307 { 308 /* Nothing yet, continue waiting next time */ 309 *lpNumberOfEventsRead = 0; 310 WaitForInput = TRUE; 311 return TRUE; 312 } 313 WaitForInput = FALSE; 314 if (!NT_SUCCESS(Status)) 315 return FALSE; 316 } 317 318 /* We got something in the queue */ 319 InputQueueEmpty = FALSE; 320 WaitForInput = FALSE; 321 } 322 323 /* Fetch from the queue but keep it inside */ 324 InputData = InputDataQueue; 325 326 lpBuffer->EventType = KEY_EVENT; 327 Status = IntTranslateKey(hConsoleInput, &InputData, &lpBuffer->Event.KeyEvent); 328 if (!NT_SUCCESS(Status)) 329 return FALSE; 330 331 *lpNumberOfEventsRead = 1; 332 return TRUE; 333 } 334 335 336 BOOL 337 WINAPI 338 ReadConsoleInput( 339 IN HANDLE hConsoleInput, 340 OUT PINPUT_RECORD lpBuffer, 341 IN DWORD nLength, 342 OUT LPDWORD lpNumberOfEventsRead) 343 { 344 NTSTATUS Status; 345 LARGE_INTEGER Offset; 346 KEYBOARD_INPUT_DATA InputData; 347 348 if (InputQueueEmpty) 349 { 350 /* Read the keyboard and wait for an event, skipping the queue */ 351 if (!WaitForInput) 352 { 353 Offset.QuadPart = 0; 354 Status = NtReadFile(hConsoleInput, 355 NULL, 356 NULL, 357 NULL, 358 &InputIosb, 359 &InputDataQueue, 360 sizeof(InputDataQueue), 361 &Offset, 362 NULL); 363 if (Status == STATUS_PENDING) 364 { 365 /* Block and wait for input */ 366 WaitForInput = TRUE; 367 Status = NtWaitForSingleObject(hConsoleInput, FALSE, NULL); 368 WaitForInput = FALSE; 369 Status = InputIosb.Status; 370 } 371 if (!NT_SUCCESS(Status)) 372 return FALSE; 373 } 374 else 375 { 376 /* 377 * We already tried to read from the keyboard and are 378 * waiting for data, block and wait for input. 379 */ 380 Status = NtWaitForSingleObject(hConsoleInput, FALSE, NULL); 381 WaitForInput = FALSE; 382 Status = InputIosb.Status; 383 if (!NT_SUCCESS(Status)) 384 return FALSE; 385 } 386 } 387 388 /* Fetch from the queue and empty it */ 389 InputData = InputDataQueue; 390 InputQueueEmpty = TRUE; 391 392 lpBuffer->EventType = KEY_EVENT; 393 Status = IntTranslateKey(hConsoleInput, &InputData, &lpBuffer->Event.KeyEvent); 394 if (!NT_SUCCESS(Status)) 395 return FALSE; 396 397 *lpNumberOfEventsRead = 1; 398 return TRUE; 399 } 400 401 402 BOOL 403 WINAPI 404 WriteConsoleOutputCharacterA( 405 HANDLE hConsoleOutput, 406 IN LPCSTR lpCharacter, 407 IN DWORD nLength, 408 IN COORD dwWriteCoord, 409 OUT LPDWORD lpNumberOfCharsWritten) 410 { 411 IO_STATUS_BLOCK IoStatusBlock; 412 PCHAR Buffer; 413 COORD *pCoord; 414 PCHAR pText; 415 NTSTATUS Status; 416 417 Buffer = (CHAR*)RtlAllocateHeap(ProcessHeap, 418 0, 419 nLength + sizeof(COORD)); 420 pCoord = (COORD *)Buffer; 421 pText = (PCHAR)(pCoord + 1); 422 423 *pCoord = dwWriteCoord; 424 memcpy(pText, lpCharacter, nLength); 425 426 Status = NtDeviceIoControlFile(hConsoleOutput, 427 NULL, 428 NULL, 429 NULL, 430 &IoStatusBlock, 431 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER, 432 NULL, 433 0, 434 Buffer, 435 nLength + sizeof(COORD)); 436 437 RtlFreeHeap(ProcessHeap, 0, Buffer); 438 if (!NT_SUCCESS(Status)) 439 return FALSE; 440 441 *lpNumberOfCharsWritten = IoStatusBlock.Information; 442 return TRUE; 443 } 444 445 446 BOOL 447 WINAPI 448 WriteConsoleOutputCharacterW( 449 HANDLE hConsoleOutput, 450 IN LPCWSTR lpCharacter, 451 IN DWORD nLength, 452 IN COORD dwWriteCoord, 453 OUT LPDWORD lpNumberOfCharsWritten) 454 { 455 IO_STATUS_BLOCK IoStatusBlock; 456 PCHAR Buffer; 457 COORD *pCoord; 458 PCHAR pText; 459 NTSTATUS Status; 460 // ULONG i; 461 462 UNICODE_STRING UnicodeString; 463 OEM_STRING OemString; 464 ULONG OemLength; 465 466 UnicodeString.Length = nLength * sizeof(WCHAR); 467 UnicodeString.MaximumLength = nLength * sizeof(WCHAR); 468 UnicodeString.Buffer = (PWSTR)lpCharacter; 469 470 OemLength = RtlUnicodeStringToOemSize(&UnicodeString); 471 472 473 Buffer = (CHAR*)RtlAllocateHeap(ProcessHeap, 474 0, 475 OemLength + sizeof(COORD)); 476 // nLength + sizeof(COORD)); 477 if (Buffer== NULL) 478 return FALSE; 479 480 pCoord = (COORD *)Buffer; 481 pText = (PCHAR)(pCoord + 1); 482 483 *pCoord = dwWriteCoord; 484 485 OemString.Length = 0; 486 OemString.MaximumLength = OemLength; 487 OemString.Buffer = pText; 488 489 Status = RtlUnicodeStringToOemString(&OemString, 490 &UnicodeString, 491 FALSE); 492 if (!NT_SUCCESS(Status)) 493 goto done; 494 495 /* FIXME: use real unicode->oem conversion */ 496 // for (i = 0; i < nLength; i++) 497 // pText[i] = (CHAR)lpCharacter[i]; 498 499 Status = NtDeviceIoControlFile(hConsoleOutput, 500 NULL, 501 NULL, 502 NULL, 503 &IoStatusBlock, 504 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER, 505 NULL, 506 0, 507 Buffer, 508 nLength + sizeof(COORD)); 509 510 done: 511 RtlFreeHeap(ProcessHeap, 0, Buffer); 512 if (!NT_SUCCESS(Status)) 513 return FALSE; 514 515 *lpNumberOfCharsWritten = IoStatusBlock.Information; 516 return TRUE; 517 } 518 519 520 BOOL 521 WINAPI 522 FillConsoleOutputAttribute( 523 IN HANDLE hConsoleOutput, 524 IN WORD wAttribute, 525 IN DWORD nLength, 526 IN COORD dwWriteCoord, 527 OUT LPDWORD lpNumberOfAttrsWritten) 528 { 529 IO_STATUS_BLOCK IoStatusBlock; 530 OUTPUT_ATTRIBUTE Buffer; 531 NTSTATUS Status; 532 533 Buffer.wAttribute = wAttribute; 534 Buffer.nLength = nLength; 535 Buffer.dwCoord = dwWriteCoord; 536 537 Status = NtDeviceIoControlFile(hConsoleOutput, 538 NULL, 539 NULL, 540 NULL, 541 &IoStatusBlock, 542 IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE, 543 &Buffer, 544 sizeof(OUTPUT_ATTRIBUTE), 545 &Buffer, 546 sizeof(OUTPUT_ATTRIBUTE)); 547 if (!NT_SUCCESS(Status)) 548 return FALSE; 549 550 *lpNumberOfAttrsWritten = Buffer.dwTransfered; 551 return TRUE; 552 } 553 554 555 BOOL 556 WINAPI 557 FillConsoleOutputCharacterA( 558 IN HANDLE hConsoleOutput, 559 IN CHAR cCharacter, 560 IN DWORD nLength, 561 IN COORD dwWriteCoord, 562 OUT LPDWORD lpNumberOfCharsWritten) 563 { 564 IO_STATUS_BLOCK IoStatusBlock; 565 OUTPUT_CHARACTER Buffer; 566 NTSTATUS Status; 567 568 Buffer.cCharacter = cCharacter; 569 Buffer.nLength = nLength; 570 Buffer.dwCoord = dwWriteCoord; 571 572 Status = NtDeviceIoControlFile(hConsoleOutput, 573 NULL, 574 NULL, 575 NULL, 576 &IoStatusBlock, 577 IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER, 578 &Buffer, 579 sizeof(OUTPUT_CHARACTER), 580 &Buffer, 581 sizeof(OUTPUT_CHARACTER)); 582 if (!NT_SUCCESS(Status)) 583 return FALSE; 584 585 *lpNumberOfCharsWritten = Buffer.dwTransfered; 586 return TRUE; 587 } 588 589 590 BOOL 591 WINAPI 592 GetConsoleScreenBufferInfo( 593 IN HANDLE hConsoleOutput, 594 OUT PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo) 595 { 596 IO_STATUS_BLOCK IoStatusBlock; 597 NTSTATUS Status; 598 599 Status = NtDeviceIoControlFile(hConsoleOutput, 600 NULL, 601 NULL, 602 NULL, 603 &IoStatusBlock, 604 IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 605 NULL, 606 0, 607 lpConsoleScreenBufferInfo, 608 sizeof(CONSOLE_SCREEN_BUFFER_INFO)); 609 return NT_SUCCESS(Status); 610 } 611 612 613 BOOL 614 WINAPI 615 SetConsoleCursorInfo( 616 IN HANDLE hConsoleOutput, 617 IN const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo) 618 { 619 IO_STATUS_BLOCK IoStatusBlock; 620 NTSTATUS Status; 621 622 Status = NtDeviceIoControlFile(hConsoleOutput, 623 NULL, 624 NULL, 625 NULL, 626 &IoStatusBlock, 627 IOCTL_CONSOLE_SET_CURSOR_INFO, 628 (PCONSOLE_CURSOR_INFO)lpConsoleCursorInfo, 629 sizeof(CONSOLE_CURSOR_INFO), 630 NULL, 631 0); 632 return NT_SUCCESS(Status); 633 } 634 635 636 BOOL 637 WINAPI 638 SetConsoleCursorPosition( 639 IN HANDLE hConsoleOutput, 640 IN COORD dwCursorPosition) 641 { 642 CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo; 643 IO_STATUS_BLOCK IoStatusBlock; 644 NTSTATUS Status; 645 646 Status = GetConsoleScreenBufferInfo(hConsoleOutput, &ConsoleScreenBufferInfo); 647 if (!NT_SUCCESS(Status)) 648 return FALSE; 649 650 ConsoleScreenBufferInfo.dwCursorPosition.X = dwCursorPosition.X; 651 ConsoleScreenBufferInfo.dwCursorPosition.Y = dwCursorPosition.Y; 652 653 Status = NtDeviceIoControlFile(hConsoleOutput, 654 NULL, 655 NULL, 656 NULL, 657 &IoStatusBlock, 658 IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, 659 &ConsoleScreenBufferInfo, 660 sizeof(CONSOLE_SCREEN_BUFFER_INFO), 661 NULL, 662 0); 663 return NT_SUCCESS(Status); 664 } 665 666 667 BOOL 668 WINAPI 669 SetConsoleTextAttribute( 670 IN HANDLE hConsoleOutput, 671 IN WORD wAttributes) 672 { 673 IO_STATUS_BLOCK IoStatusBlock; 674 NTSTATUS Status; 675 676 Status = NtDeviceIoControlFile(hConsoleOutput, 677 NULL, 678 NULL, 679 NULL, 680 &IoStatusBlock, 681 IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE, 682 &wAttributes, 683 sizeof(USHORT), 684 NULL, 685 0); 686 return NT_SUCCESS(Status); 687 } 688 689 690 BOOL 691 WINAPI 692 SetConsoleOutputCP( 693 IN UINT wCodepage) 694 { 695 WCHAR FontName[100]; 696 WCHAR FontFile[] = L"\\SystemRoot\\vgafonts.cab"; 697 CONSOLE_CABINET_CONTEXT ConsoleCabinetContext; 698 PCABINET_CONTEXT CabinetContext = &ConsoleCabinetContext.CabinetContext; 699 CAB_SEARCH Search; 700 ULONG CabStatus; 701 HANDLE hConsoleOutput; 702 IO_STATUS_BLOCK IoStatusBlock; 703 NTSTATUS Status; 704 705 if (wCodepage == LastLoadedCodepage) 706 return TRUE; 707 708 hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); 709 710 CabinetInitialize(CabinetContext); 711 CabinetSetEventHandlers(CabinetContext, 712 NULL, NULL, NULL, ConsoleCreateFileHandler); 713 CabinetSetCabinetName(CabinetContext, FontFile); 714 715 CabStatus = CabinetOpen(CabinetContext); 716 if (CabStatus != CAB_STATUS_SUCCESS) 717 { 718 DPRINT("CabinetOpen('%S') returned 0x%08x\n", FontFile, CabStatus); 719 return FALSE; 720 } 721 722 swprintf(FontName, L"%u-8x8.bin", wCodepage); 723 CabStatus = CabinetFindFirst(CabinetContext, FontName, &Search); 724 if (CabStatus != CAB_STATUS_SUCCESS) 725 { 726 DPRINT("CabinetFindFirst('%S', '%S') returned 0x%08x\n", FontFile, FontName, CabStatus); 727 CabinetClose(CabinetContext); 728 return FALSE; 729 } 730 731 CabStatus = CabinetExtractFile(CabinetContext, &Search); 732 CabinetClose(CabinetContext); 733 if (CabStatus != CAB_STATUS_SUCCESS) 734 { 735 DPRINT("CabinetLoadFile('%S', '%S') returned 0x%08x\n", FontFile, FontName, CabStatus); 736 return FALSE; 737 } 738 739 Status = NtDeviceIoControlFile(hConsoleOutput, 740 NULL, 741 NULL, 742 NULL, 743 &IoStatusBlock, 744 IOCTL_CONSOLE_SETFONT, 745 ConsoleCabinetContext.Data, 746 ConsoleCabinetContext.Size, 747 NULL, 748 0); 749 if (!NT_SUCCESS(Status)) 750 return FALSE; 751 752 LastLoadedCodepage = wCodepage; 753 return TRUE; 754 } 755 756 757 /* EOF */ 758