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