reactos/win32ss/user/consrv/coninput.c
Hermès Bélusca-Maïto e1ef078741 Create this branch to work on loading of different Kernel-Debugger DLL providers, and see whether it is possible to move KDBG from ntoskrnl to a new DLL called, say, KDROSDBG.DLL.
The idea then would be to have the following behaviour (when specifying the following options in the kernel command line):

/DEBUGPORT=COMi --> load KDCOM.DLL and use COMi port (i == 1,2,3,4) if possible.
/DEBUGPORT=FOO  --> load KDFOO.DLL (useful for KDUSB.DLL, KD1394.DLL, KDBAZIS.DLL for VirtualKD, etc...)
/DEBUGPORT=ROSDBG:[COMi|SCREEN|FILE|GDB|...] --> load KDROSDBG.DLL which contains the ROS kernel debugger, and use COMi or SCREEN or... as output port.

svn path=/branches/kd++/; revision=58883
2013-04-28 13:26:45 +00:00

904 lines
30 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/consrv/coninput.c
* PURPOSE: Console Input functions
* PROGRAMMERS: Jeffrey Morlan
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "include/conio.h"
#include "conio.h"
#include "handle.h"
#include "lineinput.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;
typedef struct _GET_INPUT_INFO
{
PCSR_THREAD CallingThread; // The thread which called the input API.
PVOID HandleEntry; // The handle data associated with the wait thread.
PCONSOLE_INPUT_BUFFER InputBuffer; // The input buffer corresponding to the handle.
} GET_INPUT_INFO, *PGET_INPUT_INFO;
/* 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);
}
}
NTSTATUS FASTCALL
ConioProcessInputEvent(PCONSOLE Console,
PINPUT_RECORD InputEvent)
{
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 = RtlAllocateHeap(ConSrvHeap, 0, sizeof(ConsoleInput));
if (ConInRec == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
ConInRec->InputEvent = *InputEvent;
InsertTailList(&Console->InputBuffer.InputEvents, &ConInRec->ListEntry);
SetEvent(Console->InputBuffer.ActiveEvent);
CsrNotifyWait(&Console->InputBuffer.ReadWaitQueue,
WaitAny,
NULL,
NULL);
if (!IsListEmpty(&Console->InputBuffer.ReadWaitQueue))
{
CsrDereferenceWait(&Console->InputBuffer.ReadWaitQueue);
}
return STATUS_SUCCESS;
}
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);
RtlFreeHeap(ConSrvHeap, 0, Event);
}
CloseHandle(Console->InputBuffer.ActiveEvent);
}
static DWORD FASTCALL
ConioGetShiftState(PBYTE KeyState, LPARAM lParam)
{
DWORD ssOut = 0;
if (KeyState[VK_CAPITAL] & 0x01)
ssOut |= CAPSLOCK_ON;
if (KeyState[VK_NUMLOCK] & 0x01)
ssOut |= NUMLOCK_ON;
if (KeyState[VK_SCROLL] & 0x01)
ssOut |= SCROLLLOCK_ON;
if (KeyState[VK_SHIFT] & 0x80)
ssOut |= SHIFT_PRESSED;
if (KeyState[VK_LCONTROL] & 0x80)
ssOut |= LEFT_CTRL_PRESSED;
if (KeyState[VK_RCONTROL] & 0x80)
ssOut |= RIGHT_CTRL_PRESSED;
if (KeyState[VK_LMENU] & 0x80)
ssOut |= LEFT_ALT_PRESSED;
if (KeyState[VK_RMENU] & 0x80)
ssOut |= RIGHT_ALT_PRESSED;
/* See WM_CHAR MSDN documentation for instance */
if (lParam & 0x01000000)
ssOut |= ENHANCED_KEY;
return ssOut;
}
VOID WINAPI
ConioProcessKey(PCONSOLE Console, MSG* msg)
{
static BYTE KeyState[256] = { 0 };
/* MSDN mentions that you should use the last virtual key code received
* when putting a virtual key identity to a WM_CHAR message since multiple
* or translated keys may be involved. */
static UINT LastVirtualKey = 0;
DWORD ShiftState;
UINT RepeatCount;
WCHAR UnicodeChar;
UINT VirtualKeyCode;
UINT VirtualScanCode;
BOOL Down = FALSE;
INPUT_RECORD er;
BOOLEAN Fake; // synthesized, not a real event
BOOLEAN NotChar; // message should not be used to return a character
if (NULL == Console)
{
DPRINT1("No Active Console!\n");
return;
}
RepeatCount = 1;
VirtualScanCode = (msg->lParam >> 16) & 0xff;
Down = msg->message == WM_KEYDOWN || msg->message == WM_CHAR ||
msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSCHAR;
GetKeyboardState(KeyState);
ShiftState = ConioGetShiftState(KeyState, msg->lParam);
if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR)
{
VirtualKeyCode = LastVirtualKey;
UnicodeChar = msg->wParam;
}
else
{
WCHAR Chars[2];
INT RetChars = 0;
VirtualKeyCode = msg->wParam;
RetChars = ToUnicodeEx(VirtualKeyCode,
VirtualScanCode,
KeyState,
Chars,
2,
0,
0);
UnicodeChar = (1 == RetChars ? Chars[0] : 0);
}
er.EventType = KEY_EVENT;
er.Event.KeyEvent.bKeyDown = Down;
er.Event.KeyEvent.wRepeatCount = RepeatCount;
er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar;
er.Event.KeyEvent.dwControlKeyState = ShiftState;
er.Event.KeyEvent.wVirtualKeyCode = VirtualKeyCode;
er.Event.KeyEvent.wVirtualScanCode = VirtualScanCode;
if (ConioProcessKeyCallback(Console,
msg,
KeyState[VK_MENU],
ShiftState,
VirtualKeyCode,
Down))
{
return;
}
Fake = UnicodeChar &&
(msg->message != WM_CHAR && msg->message != WM_SYSCHAR &&
msg->message != WM_KEYUP && msg->message != WM_SYSKEYUP);
NotChar = (msg->message != WM_CHAR && msg->message != WM_SYSCHAR);
if (NotChar) LastVirtualKey = msg->wParam;
DPRINT("CONSRV: %s %s %s %s %02x %02x '%lc' %04x\n",
Down ? "down" : "up ",
(msg->message == WM_CHAR || msg->message == WM_SYSCHAR) ?
"char" : "key ",
Fake ? "fake" : "real",
NotChar ? "notc" : "char",
VirtualScanCode,
VirtualKeyCode,
(UnicodeChar >= L' ') ? UnicodeChar : L'.',
ShiftState);
if (Fake) return;
/* process Ctrl-C and Ctrl-Break */
if (Console->InputBuffer.Mode & ENABLE_PROCESSED_INPUT &&
er.Event.KeyEvent.bKeyDown &&
((er.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE) ||
(er.Event.KeyEvent.wVirtualKeyCode == 'C')) &&
(er.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) || KeyState[VK_CONTROL] & 0x80))
{
DPRINT1("Console_Api Ctrl-C\n");
ConSrvConsoleProcessCtrlEvent(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 (0 != (er.Event.KeyEvent.dwControlKeyState
& (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
&& (VK_UP == er.Event.KeyEvent.wVirtualKeyCode
|| VK_DOWN == er.Event.KeyEvent.wVirtualKeyCode))
{
if (er.Event.KeyEvent.bKeyDown)
{
/* scroll up or down */
if (VK_UP == er.Event.KeyEvent.wVirtualKeyCode)
{
/* 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;
}
ConioProcessInputEvent(Console, &er);
}
static NTSTATUS
WaitBeforeReading(IN PGET_INPUT_INFO InputInfo,
IN PCSR_API_MESSAGE ApiMessage,
IN CSR_WAIT_FUNCTION WaitFunction OPTIONAL,
IN BOOL CreateWaitBlock OPTIONAL)
{
if (CreateWaitBlock)
{
PGET_INPUT_INFO CapturedInputInfo;
CapturedInputInfo = RtlAllocateHeap(ConSrvHeap, 0, sizeof(GET_INPUT_INFO));
if (!CapturedInputInfo) return STATUS_NO_MEMORY;
RtlMoveMemory(CapturedInputInfo, InputInfo, sizeof(GET_INPUT_INFO));
if (!CsrCreateWait(&InputInfo->InputBuffer->ReadWaitQueue,
WaitFunction,
InputInfo->CallingThread,
ApiMessage,
CapturedInputInfo,
NULL))
{
RtlFreeHeap(ConSrvHeap, 0, CapturedInputInfo);
return STATUS_NO_MEMORY;
}
}
/* Wait for input */
return STATUS_PENDING;
}
static NTSTATUS
ReadInputBuffer(IN PGET_INPUT_INFO InputInfo,
IN BOOL Wait,
IN PCSR_API_MESSAGE ApiMessage,
IN BOOL CreateWaitBlock OPTIONAL);
// Wait function CSR_WAIT_FUNCTION
static BOOLEAN
ReadInputBufferThread(IN PLIST_ENTRY WaitList,
IN PCSR_THREAD WaitThread,
IN PCSR_API_MESSAGE WaitApiMessage,
IN PVOID WaitContext,
IN PVOID WaitArgument1,
IN PVOID WaitArgument2,
IN ULONG WaitFlags)
{
NTSTATUS Status;
PCONSOLE_GETINPUT GetInputRequest = &((PCONSOLE_API_MESSAGE)WaitApiMessage)->Data.GetInputRequest;
PGET_INPUT_INFO InputInfo = (PGET_INPUT_INFO)WaitContext;
PVOID InputHandle = WaitArgument2;
DPRINT("ReadInputBufferThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags);
/*
* If we are notified of the process termination via a call
* to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
* CsrDestroyThread, just return.
*/
if (WaitFlags & CsrProcessTerminating)
{
Status = STATUS_THREAD_IS_TERMINATING;
goto Quit;
}
/*
* Somebody is closing a handle to this input buffer,
* by calling ConSrvCloseHandleEntry.
* See whether we are linked to that handle (ie. we
* are a waiter for this handle), and if so, return.
* Otherwise, ignore the call and continue waiting.
*/
if (InputHandle != NULL)
{
Status = (InputHandle == InputInfo->HandleEntry ? STATUS_ALERTED
: STATUS_PENDING);
goto Quit;
}
/*
* If we go there, that means we are notified for some new input.
* The console is therefore already locked.
*/
Status = ReadInputBuffer(InputInfo,
GetInputRequest->bRead,
WaitApiMessage,
FALSE);
Quit:
if (Status != STATUS_PENDING)
{
WaitApiMessage->Status = Status;
RtlFreeHeap(ConSrvHeap, 0, InputInfo);
}
return (Status == STATUS_PENDING ? FALSE : TRUE);
}
static NTSTATUS
ReadInputBuffer(IN PGET_INPUT_INFO InputInfo,
IN BOOL Wait, // TRUE --> Read ; FALSE --> Peek
IN PCSR_API_MESSAGE ApiMessage,
IN BOOL CreateWaitBlock OPTIONAL)
{
PCONSOLE_INPUT_BUFFER InputBuffer = InputInfo->InputBuffer;
if (IsListEmpty(&InputBuffer->InputEvents))
{
if (Wait)
{
return WaitBeforeReading(InputInfo,
ApiMessage,
ReadInputBufferThread,
CreateWaitBlock);
}
else
{
/* No input available and we don't wait, so we return success */
return STATUS_SUCCESS;
}
}
else
{
PCONSOLE_GETINPUT GetInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetInputRequest;
PLIST_ENTRY CurrentInput;
ConsoleInput* Input;
ULONG Length = GetInputRequest->Length;
PINPUT_RECORD InputRecord = GetInputRequest->InputRecord;
/* Only get input if there is any */
CurrentInput = InputBuffer->InputEvents.Flink;
while ( CurrentInput != &InputBuffer->InputEvents &&
GetInputRequest->InputsRead < Length )
{
Input = CONTAINING_RECORD(CurrentInput, ConsoleInput, ListEntry);
GetInputRequest->InputsRead++;
*InputRecord = Input->InputEvent;
if (GetInputRequest->Unicode == FALSE)
{
ConioInputEventToAnsi(InputBuffer->Header.Console, InputRecord);
}
InputRecord++;
CurrentInput = CurrentInput->Flink;
if (Wait) // TRUE --> Read, we remove inputs from the buffer ; FALSE --> Peek, we keep inputs.
{
RemoveEntryList(&Input->ListEntry);
RtlFreeHeap(ConSrvHeap, 0, Input);
}
}
if (IsListEmpty(&InputBuffer->InputEvents))
{
ResetEvent(InputBuffer->ActiveEvent);
}
/* We read all the inputs available, we return success */
return STATUS_SUCCESS;
}
}
static NTSTATUS
ReadChars(IN PGET_INPUT_INFO InputInfo,
IN PCSR_API_MESSAGE ApiMessage,
IN BOOL CreateWaitBlock OPTIONAL);
// Wait function CSR_WAIT_FUNCTION
static BOOLEAN
ReadCharsThread(IN PLIST_ENTRY WaitList,
IN PCSR_THREAD WaitThread,
IN PCSR_API_MESSAGE WaitApiMessage,
IN PVOID WaitContext,
IN PVOID WaitArgument1,
IN PVOID WaitArgument2,
IN ULONG WaitFlags)
{
NTSTATUS Status;
PGET_INPUT_INFO InputInfo = (PGET_INPUT_INFO)WaitContext;
PVOID InputHandle = WaitArgument2;
DPRINT("ReadCharsThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags);
/*
* If we are notified of the process termination via a call
* to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
* CsrDestroyThread, just return.
*/
if (WaitFlags & CsrProcessTerminating)
{
Status = STATUS_THREAD_IS_TERMINATING;
goto Quit;
}
/*
* Somebody is closing a handle to this input buffer,
* by calling ConSrvCloseHandleEntry.
* See whether we are linked to that handle (ie. we
* are a waiter for this handle), and if so, return.
* Otherwise, ignore the call and continue waiting.
*/
if (InputHandle != NULL)
{
Status = (InputHandle == InputInfo->HandleEntry ? STATUS_ALERTED
: STATUS_PENDING);
goto Quit;
}
/*
* If we go there, that means we are notified for some new input.
* The console is therefore already locked.
*/
Status = ReadChars(InputInfo,
WaitApiMessage,
FALSE);
Quit:
if (Status != STATUS_PENDING)
{
WaitApiMessage->Status = Status;
RtlFreeHeap(ConSrvHeap, 0, InputInfo);
}
return (Status == STATUS_PENDING ? FALSE : TRUE);
}
static NTSTATUS
ReadChars(IN PGET_INPUT_INFO InputInfo,
IN PCSR_API_MESSAGE ApiMessage,
IN BOOL CreateWaitBlock OPTIONAL)
{
BOOL WaitForMoreToRead = TRUE; // TRUE : Wait if more to read ; FALSE : Don't wait.
PCONSOLE_READCONSOLE ReadConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleRequest;
PCONSOLE_INPUT_BUFFER InputBuffer = InputInfo->InputBuffer;
PCONSOLE Console = InputBuffer->Header.Console;
PLIST_ENTRY CurrentEntry;
ConsoleInput *Input;
PCHAR Buffer = (PCHAR)ReadConsoleRequest->Buffer;
PWCHAR UnicodeBuffer = (PWCHAR)Buffer;
ULONG nNumberOfCharsToRead = ReadConsoleRequest->NrCharactersToRead;
/* We haven't read anything (yet) */
if (InputBuffer->Mode & ENABLE_LINE_INPUT)
{
if (Console->LineBuffer == NULL)
{
/* Starting a new line */
Console->LineMaxSize = (WORD)max(256, nNumberOfCharsToRead);
Console->LineBuffer = RtlAllocateHeap(ConSrvHeap, 0, Console->LineMaxSize * sizeof(WCHAR));
if (Console->LineBuffer == NULL)
{
return STATUS_NO_MEMORY;
}
Console->LineComplete = FALSE;
Console->LineUpPressed = FALSE;
Console->LineInsertToggle = 0;
Console->LineWakeupMask = ReadConsoleRequest->CtrlWakeupMask;
Console->LineSize = ReadConsoleRequest->NrCharactersRead;
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 (KEY_EVENT == Input->InputEvent.EventType
&& Input->InputEvent.Event.KeyEvent.bKeyDown)
{
LineInputKeyDown(Console, &Input->InputEvent.Event.KeyEvent);
ReadConsoleRequest->ControlKeyState = Input->InputEvent.Event.KeyEvent.dwControlKeyState;
}
RtlFreeHeap(ConSrvHeap, 0, Input);
}
/* Check if we have a complete line to read from */
if (Console->LineComplete)
{
while ( ReadConsoleRequest->NrCharactersRead < nNumberOfCharsToRead &&
Console->LinePos != Console->LineSize )
{
WCHAR Char = Console->LineBuffer[Console->LinePos++];
if (ReadConsoleRequest->Unicode)
{
UnicodeBuffer[ReadConsoleRequest->NrCharactersRead] = Char;
}
else
{
ConsoleInputUnicodeCharToAnsiChar(Console,
&Buffer[ReadConsoleRequest->NrCharactersRead],
&Char);
}
ReadConsoleRequest->NrCharactersRead++;
}
if (Console->LinePos == Console->LineSize)
{
/* Entire line has been read */
RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer);
Console->LineBuffer = NULL;
}
WaitForMoreToRead = FALSE;
}
}
else
{
/* Character input */
while ( ReadConsoleRequest->NrCharactersRead < nNumberOfCharsToRead &&
!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 (KEY_EVENT == Input->InputEvent.EventType
&& Input->InputEvent.Event.KeyEvent.bKeyDown
&& Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar != L'\0')
{
WCHAR Char = Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar;
if (ReadConsoleRequest->Unicode)
{
UnicodeBuffer[ReadConsoleRequest->NrCharactersRead] = Char;
}
else
{
ConsoleInputUnicodeCharToAnsiChar(Console,
&Buffer[ReadConsoleRequest->NrCharactersRead],
&Char);
}
ReadConsoleRequest->NrCharactersRead++;
/* Did read something */
WaitForMoreToRead = FALSE;
}
RtlFreeHeap(ConSrvHeap, 0, Input);
}
}
/* We haven't completed a read, so start a wait */
if (WaitForMoreToRead == TRUE)
{
return WaitBeforeReading(InputInfo,
ApiMessage,
ReadCharsThread,
CreateWaitBlock);
}
else /* We read all what we wanted, we return success */
{
return STATUS_SUCCESS;
}
}
/* PUBLIC SERVER APIS *********************************************************/
CSR_API(SrvReadConsole)
{
NTSTATUS Status;
PCONSOLE_READCONSOLE ReadConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PVOID HandleEntry;
PCONSOLE_INPUT_BUFFER InputBuffer;
GET_INPUT_INFO InputInfo;
DPRINT("SrvReadConsole\n");
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&ReadConsoleRequest->Buffer,
ReadConsoleRequest->BufferSize,
sizeof(BYTE)))
{
return STATUS_INVALID_PARAMETER;
}
if (ReadConsoleRequest->NrCharactersRead > ReadConsoleRequest->NrCharactersToRead)
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetInputBufferAndHandleEntry(ProcessData, ReadConsoleRequest->InputHandle, &InputBuffer, &HandleEntry, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
ReadConsoleRequest->NrCharactersRead = 0;
InputInfo.CallingThread = CsrGetClientThread();
InputInfo.HandleEntry = HandleEntry;
InputInfo.InputBuffer = InputBuffer;
Status = ReadChars(&InputInfo,
ApiMessage,
TRUE);
ConSrvReleaseInputBuffer(InputBuffer, TRUE);
if (Status == STATUS_PENDING)
*ReplyCode = CsrReplyPending;
return Status;
}
CSR_API(SrvGetConsoleInput)
{
NTSTATUS Status;
PCONSOLE_GETINPUT GetInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetInputRequest;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PVOID HandleEntry;
PCONSOLE_INPUT_BUFFER InputBuffer;
GET_INPUT_INFO InputInfo;
DPRINT("SrvGetConsoleInput\n");
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&GetInputRequest->InputRecord,
GetInputRequest->Length,
sizeof(INPUT_RECORD)))
{
return STATUS_INVALID_PARAMETER;
}
GetInputRequest->InputsRead = 0;
Status = ConSrvGetInputBufferAndHandleEntry(ProcessData, GetInputRequest->InputHandle, &InputBuffer, &HandleEntry, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
InputInfo.CallingThread = CsrGetClientThread();
InputInfo.HandleEntry = HandleEntry;
InputInfo.InputBuffer = InputBuffer;
Status = ReadInputBuffer(&InputInfo,
GetInputRequest->bRead,
ApiMessage,
TRUE);
ConSrvReleaseInputBuffer(InputBuffer, TRUE);
if (Status == STATUS_PENDING)
*ReplyCode = CsrReplyPending;
return Status;
}
CSR_API(SrvWriteConsoleInput)
{
NTSTATUS Status;
PCONSOLE_WRITEINPUT WriteInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteInputRequest;
PINPUT_RECORD InputRecord;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PCONSOLE_INPUT_BUFFER InputBuffer;
PCONSOLE Console;
DWORD Length;
DWORD i;
DPRINT("SrvWriteConsoleInput\n");
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&WriteInputRequest->InputRecord,
WriteInputRequest->Length,
sizeof(INPUT_RECORD)))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetInputBuffer(ProcessData, WriteInputRequest->InputHandle, &InputBuffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Console = InputBuffer->Header.Console;
InputRecord = WriteInputRequest->InputRecord;
Length = WriteInputRequest->Length;
for (i = 0; i < Length && NT_SUCCESS(Status); i++)
{
if (!WriteInputRequest->Unicode &&
InputRecord->EventType == KEY_EVENT)
{
CHAR AsciiChar = InputRecord->Event.KeyEvent.uChar.AsciiChar;
ConsoleInputAnsiCharToUnicodeChar(Console,
&InputRecord->Event.KeyEvent.uChar.UnicodeChar,
&AsciiChar);
}
Status = ConioProcessInputEvent(Console, InputRecord++);
}
ConSrvReleaseInputBuffer(InputBuffer, TRUE);
WriteInputRequest->Length = i;
return Status;
}
CSR_API(SrvFlushConsoleInputBuffer)
{
NTSTATUS Status;
PCONSOLE_FLUSHINPUTBUFFER FlushInputBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FlushInputBufferRequest;
PLIST_ENTRY CurrentEntry;
PCONSOLE_INPUT_BUFFER InputBuffer;
ConsoleInput* Event;
DPRINT("SrvFlushConsoleInputBuffer\n");
Status = ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
FlushInputBufferRequest->InputHandle,
&InputBuffer,
GENERIC_WRITE,
TRUE);
if (!NT_SUCCESS(Status)) return Status;
/* Discard all entries in the input event queue */
while (!IsListEmpty(&InputBuffer->InputEvents))
{
CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
Event = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
RtlFreeHeap(ConSrvHeap, 0, Event);
}
ResetEvent(InputBuffer->ActiveEvent);
ConSrvReleaseInputBuffer(InputBuffer, TRUE);
return STATUS_SUCCESS;
}
CSR_API(SrvGetConsoleNumberOfInputEvents)
{
NTSTATUS Status;
PCONSOLE_GETNUMINPUTEVENTS GetNumInputEventsRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetNumInputEventsRequest;
PCONSOLE_INPUT_BUFFER InputBuffer;
PLIST_ENTRY CurrentInput;
DWORD NumEvents;
DPRINT("SrvGetConsoleNumberOfInputEvents\n");
Status = ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), GetNumInputEventsRequest->InputHandle, &InputBuffer, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
CurrentInput = InputBuffer->InputEvents.Flink;
/* GetNumInputEventsRequest->NumInputEvents = */ NumEvents = 0;
/* If there are any events ... */
while (CurrentInput != &InputBuffer->InputEvents)
{
CurrentInput = CurrentInput->Flink;
NumEvents++;
}
ConSrvReleaseInputBuffer(InputBuffer, TRUE);
GetNumInputEventsRequest->NumInputEvents = NumEvents;
return STATUS_SUCCESS;
}
/* EOF */