2013-06-23 23:19:42 +00:00
|
|
|
/*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
2013-07-06 15:59:28 +00:00
|
|
|
* PROJECT: ReactOS Console Driver DLL
|
2013-07-13 04:54:49 +00:00
|
|
|
* FILE: win32ss/user/winsrv/consrv/condrv/coninput.c
|
2013-06-23 23:19:42 +00:00
|
|
|
* PURPOSE: Console Input functions
|
|
|
|
* PROGRAMMERS: Jeffrey Morlan
|
|
|
|
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
|
2014-02-04 19:54:42 +00:00
|
|
|
#include <consrv.h>
|
2013-06-23 23:19:42 +00:00
|
|
|
|
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
|
|
|
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
|
|
|
|
#define ConsoleInputUnicodeCharToAnsiChar(Console, dChar, sWChar) \
|
2014-05-02 18:44:26 +00:00
|
|
|
WideCharToMultiByte((Console)->InputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
|
2013-06-23 23:19:42 +00:00
|
|
|
|
|
|
|
#define ConsoleInputAnsiCharToUnicodeChar(Console, dWChar, sChar) \
|
2014-05-02 18:44:26 +00:00
|
|
|
MultiByteToWideChar((Console)->InputCodePage, 0, (sChar), 1, (dWChar), 1)
|
2013-06-23 23:19:42 +00:00
|
|
|
|
|
|
|
typedef struct ConsoleInput_t
|
|
|
|
{
|
|
|
|
LIST_ENTRY ListEntry;
|
|
|
|
INPUT_RECORD InputEvent;
|
|
|
|
} ConsoleInput;
|
|
|
|
|
|
|
|
|
|
|
|
/* PRIVATE FUNCTIONS **********************************************************/
|
|
|
|
|
2014-05-02 16:46:13 +00:00
|
|
|
static VOID
|
2013-06-23 23:19:42 +00:00
|
|
|
ConioInputEventToAnsi(PCONSOLE Console, PINPUT_RECORD InputEvent)
|
|
|
|
{
|
|
|
|
if (InputEvent->EventType == KEY_EVENT)
|
|
|
|
{
|
|
|
|
WCHAR UnicodeChar = InputEvent->Event.KeyEvent.uChar.UnicodeChar;
|
|
|
|
InputEvent->Event.KeyEvent.uChar.UnicodeChar = 0;
|
|
|
|
ConsoleInputUnicodeCharToAnsiChar(Console,
|
|
|
|
&InputEvent->Event.KeyEvent.uChar.AsciiChar,
|
|
|
|
&UnicodeChar);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-02 16:46:13 +00:00
|
|
|
static VOID
|
2014-04-17 00:46:43 +00:00
|
|
|
ConioInputEventToUnicode(PCONSOLE Console, PINPUT_RECORD InputEvent)
|
|
|
|
{
|
|
|
|
if (InputEvent->EventType == KEY_EVENT)
|
|
|
|
{
|
|
|
|
CHAR AsciiChar = InputEvent->Event.KeyEvent.uChar.AsciiChar;
|
|
|
|
InputEvent->Event.KeyEvent.uChar.AsciiChar = 0;
|
|
|
|
ConsoleInputAnsiCharToUnicodeChar(Console,
|
|
|
|
&InputEvent->Event.KeyEvent.uChar.UnicodeChar,
|
|
|
|
&AsciiChar);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-02 16:46:13 +00:00
|
|
|
NTSTATUS
|
2013-10-26 20:53:05 +00:00
|
|
|
ConioAddInputEvent(PCONSOLE Console,
|
|
|
|
PINPUT_RECORD InputEvent,
|
|
|
|
BOOLEAN AppendToEnd)
|
2013-06-23 23:19:42 +00:00
|
|
|
{
|
|
|
|
ConsoleInput *ConInRec;
|
|
|
|
|
|
|
|
/* Check for pause or unpause */
|
|
|
|
if (InputEvent->EventType == KEY_EVENT && InputEvent->Event.KeyEvent.bKeyDown)
|
|
|
|
{
|
|
|
|
WORD vk = InputEvent->Event.KeyEvent.wVirtualKeyCode;
|
|
|
|
if (!(Console->PauseFlags & PAUSED_FROM_KEYBOARD))
|
|
|
|
{
|
|
|
|
DWORD cks = InputEvent->Event.KeyEvent.dwControlKeyState;
|
|
|
|
if (Console->InputBuffer.Mode & ENABLE_LINE_INPUT &&
|
|
|
|
(vk == VK_PAUSE || (vk == 'S' &&
|
|
|
|
(cks & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) &&
|
|
|
|
!(cks & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)))))
|
|
|
|
{
|
|
|
|
ConioPause(Console, PAUSED_FROM_KEYBOARD);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ((vk < VK_SHIFT || vk > VK_CAPITAL) && vk != VK_LWIN &&
|
|
|
|
vk != VK_RWIN && vk != VK_NUMLOCK && vk != VK_SCROLL)
|
|
|
|
{
|
|
|
|
ConioUnpause(Console, PAUSED_FROM_KEYBOARD);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add event to the queue */
|
|
|
|
ConInRec = ConsoleAllocHeap(0, sizeof(ConsoleInput));
|
|
|
|
if (ConInRec == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
|
|
|
ConInRec->InputEvent = *InputEvent;
|
2013-10-26 20:53:05 +00:00
|
|
|
|
|
|
|
if (AppendToEnd)
|
|
|
|
{
|
|
|
|
/* Append the event to the end of the queue */
|
|
|
|
InsertTailList(&Console->InputBuffer.InputEvents, &ConInRec->ListEntry);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Append the event to the beginning of the queue */
|
|
|
|
InsertHeadList(&Console->InputBuffer.InputEvents, &ConInRec->ListEntry);
|
|
|
|
}
|
2013-06-23 23:19:42 +00:00
|
|
|
|
|
|
|
SetEvent(Console->InputBuffer.ActiveEvent);
|
2014-05-02 16:46:13 +00:00
|
|
|
CsrNotifyWait(&Console->ReadWaitQueue,
|
2013-10-05 22:17:34 +00:00
|
|
|
FALSE,
|
2013-06-23 23:19:42 +00:00
|
|
|
NULL,
|
|
|
|
NULL);
|
2014-05-02 16:46:13 +00:00
|
|
|
if (!IsListEmpty(&Console->ReadWaitQueue))
|
2013-06-23 23:19:42 +00:00
|
|
|
{
|
2014-05-02 16:46:13 +00:00
|
|
|
CsrDereferenceWait(&Console->ReadWaitQueue);
|
2013-06-23 23:19:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2014-05-02 16:46:13 +00:00
|
|
|
NTSTATUS
|
2013-10-26 20:53:05 +00:00
|
|
|
ConioProcessInputEvent(PCONSOLE Console,
|
|
|
|
PINPUT_RECORD InputEvent)
|
|
|
|
{
|
|
|
|
return ConioAddInputEvent(Console, InputEvent, TRUE);
|
|
|
|
}
|
|
|
|
|
2014-05-02 16:46:13 +00:00
|
|
|
VOID
|
2013-06-23 23:19:42 +00:00
|
|
|
PurgeInputBuffer(PCONSOLE Console)
|
|
|
|
{
|
|
|
|
PLIST_ENTRY CurrentEntry;
|
|
|
|
ConsoleInput* Event;
|
|
|
|
|
|
|
|
while (!IsListEmpty(&Console->InputBuffer.InputEvents))
|
|
|
|
{
|
|
|
|
CurrentEntry = RemoveHeadList(&Console->InputBuffer.InputEvents);
|
|
|
|
Event = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
|
|
|
|
ConsoleFreeHeap(Event);
|
|
|
|
}
|
|
|
|
|
|
|
|
CloseHandle(Console->InputBuffer.ActiveEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-06 15:59:28 +00:00
|
|
|
/* PUBLIC DRIVER APIS *********************************************************/
|
2013-06-23 23:19:42 +00:00
|
|
|
|
2013-06-27 00:20:58 +00:00
|
|
|
NTSTATUS NTAPI
|
|
|
|
ConDrvReadConsole(IN PCONSOLE Console,
|
|
|
|
IN PCONSOLE_INPUT_BUFFER InputBuffer,
|
|
|
|
IN BOOLEAN Unicode,
|
|
|
|
OUT PVOID Buffer,
|
|
|
|
IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl,
|
|
|
|
IN ULONG NumCharsToRead,
|
|
|
|
OUT PULONG NumCharsRead OPTIONAL)
|
|
|
|
{
|
|
|
|
// STATUS_PENDING : Wait if more to read ; STATUS_SUCCESS : Don't wait.
|
|
|
|
NTSTATUS Status = STATUS_PENDING;
|
|
|
|
PLIST_ENTRY CurrentEntry;
|
|
|
|
ConsoleInput *Input;
|
2014-04-28 19:50:27 +00:00
|
|
|
ULONG i;
|
2013-06-27 00:20:58 +00:00
|
|
|
|
|
|
|
if (Console == NULL || InputBuffer == NULL || /* Buffer == NULL || */
|
|
|
|
ReadControl == NULL || ReadControl->nLength != sizeof(CONSOLE_READCONSOLE_CONTROL))
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Validity checks */
|
|
|
|
ASSERT(Console == InputBuffer->Header.Console);
|
2014-05-02 15:09:26 +00:00
|
|
|
ASSERT( (Buffer != NULL && NumCharsToRead > 0) ||
|
2013-06-27 00:20:58 +00:00
|
|
|
(Buffer == NULL && NumCharsToRead == 0) );
|
|
|
|
|
|
|
|
/* We haven't read anything (yet) */
|
|
|
|
|
2014-04-28 19:50:27 +00:00
|
|
|
i = ReadControl->nInitialChars;
|
|
|
|
|
2013-06-27 00:20:58 +00:00
|
|
|
if (InputBuffer->Mode & ENABLE_LINE_INPUT)
|
|
|
|
{
|
|
|
|
if (Console->LineBuffer == NULL)
|
|
|
|
{
|
|
|
|
/* Starting a new line */
|
|
|
|
Console->LineMaxSize = (WORD)max(256, NumCharsToRead);
|
|
|
|
|
|
|
|
Console->LineBuffer = ConsoleAllocHeap(0, Console->LineMaxSize * sizeof(WCHAR));
|
|
|
|
if (Console->LineBuffer == NULL) return STATUS_NO_MEMORY;
|
|
|
|
|
|
|
|
Console->LineComplete = FALSE;
|
|
|
|
Console->LineUpPressed = FALSE;
|
2014-04-10 20:24:49 +00:00
|
|
|
Console->LineInsertToggle = Console->InsertMode;
|
2013-06-27 00:20:58 +00:00
|
|
|
Console->LineWakeupMask = ReadControl->dwCtrlWakeupMask;
|
|
|
|
Console->LineSize = ReadControl->nInitialChars;
|
|
|
|
Console->LinePos = Console->LineSize;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pre-filling the buffer is only allowed in the Unicode API,
|
|
|
|
* so we don't need to worry about ANSI <-> Unicode conversion.
|
|
|
|
*/
|
|
|
|
memcpy(Console->LineBuffer, Buffer, Console->LineSize * sizeof(WCHAR));
|
|
|
|
if (Console->LineSize == Console->LineMaxSize)
|
|
|
|
{
|
|
|
|
Console->LineComplete = TRUE;
|
|
|
|
Console->LinePos = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we don't have a complete line yet, process the pending input */
|
|
|
|
while (!Console->LineComplete && !IsListEmpty(&InputBuffer->InputEvents))
|
|
|
|
{
|
|
|
|
/* Remove input event from queue */
|
|
|
|
CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
|
|
|
|
if (IsListEmpty(&InputBuffer->InputEvents))
|
|
|
|
{
|
|
|
|
ResetEvent(InputBuffer->ActiveEvent);
|
|
|
|
}
|
|
|
|
Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
|
|
|
|
|
|
|
|
/* Only pay attention to key down */
|
|
|
|
if (Input->InputEvent.EventType == KEY_EVENT &&
|
|
|
|
Input->InputEvent.Event.KeyEvent.bKeyDown)
|
|
|
|
{
|
|
|
|
LineInputKeyDown(Console, &Input->InputEvent.Event.KeyEvent);
|
|
|
|
ReadControl->dwControlKeyState = Input->InputEvent.Event.KeyEvent.dwControlKeyState;
|
|
|
|
}
|
|
|
|
ConsoleFreeHeap(Input);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if we have a complete line to read from */
|
|
|
|
if (Console->LineComplete)
|
|
|
|
{
|
|
|
|
while (i < NumCharsToRead && Console->LinePos != Console->LineSize)
|
|
|
|
{
|
|
|
|
WCHAR Char = Console->LineBuffer[Console->LinePos++];
|
|
|
|
|
|
|
|
if (Unicode)
|
|
|
|
{
|
|
|
|
((PWCHAR)Buffer)[i] = Char;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ConsoleInputUnicodeCharToAnsiChar(Console, &((PCHAR)Buffer)[i], &Char);
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Console->LinePos == Console->LineSize)
|
|
|
|
{
|
|
|
|
/* Entire line has been read */
|
|
|
|
ConsoleFreeHeap(Console->LineBuffer);
|
|
|
|
Console->LineBuffer = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Character input */
|
|
|
|
while (i < NumCharsToRead && !IsListEmpty(&InputBuffer->InputEvents))
|
|
|
|
{
|
|
|
|
/* Remove input event from queue */
|
|
|
|
CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
|
|
|
|
if (IsListEmpty(&InputBuffer->InputEvents))
|
|
|
|
{
|
|
|
|
ResetEvent(InputBuffer->ActiveEvent);
|
|
|
|
}
|
|
|
|
Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
|
|
|
|
|
|
|
|
/* Only pay attention to valid ASCII chars, on key down */
|
|
|
|
if (Input->InputEvent.EventType == KEY_EVENT &&
|
|
|
|
Input->InputEvent.Event.KeyEvent.bKeyDown &&
|
|
|
|
Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar != L'\0')
|
|
|
|
{
|
|
|
|
WCHAR Char = Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar;
|
|
|
|
|
|
|
|
if (Unicode)
|
|
|
|
{
|
|
|
|
((PWCHAR)Buffer)[i] = Char;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ConsoleInputUnicodeCharToAnsiChar(Console, &((PCHAR)Buffer)[i], &Char);
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
|
|
|
|
/* Did read something */
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
ConsoleFreeHeap(Input);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NumCharsRead) *NumCharsRead = i;
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS NTAPI
|
|
|
|
ConDrvGetConsoleInput(IN PCONSOLE Console,
|
|
|
|
IN PCONSOLE_INPUT_BUFFER InputBuffer,
|
2013-11-10 20:20:57 +00:00
|
|
|
IN BOOLEAN KeepEvents,
|
2013-06-27 00:20:58 +00:00
|
|
|
IN BOOLEAN WaitForMoreEvents,
|
|
|
|
IN BOOLEAN Unicode,
|
|
|
|
OUT PINPUT_RECORD InputRecord,
|
|
|
|
IN ULONG NumEventsToRead,
|
|
|
|
OUT PULONG NumEventsRead OPTIONAL)
|
|
|
|
{
|
|
|
|
PLIST_ENTRY CurrentInput;
|
|
|
|
ConsoleInput* Input;
|
|
|
|
ULONG i = 0;
|
|
|
|
|
|
|
|
if (Console == NULL || InputBuffer == NULL /* || InputRecord == NULL */)
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
/* Validity checks */
|
|
|
|
ASSERT(Console == InputBuffer->Header.Console);
|
2014-05-02 15:09:26 +00:00
|
|
|
ASSERT( (InputRecord != NULL && NumEventsToRead > 0) ||
|
2013-06-27 00:20:58 +00:00
|
|
|
(InputRecord == NULL && NumEventsToRead == 0) );
|
|
|
|
|
|
|
|
// Do NOT do that !! Use the existing number of events already read, if any...
|
|
|
|
// if (NumEventsRead) *NumEventsRead = 0;
|
|
|
|
|
|
|
|
if (IsListEmpty(&InputBuffer->InputEvents))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* No input is available. Wait for more input if requested,
|
|
|
|
* otherwise, we don't wait, so we return success.
|
|
|
|
*/
|
|
|
|
return (WaitForMoreEvents ? STATUS_PENDING : STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Only get input if there is any */
|
|
|
|
CurrentInput = InputBuffer->InputEvents.Flink;
|
|
|
|
if (NumEventsRead) i = *NumEventsRead; // We will read the remaining events...
|
|
|
|
|
|
|
|
while ((CurrentInput != &InputBuffer->InputEvents) && (i < NumEventsToRead))
|
|
|
|
{
|
|
|
|
Input = CONTAINING_RECORD(CurrentInput, ConsoleInput, ListEntry);
|
|
|
|
|
|
|
|
*InputRecord = Input->InputEvent;
|
|
|
|
|
|
|
|
if (!Unicode)
|
|
|
|
{
|
|
|
|
ConioInputEventToAnsi(InputBuffer->Header.Console, InputRecord);
|
|
|
|
}
|
|
|
|
|
|
|
|
++InputRecord;
|
|
|
|
++i;
|
|
|
|
CurrentInput = CurrentInput->Flink;
|
|
|
|
|
2013-11-10 20:20:57 +00:00
|
|
|
/* Remove the events from the queue if needed */
|
|
|
|
if (!KeepEvents)
|
2013-06-27 00:20:58 +00:00
|
|
|
{
|
|
|
|
RemoveEntryList(&Input->ListEntry);
|
|
|
|
ConsoleFreeHeap(Input);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NumEventsRead) *NumEventsRead = i;
|
|
|
|
|
|
|
|
if (IsListEmpty(&InputBuffer->InputEvents))
|
|
|
|
{
|
|
|
|
ResetEvent(InputBuffer->ActiveEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We read all the inputs available, we return success */
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2013-06-23 23:19:42 +00:00
|
|
|
NTSTATUS NTAPI
|
|
|
|
ConDrvWriteConsoleInput(IN PCONSOLE Console,
|
|
|
|
IN PCONSOLE_INPUT_BUFFER InputBuffer,
|
|
|
|
IN BOOLEAN Unicode,
|
2013-10-26 20:53:05 +00:00
|
|
|
IN BOOLEAN AppendToEnd,
|
2013-06-23 23:19:42 +00:00
|
|
|
IN PINPUT_RECORD InputRecord,
|
|
|
|
IN ULONG NumEventsToWrite,
|
2013-06-27 00:20:58 +00:00
|
|
|
OUT PULONG NumEventsWritten OPTIONAL)
|
2013-06-23 23:19:42 +00:00
|
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
if (Console == NULL || InputBuffer == NULL /* || InputRecord == NULL */)
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
/* Validity checks */
|
|
|
|
ASSERT(Console == InputBuffer->Header.Console);
|
2014-05-02 15:09:26 +00:00
|
|
|
ASSERT( (InputRecord != NULL && NumEventsToWrite > 0) ||
|
2013-06-23 23:19:42 +00:00
|
|
|
(InputRecord == NULL && NumEventsToWrite == 0) );
|
|
|
|
|
2013-06-27 00:20:58 +00:00
|
|
|
// if (NumEventsWritten) *NumEventsWritten = 0;
|
2013-06-23 23:19:42 +00:00
|
|
|
|
2014-07-28 13:20:54 +00:00
|
|
|
/// Status = ConioAddInputEvents(Console, InputRecord, NumEventsToWrite, NumEventsWritten, AppendToEnd);
|
|
|
|
|
|
|
|
for (i = 0; i < NumEventsToWrite && NT_SUCCESS(Status); ++i)
|
2013-06-23 23:19:42 +00:00
|
|
|
{
|
2014-04-17 00:46:43 +00:00
|
|
|
if (!Unicode)
|
2013-06-23 23:19:42 +00:00
|
|
|
{
|
2014-04-17 00:46:43 +00:00
|
|
|
ConioInputEventToUnicode(Console, InputRecord);
|
2013-06-23 23:19:42 +00:00
|
|
|
}
|
|
|
|
|
2013-10-26 20:53:05 +00:00
|
|
|
Status = ConioAddInputEvent(Console, InputRecord++, AppendToEnd);
|
2013-06-23 23:19:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (NumEventsWritten) *NumEventsWritten = i;
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS NTAPI
|
|
|
|
ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console,
|
|
|
|
IN PCONSOLE_INPUT_BUFFER InputBuffer)
|
|
|
|
{
|
|
|
|
PLIST_ENTRY CurrentEntry;
|
|
|
|
ConsoleInput* Event;
|
|
|
|
|
|
|
|
if (Console == NULL || InputBuffer == NULL)
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
/* Validity check */
|
|
|
|
ASSERT(Console == InputBuffer->Header.Console);
|
|
|
|
|
|
|
|
/* Discard all entries in the input event queue */
|
|
|
|
while (!IsListEmpty(&InputBuffer->InputEvents))
|
|
|
|
{
|
|
|
|
CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
|
|
|
|
Event = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
|
|
|
|
ConsoleFreeHeap(Event);
|
|
|
|
}
|
|
|
|
ResetEvent(InputBuffer->ActiveEvent);
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS NTAPI
|
|
|
|
ConDrvGetConsoleNumberOfInputEvents(IN PCONSOLE Console,
|
|
|
|
IN PCONSOLE_INPUT_BUFFER InputBuffer,
|
2014-04-20 11:25:38 +00:00
|
|
|
OUT PULONG NumberOfEvents)
|
2013-06-23 23:19:42 +00:00
|
|
|
{
|
|
|
|
PLIST_ENTRY CurrentInput;
|
|
|
|
|
2014-04-20 11:25:38 +00:00
|
|
|
if (Console == NULL || InputBuffer == NULL || NumberOfEvents == NULL)
|
2013-06-23 23:19:42 +00:00
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
/* Validity check */
|
|
|
|
ASSERT(Console == InputBuffer->Header.Console);
|
|
|
|
|
2014-04-20 11:25:38 +00:00
|
|
|
*NumberOfEvents = 0;
|
2013-06-23 23:19:42 +00:00
|
|
|
|
|
|
|
/* If there are any events ... */
|
|
|
|
CurrentInput = InputBuffer->InputEvents.Flink;
|
|
|
|
while (CurrentInput != &InputBuffer->InputEvents)
|
|
|
|
{
|
|
|
|
CurrentInput = CurrentInput->Flink;
|
2014-04-20 11:25:38 +00:00
|
|
|
(*NumberOfEvents)++;
|
2013-06-23 23:19:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF */
|