xref: /reactos/base/setup/usetup/console.c (revision b8dd046e)
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