3 * Copyright (C) 2002 ReactOS Team
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.
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.
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.
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
27 /* INCLUDES ******************************************************************/
30 /* Blue Driver Header */
31 #include <blue/ntddblue.h>
37 /* DATA **********************************************************************/
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
;
45 /* FUNCTIONS *****************************************************************/
47 typedef struct _CONSOLE_CABINET_CONTEXT
49 CABINET_CONTEXT CabinetContext
;
52 } CONSOLE_CABINET_CONTEXT
, *PCONSOLE_CABINET_CONTEXT
;
55 ConsoleCreateFileHandler(
56 IN PCABINET_CONTEXT CabinetContext
,
59 PCONSOLE_CABINET_CONTEXT ConsoleCabinetContext
;
61 ConsoleCabinetContext
= (PCONSOLE_CABINET_CONTEXT
)CabinetContext
;
62 ConsoleCabinetContext
->Data
= RtlAllocateHeap(ProcessHeap
, 0, FileSize
);
63 if (!ConsoleCabinetContext
->Data
)
65 DPRINT("Failed to allocate %d bytes\n", FileSize
);
68 ConsoleCabinetContext
->Size
= FileSize
;
69 return ConsoleCabinetContext
->Data
;
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
;
84 InitializeObjectAttributes(&ObjectAttributes
,
89 Status
= NtOpenFile(&StdOutput
,
94 FILE_SYNCHRONOUS_IO_ALERT
);
95 if (!NT_SUCCESS(Status
))
100 Status
= NtDeviceIoControlFile(StdOutput
,
105 IOCTL_CONSOLE_RESET_SCREEN
,
110 if (!NT_SUCCESS(Status
))
116 /* Default to en-US output codepage */
117 SetConsoleOutputCP(437);
119 /* Open the keyboard */
120 InitializeObjectAttributes(&ObjectAttributes
,
125 Status
= NtOpenFile(&StdInput
,
131 if (!NT_SUCCESS(Status
))
137 /* Reset the queue state */
138 InputQueueEmpty
= TRUE
;
139 WaitForInput
= FALSE
;
148 IN DWORD dwProcessId
)
158 /* Reset the queue state */
159 InputQueueEmpty
= TRUE
;
160 WaitForInput
= FALSE
;
162 if (StdInput
!= INVALID_HANDLE_VALUE
)
165 if (StdOutput
!= INVALID_HANDLE_VALUE
)
175 IN HANDLE hConsoleOutput
,
176 IN
const VOID
*lpBuffer
,
177 IN DWORD nNumberOfCharsToWrite
,
178 OUT LPDWORD lpNumberOfCharsWritten
,
179 IN LPVOID lpReserved
)
181 IO_STATUS_BLOCK IoStatusBlock
;
184 Status
= NtWriteFile(hConsoleOutput
,
190 nNumberOfCharsToWrite
,
193 if (!NT_SUCCESS(Status
))
196 *lpNumberOfCharsWritten
= IoStatusBlock
.Information
;
208 case STD_INPUT_HANDLE
:
210 case STD_OUTPUT_HANDLE
:
213 return INVALID_HANDLE_VALUE
;
220 FlushConsoleInputBuffer(
221 IN HANDLE hConsoleInput
)
224 LARGE_INTEGER Offset
, Timeout
;
225 IO_STATUS_BLOCK IoStatusBlock
;
226 KEYBOARD_INPUT_DATA InputData
;
228 /* Cancel any pending read */
230 NtCancelIoFile(hConsoleInput
, &IoStatusBlock
);
232 /* Reset the queue state */
233 InputQueueEmpty
= TRUE
;
234 WaitForInput
= FALSE
;
236 /* Flush the keyboard buffer */
240 Status
= NtReadFile(hConsoleInput
,
249 if (Status
== STATUS_PENDING
)
251 Timeout
.QuadPart
= -100;
252 Status
= NtWaitForSingleObject(hConsoleInput
, FALSE
, &Timeout
);
253 if (Status
== STATUS_TIMEOUT
)
255 NtCancelIoFile(hConsoleInput
, &IoStatusBlock
);
259 } while (NT_SUCCESS(Status
));
267 IN HANDLE hConsoleInput
,
268 OUT PINPUT_RECORD lpBuffer
,
270 OUT LPDWORD lpNumberOfEventsRead
)
273 LARGE_INTEGER Offset
, Timeout
;
274 KEYBOARD_INPUT_DATA InputData
;
278 /* Read the keyboard for an event, without waiting */
282 Status
= NtReadFile(hConsoleInput
,
288 sizeof(InputDataQueue
),
291 if (!NT_SUCCESS(Status
))
293 if (Status
== STATUS_PENDING
)
295 /* No input yet, we will have to wait next time */
296 *lpNumberOfEventsRead
= 0;
304 * We already tried to read from the keyboard and are
305 * waiting for data, check whether something showed up.
307 Timeout
.QuadPart
= -100; // Wait just a little bit.
308 Status
= NtWaitForSingleObject(hConsoleInput
, FALSE
, &Timeout
);
309 if (Status
== STATUS_TIMEOUT
)
311 /* Nothing yet, continue waiting next time */
312 *lpNumberOfEventsRead
= 0;
316 WaitForInput
= FALSE
;
317 if (!NT_SUCCESS(Status
))
321 /* We got something in the queue */
322 InputQueueEmpty
= FALSE
;
323 WaitForInput
= FALSE
;
326 /* Fetch from the queue but keep it inside */
327 InputData
= InputDataQueue
;
329 lpBuffer
->EventType
= KEY_EVENT
;
330 Status
= IntTranslateKey(hConsoleInput
, &InputData
, &lpBuffer
->Event
.KeyEvent
);
331 if (!NT_SUCCESS(Status
))
334 *lpNumberOfEventsRead
= 1;
342 IN HANDLE hConsoleInput
,
343 OUT PINPUT_RECORD lpBuffer
,
345 OUT LPDWORD lpNumberOfEventsRead
)
348 LARGE_INTEGER Offset
;
349 KEYBOARD_INPUT_DATA InputData
;
353 /* Read the keyboard and wait for an event, skipping the queue */
357 Status
= NtReadFile(hConsoleInput
,
363 sizeof(InputDataQueue
),
366 if (Status
== STATUS_PENDING
)
368 /* Block and wait for input */
370 Status
= NtWaitForSingleObject(hConsoleInput
, FALSE
, NULL
);
371 WaitForInput
= FALSE
;
372 Status
= InputIosb
.Status
;
374 if (!NT_SUCCESS(Status
))
380 * We already tried to read from the keyboard and are
381 * waiting for data, block and wait for input.
383 Status
= NtWaitForSingleObject(hConsoleInput
, FALSE
, NULL
);
384 WaitForInput
= FALSE
;
385 Status
= InputIosb
.Status
;
386 if (!NT_SUCCESS(Status
))
391 /* Fetch from the queue and empty it */
392 InputData
= InputDataQueue
;
393 InputQueueEmpty
= TRUE
;
395 lpBuffer
->EventType
= KEY_EVENT
;
396 Status
= IntTranslateKey(hConsoleInput
, &InputData
, &lpBuffer
->Event
.KeyEvent
);
397 if (!NT_SUCCESS(Status
))
400 *lpNumberOfEventsRead
= 1;
407 WriteConsoleOutputCharacterA(
408 HANDLE hConsoleOutput
,
409 IN LPCSTR lpCharacter
,
411 IN COORD dwWriteCoord
,
412 OUT LPDWORD lpNumberOfCharsWritten
)
414 IO_STATUS_BLOCK IoStatusBlock
;
420 Buffer
= (CHAR
*)RtlAllocateHeap(ProcessHeap
,
422 nLength
+ sizeof(COORD
));
423 pCoord
= (COORD
*)Buffer
;
424 pText
= (PCHAR
)(pCoord
+ 1);
426 *pCoord
= dwWriteCoord
;
427 memcpy(pText
, lpCharacter
, nLength
);
429 Status
= NtDeviceIoControlFile(hConsoleOutput
,
434 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER
,
438 nLength
+ sizeof(COORD
));
440 RtlFreeHeap(ProcessHeap
, 0, Buffer
);
441 if (!NT_SUCCESS(Status
))
444 *lpNumberOfCharsWritten
= IoStatusBlock
.Information
;
451 WriteConsoleOutputCharacterW(
452 HANDLE hConsoleOutput
,
453 IN LPCWSTR lpCharacter
,
455 IN COORD dwWriteCoord
,
456 OUT LPDWORD lpNumberOfCharsWritten
)
458 IO_STATUS_BLOCK IoStatusBlock
;
465 UNICODE_STRING UnicodeString
;
466 OEM_STRING OemString
;
469 UnicodeString
.Length
= nLength
* sizeof(WCHAR
);
470 UnicodeString
.MaximumLength
= nLength
* sizeof(WCHAR
);
471 UnicodeString
.Buffer
= (PWSTR
)lpCharacter
;
473 OemLength
= RtlUnicodeStringToOemSize(&UnicodeString
);
476 Buffer
= (CHAR
*)RtlAllocateHeap(ProcessHeap
,
478 OemLength
+ sizeof(COORD
));
479 // nLength + sizeof(COORD));
483 pCoord
= (COORD
*)Buffer
;
484 pText
= (PCHAR
)(pCoord
+ 1);
486 *pCoord
= dwWriteCoord
;
488 OemString
.Length
= 0;
489 OemString
.MaximumLength
= OemLength
;
490 OemString
.Buffer
= pText
;
492 Status
= RtlUnicodeStringToOemString(&OemString
,
495 if (!NT_SUCCESS(Status
))
498 /* FIXME: use real unicode->oem conversion */
499 // for (i = 0; i < nLength; i++)
500 // pText[i] = (CHAR)lpCharacter[i];
502 Status
= NtDeviceIoControlFile(hConsoleOutput
,
507 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER
,
511 nLength
+ sizeof(COORD
));
514 RtlFreeHeap(ProcessHeap
, 0, Buffer
);
515 if (!NT_SUCCESS(Status
))
518 *lpNumberOfCharsWritten
= IoStatusBlock
.Information
;
525 FillConsoleOutputAttribute(
526 IN HANDLE hConsoleOutput
,
529 IN COORD dwWriteCoord
,
530 OUT LPDWORD lpNumberOfAttrsWritten
)
532 IO_STATUS_BLOCK IoStatusBlock
;
533 OUTPUT_ATTRIBUTE Buffer
;
536 Buffer
.wAttribute
= wAttribute
;
537 Buffer
.nLength
= nLength
;
538 Buffer
.dwCoord
= dwWriteCoord
;
540 Status
= NtDeviceIoControlFile(hConsoleOutput
,
545 IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE
,
547 sizeof(OUTPUT_ATTRIBUTE
),
549 sizeof(OUTPUT_ATTRIBUTE
));
550 if (!NT_SUCCESS(Status
))
553 *lpNumberOfAttrsWritten
= Buffer
.dwTransfered
;
560 FillConsoleOutputCharacterA(
561 IN HANDLE hConsoleOutput
,
564 IN COORD dwWriteCoord
,
565 OUT LPDWORD lpNumberOfCharsWritten
)
567 IO_STATUS_BLOCK IoStatusBlock
;
568 OUTPUT_CHARACTER Buffer
;
571 Buffer
.cCharacter
= cCharacter
;
572 Buffer
.nLength
= nLength
;
573 Buffer
.dwCoord
= dwWriteCoord
;
575 Status
= NtDeviceIoControlFile(hConsoleOutput
,
580 IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER
,
582 sizeof(OUTPUT_CHARACTER
),
584 sizeof(OUTPUT_CHARACTER
));
585 if (!NT_SUCCESS(Status
))
588 *lpNumberOfCharsWritten
= Buffer
.dwTransfered
;
595 GetConsoleScreenBufferInfo(
596 IN HANDLE hConsoleOutput
,
597 OUT PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo
)
599 IO_STATUS_BLOCK IoStatusBlock
;
602 Status
= NtDeviceIoControlFile(hConsoleOutput
,
607 IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO
,
610 lpConsoleScreenBufferInfo
,
611 sizeof(CONSOLE_SCREEN_BUFFER_INFO
));
612 return NT_SUCCESS(Status
);
618 SetConsoleCursorInfo(
619 IN HANDLE hConsoleOutput
,
620 IN
const CONSOLE_CURSOR_INFO
*lpConsoleCursorInfo
)
622 IO_STATUS_BLOCK IoStatusBlock
;
625 Status
= NtDeviceIoControlFile(hConsoleOutput
,
630 IOCTL_CONSOLE_SET_CURSOR_INFO
,
631 (PCONSOLE_CURSOR_INFO
)lpConsoleCursorInfo
,
632 sizeof(CONSOLE_CURSOR_INFO
),
635 return NT_SUCCESS(Status
);
641 SetConsoleCursorPosition(
642 IN HANDLE hConsoleOutput
,
643 IN COORD dwCursorPosition
)
645 CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo
;
646 IO_STATUS_BLOCK IoStatusBlock
;
649 Status
= GetConsoleScreenBufferInfo(hConsoleOutput
, &ConsoleScreenBufferInfo
);
650 if (!NT_SUCCESS(Status
))
653 ConsoleScreenBufferInfo
.dwCursorPosition
.X
= dwCursorPosition
.X
;
654 ConsoleScreenBufferInfo
.dwCursorPosition
.Y
= dwCursorPosition
.Y
;
656 Status
= NtDeviceIoControlFile(hConsoleOutput
,
661 IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
,
662 &ConsoleScreenBufferInfo
,
663 sizeof(CONSOLE_SCREEN_BUFFER_INFO
),
666 return NT_SUCCESS(Status
);
672 SetConsoleTextAttribute(
673 IN HANDLE hConsoleOutput
,
676 IO_STATUS_BLOCK IoStatusBlock
;
679 Status
= NtDeviceIoControlFile(hConsoleOutput
,
684 IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE
,
689 return NT_SUCCESS(Status
);
698 static PCWSTR FontFile
= L
"\\SystemRoot\\vgafonts.cab";
700 CONSOLE_CABINET_CONTEXT ConsoleCabinetContext
;
701 PCABINET_CONTEXT CabinetContext
= &ConsoleCabinetContext
.CabinetContext
;
704 HANDLE hConsoleOutput
;
705 IO_STATUS_BLOCK IoStatusBlock
;
708 if (wCodepage
== LastLoadedCodepage
)
711 hConsoleOutput
= GetStdHandle(STD_OUTPUT_HANDLE
);
713 CabinetInitialize(CabinetContext
);
714 CabinetSetEventHandlers(CabinetContext
,
715 NULL
, NULL
, NULL
, ConsoleCreateFileHandler
);
716 CabinetSetCabinetName(CabinetContext
, FontFile
);
718 CabStatus
= CabinetOpen(CabinetContext
);
719 if (CabStatus
!= CAB_STATUS_SUCCESS
)
721 DPRINT("CabinetOpen('%S') returned 0x%08x\n", FontFile
, CabStatus
);
725 RtlStringCbPrintfW(FontName
, sizeof(FontName
),
726 L
"%u-8x8.bin", wCodepage
);
727 CabStatus
= CabinetFindFirst(CabinetContext
, FontName
, &Search
);
728 if (CabStatus
!= CAB_STATUS_SUCCESS
)
730 DPRINT("CabinetFindFirst('%S', '%S') returned 0x%08x\n", FontFile
, FontName
, CabStatus
);
731 CabinetClose(CabinetContext
);
735 CabStatus
= CabinetExtractFile(CabinetContext
, &Search
);
736 CabinetClose(CabinetContext
);
737 if (CabStatus
!= CAB_STATUS_SUCCESS
)
739 DPRINT("CabinetExtractFile('%S', '%S') returned 0x%08x\n", FontFile
, FontName
, CabStatus
);
740 if (ConsoleCabinetContext
.Data
)
741 RtlFreeHeap(ProcessHeap
, 0, ConsoleCabinetContext
.Data
);
744 ASSERT(ConsoleCabinetContext
.Data
);
746 Status
= NtDeviceIoControlFile(hConsoleOutput
,
751 IOCTL_CONSOLE_LOADFONT
,
752 ConsoleCabinetContext
.Data
,
753 ConsoleCabinetContext
.Size
,
757 RtlFreeHeap(ProcessHeap
, 0, ConsoleCabinetContext
.Data
);
759 if (!NT_SUCCESS(Status
))
762 LastLoadedCodepage
= wCodepage
;