+++ /dev/null
-/*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS Console Driver DLL
- * FILE: win32ss/user/winsrv/consrv/condrv/coninput.c
- * PURPOSE: Console Input functions
- * PROGRAMMERS: Jeffrey Morlan
- * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
- */
-
-/* INCLUDES *******************************************************************/
-
-#include <consrv.h>
-
-#define NDEBUG
-#include <debug.h>
-
-/* GLOBALS ********************************************************************/
-
-#define ConSrvGetInputBuffer(ProcessData, Handle, Ptr, Access, LockConsole) \
- ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), NULL, \
- (Access), (LockConsole), INPUT_BUFFER)
-#define ConSrvGetInputBufferAndHandleEntry(ProcessData, Handle, Ptr, Entry, Access, LockConsole) \
- ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), (Entry), \
- (Access), (LockConsole), INPUT_BUFFER)
-#define ConSrvReleaseInputBuffer(Buff, IsConsoleLocked) \
- ConSrvReleaseObject(&(Buff)->Header, (IsConsoleLocked))
-
-
-#define ConsoleInputUnicodeCharToAnsiChar(Console, dChar, sWChar) \
- WideCharToMultiByte((Console)->CodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
-
-#define ConsoleInputAnsiCharToUnicodeChar(Console, dWChar, sChar) \
- MultiByteToWideChar((Console)->CodePage, 0, (sChar), 1, (dWChar), 1)
-
-typedef struct ConsoleInput_t
-{
- LIST_ENTRY ListEntry;
- INPUT_RECORD InputEvent;
-} ConsoleInput;
-
-
-/* PRIVATE FUNCTIONS **********************************************************/
-
-static VOID FASTCALL
-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);
- }
-}
-
-static VOID FASTCALL
-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);
- }
-}
-
-NTSTATUS FASTCALL
-ConioAddInputEvent(PCONSOLE Console,
- PINPUT_RECORD InputEvent,
- BOOLEAN AppendToEnd)
-{
- 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;
-
- 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);
- }
-
- SetEvent(Console->InputBuffer.ActiveEvent);
- CsrNotifyWait(&Console->InputBuffer.ReadWaitQueue,
- FALSE,
- NULL,
- NULL);
- if (!IsListEmpty(&Console->InputBuffer.ReadWaitQueue))
- {
- CsrDereferenceWait(&Console->InputBuffer.ReadWaitQueue);
- }
-
- return STATUS_SUCCESS;
-}
-
-NTSTATUS FASTCALL
-ConioProcessInputEvent(PCONSOLE Console,
- PINPUT_RECORD InputEvent)
-{
- return ConioAddInputEvent(Console, InputEvent, TRUE);
-}
-
-VOID FASTCALL
-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);
-}
-
-/*
- * This function explicitely references Console->ActiveBuffer
- * (and also makes use of keyboard functions...).
- * It is possible that it will move into frontends...
- */
-VOID NTAPI
-ConDrvProcessKey(IN PCONSOLE Console,
- IN BOOLEAN Down,
- IN UINT VirtualKeyCode,
- IN UINT VirtualScanCode,
- IN WCHAR UnicodeChar,
- IN ULONG ShiftState,
- IN BYTE KeyStateCtrl)
-{
- INPUT_RECORD er;
-
- /* process Ctrl-C and Ctrl-Break */
- if ( Console->InputBuffer.Mode & ENABLE_PROCESSED_INPUT &&
- Down && (VirtualKeyCode == VK_PAUSE || VirtualKeyCode == 'C') &&
- (ShiftState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) || KeyStateCtrl & 0x80) )
- {
- DPRINT1("Console_Api Ctrl-C\n");
- ConDrvConsoleProcessCtrlEvent(Console, 0, CTRL_C_EVENT);
-
- if (Console->LineBuffer && !Console->LineComplete)
- {
- /* Line input is in progress; end it */
- Console->LinePos = Console->LineSize = 0;
- Console->LineComplete = TRUE;
- }
- return;
- }
-
- if ( (ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) != 0 &&
- (VK_UP == VirtualKeyCode || VK_DOWN == VirtualKeyCode) )
- {
- if (!Down) return;
-
- /* scroll up or down */
- if (VK_UP == VirtualKeyCode)
- {
- /* only scroll up if there is room to scroll up into */
- if (Console->ActiveBuffer->CursorPosition.Y != Console->ActiveBuffer->ScreenBufferSize.Y - 1)
- {
- Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY +
- Console->ActiveBuffer->ScreenBufferSize.Y - 1) %
- Console->ActiveBuffer->ScreenBufferSize.Y;
- Console->ActiveBuffer->CursorPosition.Y++;
- }
- }
- else
- {
- /* only scroll down if there is room to scroll down into */
- if (Console->ActiveBuffer->CursorPosition.Y != 0)
- {
- Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + 1) %
- Console->ActiveBuffer->ScreenBufferSize.Y;
- Console->ActiveBuffer->CursorPosition.Y--;
- }
- }
-
- ConioDrawConsole(Console);
- return;
- }
-
- er.EventType = KEY_EVENT;
- er.Event.KeyEvent.bKeyDown = Down;
- er.Event.KeyEvent.wRepeatCount = 1;
- er.Event.KeyEvent.wVirtualKeyCode = VirtualKeyCode;
- er.Event.KeyEvent.wVirtualScanCode = VirtualScanCode;
- er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar;
- er.Event.KeyEvent.dwControlKeyState = ShiftState;
-
- ConioProcessInputEvent(Console, &er);
-}
-
-
-/* PUBLIC DRIVER APIS *********************************************************/
-
-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;
- ULONG i;
-
- 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);
- ASSERT( (Buffer != NULL && NumCharsToRead >= 0) ||
- (Buffer == NULL && NumCharsToRead == 0) );
-
- /* We haven't read anything (yet) */
-
- i = ReadControl->nInitialChars;
-
- 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;
- Console->LineInsertToggle = Console->InsertMode;
- 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,
- IN BOOLEAN KeepEvents,
- 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);
- ASSERT( (InputRecord != NULL && NumEventsToRead >= 0) ||
- (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;
-
- /* Remove the events from the queue if needed */
- if (!KeepEvents)
- {
- 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;
-}
-
-NTSTATUS NTAPI
-ConDrvWriteConsoleInput(IN PCONSOLE Console,
- IN PCONSOLE_INPUT_BUFFER InputBuffer,
- IN BOOLEAN Unicode,
- IN BOOLEAN AppendToEnd,
- IN PINPUT_RECORD InputRecord,
- IN ULONG NumEventsToWrite,
- OUT PULONG NumEventsWritten OPTIONAL)
-{
- NTSTATUS Status = STATUS_SUCCESS;
- ULONG i;
-
- if (Console == NULL || InputBuffer == NULL /* || InputRecord == NULL */)
- return STATUS_INVALID_PARAMETER;
-
- /* Validity checks */
- ASSERT(Console == InputBuffer->Header.Console);
- ASSERT( (InputRecord != NULL && NumEventsToWrite >= 0) ||
- (InputRecord == NULL && NumEventsToWrite == 0) );
-
- // Do NOT do that !! Use the existing number of events already written, if any...
- // if (NumEventsWritten) *NumEventsWritten = 0;
-
- for (i = (NumEventsWritten ? *NumEventsWritten : 0); i < NumEventsToWrite && NT_SUCCESS(Status); ++i)
- {
- if (!Unicode)
- {
- ConioInputEventToUnicode(Console, InputRecord);
- }
-
- Status = ConioAddInputEvent(Console, InputRecord++, AppendToEnd);
- }
-
- 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,
- OUT PULONG NumberOfEvents)
-{
- PLIST_ENTRY CurrentInput;
-
- if (Console == NULL || InputBuffer == NULL || NumberOfEvents == NULL)
- return STATUS_INVALID_PARAMETER;
-
- /* Validity check */
- ASSERT(Console == InputBuffer->Header.Console);
-
- *NumberOfEvents = 0;
-
- /* If there are any events ... */
- CurrentInput = InputBuffer->InputEvents.Flink;
- while (CurrentInput != &InputBuffer->InputEvents)
- {
- CurrentInput = CurrentInput->Flink;
- (*NumberOfEvents)++;
- }
-
- return STATUS_SUCCESS;
-}
-
-/* EOF */