https://git.reactos.org/?p=reactos.git;a=commitdiff;h=6241a16f41abb947579092b1b206fac5e34164f7

commit 6241a16f41abb947579092b1b206fac5e34164f7
Author:     Hermès Bélusca-Maïto <[email protected]>
AuthorDate: Mon Aug 27 00:22:07 2018 +0200
Commit:     Hermès Bélusca-Maïto <[email protected]>
CommitDate: Mon Aug 27 00:28:08 2018 +0200

    [USETUP] Implement a basic console 'input queue' and implement 
PeekConsoleInput() and CONSOLE_ConInKeyPeek() around it.
---
 base/setup/usetup/console.c | 162 ++++++++++++++++++++++++++++++++++++++------
 base/setup/usetup/consup.c  |  32 ++++++++-
 base/setup/usetup/consup.h  |   4 ++
 3 files changed, 177 insertions(+), 21 deletions(-)

diff --git a/base/setup/usetup/console.c b/base/setup/usetup/console.c
index 1c35375dd6..14a0564c6b 100644
--- a/base/setup/usetup/console.c
+++ b/base/setup/usetup/console.c
@@ -34,6 +34,13 @@
 #define NDEBUG
 #include <debug.h>
 
+/* DATA **********************************************************************/
+
+static BOOLEAN InputQueueEmpty;
+static BOOLEAN WaitForInput;
+static KEYBOARD_INPUT_DATA InputDataQueue; // Only one element!
+static IO_STATUS_BLOCK InputIosb;
+
 /* FUNCTIONS *****************************************************************/
 
 BOOL
@@ -76,6 +83,10 @@ AllocConsole(VOID)
     if (!NT_SUCCESS(Status))
         return FALSE;
 
+    /* Reset the queue state */
+    InputQueueEmpty = TRUE;
+    WaitForInput = FALSE;
+
     return TRUE;
 }
 
@@ -93,6 +104,10 @@ BOOL
 WINAPI
 FreeConsole(VOID)
 {
+    /* Reset the queue state */
+    InputQueueEmpty = TRUE;
+    WaitForInput = FALSE;
+
     if (StdInput != INVALID_HANDLE_VALUE)
         NtClose(StdInput);
 
@@ -154,11 +169,20 @@ WINAPI
 FlushConsoleInputBuffer(
     IN HANDLE hConsoleInput)
 {
+    NTSTATUS Status;
     LARGE_INTEGER Offset, Timeout;
     IO_STATUS_BLOCK IoStatusBlock;
     KEYBOARD_INPUT_DATA InputData;
-    NTSTATUS Status;
 
+    /* Cancel any pending read */
+    if (WaitForInput)
+        NtCancelIoFile(hConsoleInput, &IoStatusBlock);
+
+    /* Reset the queue state */
+    InputQueueEmpty = TRUE;
+    WaitForInput = FALSE;
+
+    /* Flush the keyboard buffer */
     do
     {
         Offset.QuadPart = 0;
@@ -168,7 +192,7 @@ FlushConsoleInputBuffer(
                             NULL,
                             &IoStatusBlock,
                             &InputData,
-                            sizeof(KEYBOARD_INPUT_DATA),
+                            sizeof(InputData),
                             &Offset,
                             NULL);
         if (Status == STATUS_PENDING)
@@ -188,35 +212,135 @@ FlushConsoleInputBuffer(
 
 BOOL
 WINAPI
-ReadConsoleInput(
+PeekConsoleInput(
     IN HANDLE hConsoleInput,
     OUT PINPUT_RECORD lpBuffer,
     IN DWORD nLength,
     OUT LPDWORD lpNumberOfEventsRead)
 {
-    LARGE_INTEGER Offset;
-    IO_STATUS_BLOCK IoStatusBlock;
-    KEYBOARD_INPUT_DATA InputData;
     NTSTATUS Status;
+    LARGE_INTEGER Offset, Timeout;
+    KEYBOARD_INPUT_DATA InputData;
 
-    Offset.QuadPart = 0;
-    Status = NtReadFile(hConsoleInput,
-                        NULL,
-                        NULL,
-                        NULL,
-                        &IoStatusBlock,
-                        &InputData,
-                        sizeof(KEYBOARD_INPUT_DATA),
-                        &Offset,
-                        NULL);
-    if (Status == STATUS_PENDING)
+    if (InputQueueEmpty)
     {
-        Status = NtWaitForSingleObject(hConsoleInput, FALSE, NULL);
-        Status = IoStatusBlock.Status;
+        /* Read the keyboard for an event, without waiting */
+        if (!WaitForInput)
+        {
+            Offset.QuadPart = 0;
+            Status = NtReadFile(hConsoleInput,
+                                NULL,
+                                NULL,
+                                NULL,
+                                &InputIosb,
+                                &InputDataQueue,
+                                sizeof(InputDataQueue),
+                                &Offset,
+                                NULL);
+            if (!NT_SUCCESS(Status))
+                return FALSE;
+            if (Status == STATUS_PENDING)
+            {
+                /* No input yet, we will have to wait next time */
+                *lpNumberOfEventsRead = 0;
+                WaitForInput = TRUE;
+                return TRUE;
+            }
+        }
+        else
+        {
+            /*
+             * We already tried to read from the keyboard and are
+             * waiting for data, check whether something showed up.
+             */
+            Timeout.QuadPart = -100; // Wait just a little bit.
+            Status = NtWaitForSingleObject(hConsoleInput, FALSE, &Timeout);
+            if (Status == STATUS_TIMEOUT)
+            {
+                /* Nothing yet, continue waiting next time */
+                *lpNumberOfEventsRead = 0;
+                WaitForInput = TRUE;
+                return TRUE;
+            }
+            WaitForInput = FALSE;
+            if (!NT_SUCCESS(Status))
+                return FALSE;
+        }
+
+        /* We got something in the queue */
+        InputQueueEmpty = FALSE;
+        WaitForInput = FALSE;
     }
+
+    /* Fetch from the queue but keep it inside */
+    InputData = InputDataQueue;
+
+    lpBuffer->EventType = KEY_EVENT;
+    Status = IntTranslateKey(hConsoleInput, &InputData, 
&lpBuffer->Event.KeyEvent);
     if (!NT_SUCCESS(Status))
         return FALSE;
 
+    *lpNumberOfEventsRead = 1;
+    return TRUE;
+}
+
+
+BOOL
+WINAPI
+ReadConsoleInput(
+    IN HANDLE hConsoleInput,
+    OUT PINPUT_RECORD lpBuffer,
+    IN DWORD nLength,
+    OUT LPDWORD lpNumberOfEventsRead)
+{
+    NTSTATUS Status;
+    LARGE_INTEGER Offset;
+    KEYBOARD_INPUT_DATA InputData;
+
+    if (InputQueueEmpty)
+    {
+        /* Read the keyboard and wait for an event, skipping the queue */
+        if (!WaitForInput)
+        {
+            Offset.QuadPart = 0;
+            Status = NtReadFile(hConsoleInput,
+                                NULL,
+                                NULL,
+                                NULL,
+                                &InputIosb,
+                                &InputDataQueue,
+                                sizeof(InputDataQueue),
+                                &Offset,
+                                NULL);
+            if (Status == STATUS_PENDING)
+            {
+                /* Block and wait for input */
+                WaitForInput = TRUE;
+                Status = NtWaitForSingleObject(hConsoleInput, FALSE, NULL);
+                WaitForInput = FALSE;
+                Status = InputIosb.Status;
+            }
+            if (!NT_SUCCESS(Status))
+                return FALSE;
+        }
+        else
+        {
+            /*
+             * We already tried to read from the keyboard and are
+             * waiting for data, block and wait for input.
+             */
+            Status = NtWaitForSingleObject(hConsoleInput, FALSE, NULL);
+            WaitForInput = FALSE;
+            Status = InputIosb.Status;
+            if (!NT_SUCCESS(Status))
+                return FALSE;
+        }
+    }
+
+    /* Fetch from the queue and empty it */
+    InputData = InputDataQueue;
+    InputQueueEmpty = TRUE;
+
     lpBuffer->EventType = KEY_EVENT;
     Status = IntTranslateKey(hConsoleInput, &InputData, 
&lpBuffer->Event.KeyEvent);
     if (!NT_SUCCESS(Status))
diff --git a/base/setup/usetup/consup.c b/base/setup/usetup/consup.c
index 461cd7cbac..f559d04edb 100644
--- a/base/setup/usetup/consup.c
+++ b/base/setup/usetup/consup.c
@@ -66,11 +66,39 @@ CONSOLE_ConInKey(
 
     while (TRUE)
     {
+        /* Wait for a key press */
         ReadConsoleInput(StdInput, Buffer, 1, &Read);
 
-        if ((Buffer->EventType == KEY_EVENT)
-         && (Buffer->Event.KeyEvent.bKeyDown != FALSE))
+        if ((Buffer->EventType == KEY_EVENT) &&
+            (Buffer->Event.KeyEvent.bKeyDown != FALSE))
+        {
             break;
+        }
+    }
+}
+
+BOOLEAN
+CONSOLE_ConInKeyPeek(
+    OUT PINPUT_RECORD Buffer)
+{
+    DWORD Read = 0;
+
+    while (TRUE)
+    {
+        /* Try to get a key press without blocking */
+        if (!PeekConsoleInput(StdInput, Buffer, 1, &Read))
+            return FALSE;
+        if (Read == 0)
+            return FALSE;
+
+        /* Consume it */
+        ReadConsoleInput(StdInput, Buffer, 1, &Read);
+
+        if ((Buffer->EventType == KEY_EVENT) &&
+            (Buffer->Event.KeyEvent.bKeyDown != FALSE))
+        {
+            return TRUE;
+        }
     }
 }
 
diff --git a/base/setup/usetup/consup.h b/base/setup/usetup/consup.h
index e00ebcd098..dce5fa86aa 100644
--- a/base/setup/usetup/consup.h
+++ b/base/setup/usetup/consup.h
@@ -64,6 +64,10 @@ VOID
 CONSOLE_ConInKey(
        OUT PINPUT_RECORD Buffer);
 
+BOOLEAN
+CONSOLE_ConInKeyPeek(
+    OUT PINPUT_RECORD Buffer);
+
 VOID
 CONSOLE_ConOutChar(
        IN CHAR c);

Reply via email to