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