mirror of
https://github.com/reactos/reactos.git
synced 2025-06-12 12:48:40 +00:00
[KERNEL32]
- Simplify IntGetConsoleInput and IntReadConsole. [CONSRV] - Implement event waiting for reading console input buffer with CSR wait blocks. This replaces the event-based waiting which, after being moved from client-side (kernel32) to server-side (see r57721), made all consoles hang when one of them was waiting for new input. TODO: Dereference all the waits in Console->ReadWaitQueue. svn path=/branches/ros-csrss/; revision=57817
This commit is contained in:
parent
80d0bde839
commit
0d59b8df65
5 changed files with 424 additions and 381 deletions
|
@ -57,6 +57,7 @@ IntReadConsole(HANDLE hConsoleInput,
|
||||||
ReadConsoleRequest->BufferSize,
|
ReadConsoleRequest->BufferSize,
|
||||||
(PVOID*)&ReadConsoleRequest->Buffer);
|
(PVOID*)&ReadConsoleRequest->Buffer);
|
||||||
|
|
||||||
|
/* Set up the data to send to the Console Server */
|
||||||
ReadConsoleRequest->ConsoleHandle = hConsoleInput;
|
ReadConsoleRequest->ConsoleHandle = hConsoleInput;
|
||||||
ReadConsoleRequest->Unicode = bUnicode;
|
ReadConsoleRequest->Unicode = bUnicode;
|
||||||
ReadConsoleRequest->NrCharactersToRead = (WORD)nNumberOfCharsToRead;
|
ReadConsoleRequest->NrCharactersToRead = (WORD)nNumberOfCharsToRead;
|
||||||
|
@ -71,31 +72,42 @@ IntReadConsole(HANDLE hConsoleInput,
|
||||||
ReadConsoleRequest->CtrlWakeupMask = pInputControl->dwCtrlWakeupMask;
|
ReadConsoleRequest->CtrlWakeupMask = pInputControl->dwCtrlWakeupMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Call the server */
|
||||||
Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
|
Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
|
||||||
CaptureBuffer,
|
CaptureBuffer,
|
||||||
CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepReadConsole),
|
CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepReadConsole),
|
||||||
sizeof(CSRSS_READ_CONSOLE));
|
sizeof(CSRSS_READ_CONSOLE));
|
||||||
if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = ApiMessage.Status))
|
|
||||||
|
/* Check for success */
|
||||||
|
if (NT_SUCCESS(Status) || NT_SUCCESS(Status = ApiMessage.Status))
|
||||||
|
{
|
||||||
|
memcpy(lpBuffer,
|
||||||
|
ReadConsoleRequest->Buffer,
|
||||||
|
ReadConsoleRequest->NrCharactersRead * CharSize);
|
||||||
|
|
||||||
|
if (lpNumberOfCharsRead != NULL)
|
||||||
|
*lpNumberOfCharsRead = ReadConsoleRequest->NrCharactersRead;
|
||||||
|
|
||||||
|
if (pInputControl && pInputControl->nLength == sizeof(CONSOLE_READCONSOLE_CONTROL))
|
||||||
|
pInputControl->dwControlKeyState = ReadConsoleRequest->ControlKeyState;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
DPRINT1("CSR returned error in ReadConsole\n");
|
DPRINT1("CSR returned error in ReadConsole\n");
|
||||||
CsrFreeCaptureBuffer(CaptureBuffer);
|
|
||||||
BaseSetLastNTError(Status);
|
if (lpNumberOfCharsRead != NULL)
|
||||||
return FALSE;
|
*lpNumberOfCharsRead = 0;
|
||||||
|
|
||||||
|
/* Error out */
|
||||||
|
BaseSetLastNTError(Status /* ApiMessage.Status */);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(lpBuffer,
|
|
||||||
ReadConsoleRequest->Buffer,
|
|
||||||
ReadConsoleRequest->NrCharactersRead * CharSize);
|
|
||||||
|
|
||||||
if (lpNumberOfCharsRead != NULL)
|
|
||||||
*lpNumberOfCharsRead = ReadConsoleRequest->NrCharactersRead;
|
|
||||||
|
|
||||||
if (pInputControl && pInputControl->nLength == sizeof(CONSOLE_READCONSOLE_CONTROL))
|
|
||||||
pInputControl->dwControlKeyState = ReadConsoleRequest->ControlKeyState;
|
|
||||||
|
|
||||||
CsrFreeCaptureBuffer(CaptureBuffer);
|
CsrFreeCaptureBuffer(CaptureBuffer);
|
||||||
|
|
||||||
return TRUE;
|
/* Return TRUE or FALSE */
|
||||||
|
// return TRUE;
|
||||||
|
return (ReadConsoleRequest->NrCharactersRead > 0);
|
||||||
|
// return NT_SUCCESS(ApiMessage.Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,10 +154,7 @@ IntGetConsoleInput(HANDLE hConsoleInput,
|
||||||
GetConsoleInputRequest->ConsoleHandle = hConsoleInput;
|
GetConsoleInputRequest->ConsoleHandle = hConsoleInput;
|
||||||
GetConsoleInputRequest->Unicode = bUnicode;
|
GetConsoleInputRequest->Unicode = bUnicode;
|
||||||
GetConsoleInputRequest->bRead = bRead;
|
GetConsoleInputRequest->bRead = bRead;
|
||||||
if (bRead == TRUE)
|
GetConsoleInputRequest->InputsRead = 0;
|
||||||
{
|
|
||||||
GetConsoleInputRequest->InputsRead = 0;
|
|
||||||
}
|
|
||||||
GetConsoleInputRequest->Length = nLength;
|
GetConsoleInputRequest->Length = nLength;
|
||||||
|
|
||||||
/* Call the server */
|
/* Call the server */
|
||||||
|
@ -155,9 +164,30 @@ IntGetConsoleInput(HANDLE hConsoleInput,
|
||||||
sizeof(CSRSS_GET_CONSOLE_INPUT));
|
sizeof(CSRSS_GET_CONSOLE_INPUT));
|
||||||
DPRINT("Server returned: %x\n", ApiMessage.Status);
|
DPRINT("Server returned: %x\n", ApiMessage.Status);
|
||||||
|
|
||||||
/** For Read only **
|
/* Check for success */
|
||||||
if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = ApiMessage.Status))
|
if (NT_SUCCESS(Status) || NT_SUCCESS(Status = ApiMessage.Status))
|
||||||
{
|
{
|
||||||
|
/* Return the number of events read */
|
||||||
|
DPRINT("Events read: %lx\n", GetConsoleInputRequest->InputsRead);
|
||||||
|
|
||||||
|
if (lpNumberOfEventsRead != NULL)
|
||||||
|
*lpNumberOfEventsRead = GetConsoleInputRequest->InputsRead;
|
||||||
|
|
||||||
|
/* Copy into the buffer */
|
||||||
|
DPRINT("Copying to buffer\n");
|
||||||
|
RtlCopyMemory(lpBuffer,
|
||||||
|
GetConsoleInputRequest->InputRecord,
|
||||||
|
sizeof(INPUT_RECORD) * GetConsoleInputRequest->InputsRead);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (lpNumberOfEventsRead != NULL)
|
||||||
|
*lpNumberOfEventsRead = 0;
|
||||||
|
|
||||||
|
/* Error out */
|
||||||
|
BaseSetLastNTError(ApiMessage.Status);
|
||||||
|
|
||||||
|
/*********
|
||||||
// BaseSetLastNTError(Status); ????
|
// BaseSetLastNTError(Status); ????
|
||||||
if (GetConsoleInputRequest->InputsRead == 0)
|
if (GetConsoleInputRequest->InputsRead == 0)
|
||||||
{
|
{
|
||||||
|
@ -170,75 +200,15 @@ IntGetConsoleInput(HANDLE hConsoleInput,
|
||||||
/\* FIXME - fail gracefully in case we already read at least one record? *\/
|
/\* FIXME - fail gracefully in case we already read at least one record? *\/
|
||||||
// break;
|
// break;
|
||||||
}
|
}
|
||||||
|
*********/
|
||||||
}
|
}
|
||||||
**/
|
|
||||||
|
|
||||||
/**
|
/* Release the capture buffer */
|
||||||
** TODO: !! Simplify the function !!
|
CsrFreeCaptureBuffer(CaptureBuffer);
|
||||||
**/
|
|
||||||
if (bRead == TRUE) // ReadConsoleInput call.
|
|
||||||
{
|
|
||||||
/* Check for success */
|
|
||||||
if (NT_SUCCESS(Status) || NT_SUCCESS(Status = ApiMessage.Status))
|
|
||||||
{
|
|
||||||
/* Return the number of events read */
|
|
||||||
DPRINT("Events read: %lx\n", GetConsoleInputRequest->InputsRead/*Length*/);
|
|
||||||
|
|
||||||
if (lpNumberOfEventsRead != NULL)
|
/* Return TRUE or FALSE */
|
||||||
*lpNumberOfEventsRead = GetConsoleInputRequest->InputsRead/*Length*/;
|
return (GetConsoleInputRequest->InputsRead > 0);
|
||||||
|
// return NT_SUCCESS(ApiMessage.Status);
|
||||||
/* Copy into the buffer */
|
|
||||||
DPRINT("Copying to buffer\n");
|
|
||||||
RtlCopyMemory(lpBuffer,
|
|
||||||
GetConsoleInputRequest->InputRecord,
|
|
||||||
sizeof(INPUT_RECORD) * GetConsoleInputRequest->InputsRead/*Length*/);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (lpNumberOfEventsRead != NULL)
|
|
||||||
*lpNumberOfEventsRead = 0;
|
|
||||||
|
|
||||||
/* Error out */
|
|
||||||
BaseSetLastNTError(ApiMessage.Status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Release the capture buffer */
|
|
||||||
CsrFreeCaptureBuffer(CaptureBuffer);
|
|
||||||
|
|
||||||
return (GetConsoleInputRequest->InputsRead > 0);
|
|
||||||
}
|
|
||||||
else // PeekConsoleInput call.
|
|
||||||
{
|
|
||||||
/* Check for success */
|
|
||||||
if (NT_SUCCESS(Status) || NT_SUCCESS(ApiMessage.Status))
|
|
||||||
{
|
|
||||||
/* Return the number of events read */
|
|
||||||
DPRINT("Events read: %lx\n", GetConsoleInputRequest->Length);
|
|
||||||
|
|
||||||
if (lpNumberOfEventsRead != NULL)
|
|
||||||
*lpNumberOfEventsRead = GetConsoleInputRequest->Length;
|
|
||||||
|
|
||||||
/* Copy into the buffer */
|
|
||||||
DPRINT("Copying to buffer\n");
|
|
||||||
RtlCopyMemory(lpBuffer,
|
|
||||||
GetConsoleInputRequest->InputRecord,
|
|
||||||
sizeof(INPUT_RECORD) * GetConsoleInputRequest->Length);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (lpNumberOfEventsRead != NULL)
|
|
||||||
*lpNumberOfEventsRead = 0;
|
|
||||||
|
|
||||||
/* Error out */
|
|
||||||
BaseSetLastNTError(ApiMessage.Status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Release the capture buffer */
|
|
||||||
CsrFreeCaptureBuffer(CaptureBuffer);
|
|
||||||
|
|
||||||
/* Return TRUE or FALSE */
|
|
||||||
return NT_SUCCESS(ApiMessage.Status);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,6 @@ typedef struct
|
||||||
BOOL Unicode;
|
BOOL Unicode;
|
||||||
WORD NrCharactersToRead;
|
WORD NrCharactersToRead;
|
||||||
WORD NrCharactersRead;
|
WORD NrCharactersRead;
|
||||||
HANDLE EventHandle;
|
|
||||||
|
|
||||||
UNICODE_STRING ExeName;
|
UNICODE_STRING ExeName;
|
||||||
DWORD CtrlWakeupMask;
|
DWORD CtrlWakeupMask;
|
||||||
|
@ -326,14 +325,10 @@ typedef struct
|
||||||
BOOL Unicode;
|
BOOL Unicode;
|
||||||
BOOL bRead; // TRUE --> Read ; FALSE --> Peek
|
BOOL bRead; // TRUE --> Read ; FALSE --> Peek
|
||||||
|
|
||||||
DWORD Length;
|
|
||||||
INPUT_RECORD* InputRecord;
|
|
||||||
|
|
||||||
/** For Read **/
|
|
||||||
ULONG InputsRead;
|
ULONG InputsRead;
|
||||||
// INPUT_RECORD Input;
|
|
||||||
BOOL MoreEvents;
|
ULONG Length;
|
||||||
HANDLE Event;
|
PINPUT_RECORD InputRecord;
|
||||||
} CSRSS_GET_CONSOLE_INPUT, *PCSRSS_GET_CONSOLE_INPUT;
|
} CSRSS_GET_CONSOLE_INPUT, *PCSRSS_GET_CONSOLE_INPUT;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|
|
@ -25,6 +25,13 @@
|
||||||
MultiByteToWideChar((Console)->CodePage, 0, (sChar), 1, (dWChar), 1)
|
MultiByteToWideChar((Console)->CodePage, 0, (sChar), 1, (dWChar), 1)
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _GET_INPUT_INFO
|
||||||
|
{
|
||||||
|
PCONSOLE_PROCESS_DATA ProcessData;
|
||||||
|
PCSRSS_CONSOLE Console;
|
||||||
|
} GET_INPUT_INFO, *PGET_INPUT_INFO;
|
||||||
|
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS **********************************************************/
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
static VOID FASTCALL
|
static VOID FASTCALL
|
||||||
|
@ -79,7 +86,13 @@ ConioProcessChar(PCSRSS_CONSOLE Console,
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
ConInRec->InputEvent = *InputEvent;
|
ConInRec->InputEvent = *InputEvent;
|
||||||
InsertTailList(&Console->InputEvents, &ConInRec->ListEntry);
|
InsertTailList(&Console->InputEvents, &ConInRec->ListEntry);
|
||||||
|
|
||||||
SetEvent(Console->ActiveEvent);
|
SetEvent(Console->ActiveEvent);
|
||||||
|
CsrNotifyWait(&Console->ReadWaitQueue,
|
||||||
|
WaitAny,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,6 +302,322 @@ ConioProcessKey(MSG *msg, PCSRSS_CONSOLE Console, BOOL TextMode)
|
||||||
ConioProcessChar(Console, &er);
|
ConioProcessChar(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 = HeapAlloc(ConSrvHeap, 0, sizeof(GET_INPUT_INFO));
|
||||||
|
if (!CapturedInputInfo) return STATUS_NO_MEMORY;
|
||||||
|
|
||||||
|
memmove(CapturedInputInfo, InputInfo, sizeof(GET_INPUT_INFO));
|
||||||
|
|
||||||
|
if (!CsrCreateWait(&InputInfo->Console->ReadWaitQueue,
|
||||||
|
WaitFunction,
|
||||||
|
CsrGetClientThread(),
|
||||||
|
ApiMessage,
|
||||||
|
CapturedInputInfo,
|
||||||
|
NULL))
|
||||||
|
{
|
||||||
|
HeapFree(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;
|
||||||
|
PCSRSS_GET_CONSOLE_INPUT GetConsoleInputRequest = &((PCONSOLE_API_MESSAGE)WaitApiMessage)->Data.GetConsoleInputRequest;
|
||||||
|
PGET_INPUT_INFO InputInfo = (PGET_INPUT_INFO)WaitContext;
|
||||||
|
|
||||||
|
Status = ReadInputBuffer(InputInfo,
|
||||||
|
GetConsoleInputRequest->bRead,
|
||||||
|
WaitApiMessage,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
if (Status != STATUS_PENDING)
|
||||||
|
{
|
||||||
|
WaitApiMessage->Status = Status;
|
||||||
|
HeapFree(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)
|
||||||
|
{
|
||||||
|
if (IsListEmpty(&InputInfo->Console->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
|
||||||
|
{
|
||||||
|
PCSRSS_GET_CONSOLE_INPUT GetConsoleInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleInputRequest;
|
||||||
|
PLIST_ENTRY CurrentInput;
|
||||||
|
ConsoleInput* Input;
|
||||||
|
ULONG Length = GetConsoleInputRequest->Length;
|
||||||
|
PINPUT_RECORD InputRecord = GetConsoleInputRequest->InputRecord;
|
||||||
|
|
||||||
|
/* Only get input if there is any */
|
||||||
|
CurrentInput = InputInfo->Console->InputEvents.Flink;
|
||||||
|
|
||||||
|
while ( CurrentInput != &InputInfo->Console->InputEvents &&
|
||||||
|
GetConsoleInputRequest->InputsRead < Length )
|
||||||
|
{
|
||||||
|
Input = CONTAINING_RECORD(CurrentInput, ConsoleInput, ListEntry);
|
||||||
|
|
||||||
|
GetConsoleInputRequest->InputsRead++;
|
||||||
|
*InputRecord = Input->InputEvent;
|
||||||
|
|
||||||
|
if (GetConsoleInputRequest->Unicode == FALSE)
|
||||||
|
{
|
||||||
|
ConioInputEventToAnsi(InputInfo->Console, InputRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputRecord++;
|
||||||
|
CurrentInput = CurrentInput->Flink;
|
||||||
|
|
||||||
|
if (Wait) // TRUE --> Read, we remove inputs from the buffer ; FALSE --> Peek, we keep inputs.
|
||||||
|
{
|
||||||
|
RemoveEntryList(&Input->ListEntry);
|
||||||
|
HeapFree(ConSrvHeap, 0, Input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsListEmpty(&InputInfo->Console->InputEvents))
|
||||||
|
{
|
||||||
|
ResetEvent(InputInfo->Console->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;
|
||||||
|
|
||||||
|
Status = ReadChars(InputInfo,
|
||||||
|
WaitApiMessage,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
if (Status != STATUS_PENDING)
|
||||||
|
{
|
||||||
|
WaitApiMessage->Status = Status;
|
||||||
|
HeapFree(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.
|
||||||
|
|
||||||
|
PCSRSS_READ_CONSOLE ReadConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleRequest;
|
||||||
|
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 (InputInfo->Console->Mode & ENABLE_LINE_INPUT)
|
||||||
|
{
|
||||||
|
if (InputInfo->Console->LineBuffer == NULL)
|
||||||
|
{
|
||||||
|
/* Starting a new line */
|
||||||
|
InputInfo->Console->LineMaxSize = max(256, nNumberOfCharsToRead);
|
||||||
|
InputInfo->Console->LineBuffer = HeapAlloc(ConSrvHeap, 0, InputInfo->Console->LineMaxSize * sizeof(WCHAR));
|
||||||
|
if (InputInfo->Console->LineBuffer == NULL)
|
||||||
|
{
|
||||||
|
return STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
InputInfo->Console->LineComplete = FALSE;
|
||||||
|
InputInfo->Console->LineUpPressed = FALSE;
|
||||||
|
InputInfo->Console->LineInsertToggle = 0;
|
||||||
|
InputInfo->Console->LineWakeupMask = ReadConsoleRequest->CtrlWakeupMask;
|
||||||
|
InputInfo->Console->LineSize = ReadConsoleRequest->NrCharactersRead;
|
||||||
|
InputInfo->Console->LinePos = InputInfo->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(InputInfo->Console->LineBuffer, Buffer, InputInfo->Console->LineSize * sizeof(WCHAR));
|
||||||
|
if (InputInfo->Console->LineSize == InputInfo->Console->LineMaxSize)
|
||||||
|
{
|
||||||
|
InputInfo->Console->LineComplete = TRUE;
|
||||||
|
InputInfo->Console->LinePos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we don't have a complete line yet, process the pending input */
|
||||||
|
while ( !InputInfo->Console->LineComplete &&
|
||||||
|
!IsListEmpty(&InputInfo->Console->InputEvents) )
|
||||||
|
{
|
||||||
|
/* Remove input event from queue */
|
||||||
|
CurrentEntry = RemoveHeadList(&InputInfo->Console->InputEvents);
|
||||||
|
if (IsListEmpty(&InputInfo->Console->InputEvents))
|
||||||
|
{
|
||||||
|
ResetEvent(InputInfo->Console->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(InputInfo->Console, &Input->InputEvent.Event.KeyEvent);
|
||||||
|
ReadConsoleRequest->ControlKeyState = Input->InputEvent.Event.KeyEvent.dwControlKeyState;
|
||||||
|
}
|
||||||
|
HeapFree(ConSrvHeap, 0, Input);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we have a complete line to read from */
|
||||||
|
if (InputInfo->Console->LineComplete)
|
||||||
|
{
|
||||||
|
while ( ReadConsoleRequest->NrCharactersRead < nNumberOfCharsToRead &&
|
||||||
|
InputInfo->Console->LinePos != InputInfo->Console->LineSize )
|
||||||
|
{
|
||||||
|
WCHAR Char = InputInfo->Console->LineBuffer[InputInfo->Console->LinePos++];
|
||||||
|
|
||||||
|
if (ReadConsoleRequest->Unicode)
|
||||||
|
{
|
||||||
|
UnicodeBuffer[ReadConsoleRequest->NrCharactersRead] = Char;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ConsoleInputUnicodeCharToAnsiChar(InputInfo->Console,
|
||||||
|
&Buffer[ReadConsoleRequest->NrCharactersRead],
|
||||||
|
&Char);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadConsoleRequest->NrCharactersRead++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InputInfo->Console->LinePos == InputInfo->Console->LineSize)
|
||||||
|
{
|
||||||
|
/* Entire line has been read */
|
||||||
|
HeapFree(ConSrvHeap, 0, InputInfo->Console->LineBuffer);
|
||||||
|
InputInfo->Console->LineBuffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitForMoreToRead = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Character input */
|
||||||
|
while ( ReadConsoleRequest->NrCharactersRead < nNumberOfCharsToRead &&
|
||||||
|
!IsListEmpty(&InputInfo->Console->InputEvents) )
|
||||||
|
{
|
||||||
|
/* Remove input event from queue */
|
||||||
|
CurrentEntry = RemoveHeadList(&InputInfo->Console->InputEvents);
|
||||||
|
if (IsListEmpty(&InputInfo->Console->InputEvents))
|
||||||
|
{
|
||||||
|
ResetEvent(InputInfo->Console->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(InputInfo->Console,
|
||||||
|
&Buffer[ReadConsoleRequest->NrCharactersRead],
|
||||||
|
&Char);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadConsoleRequest->NrCharactersRead++;
|
||||||
|
|
||||||
|
/* Did read something */
|
||||||
|
WaitForMoreToRead = FALSE;
|
||||||
|
}
|
||||||
|
HeapFree(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 APIS ****************************************************************/
|
/* PUBLIC APIS ****************************************************************/
|
||||||
|
|
||||||
|
@ -298,17 +627,10 @@ CSR_API(SrvGetConsoleInput)
|
||||||
PCSRSS_GET_CONSOLE_INPUT GetConsoleInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleInputRequest;
|
PCSRSS_GET_CONSOLE_INPUT GetConsoleInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleInputRequest;
|
||||||
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
|
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
|
||||||
PCSRSS_CONSOLE Console;
|
PCSRSS_CONSOLE Console;
|
||||||
PLIST_ENTRY CurrentInput;
|
GET_INPUT_INFO InputInfo;
|
||||||
ConsoleInput* Input;
|
|
||||||
|
|
||||||
DWORD Length;
|
|
||||||
PINPUT_RECORD InputRecord;
|
|
||||||
|
|
||||||
DPRINT("SrvGetConsoleInput\n");
|
DPRINT("SrvGetConsoleInput\n");
|
||||||
|
|
||||||
Status = ConioLockConsole(ProcessData, GetConsoleInputRequest->ConsoleHandle, &Console, GENERIC_READ);
|
|
||||||
if(!NT_SUCCESS(Status)) return Status;
|
|
||||||
|
|
||||||
if (!CsrValidateMessageBuffer(ApiMessage,
|
if (!CsrValidateMessageBuffer(ApiMessage,
|
||||||
(PVOID*)&GetConsoleInputRequest->InputRecord,
|
(PVOID*)&GetConsoleInputRequest->InputRecord,
|
||||||
GetConsoleInputRequest->Length,
|
GetConsoleInputRequest->Length,
|
||||||
|
@ -317,131 +639,24 @@ CSR_API(SrvGetConsoleInput)
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputRecord = GetConsoleInputRequest->InputRecord;
|
Status = ConioLockConsole(ProcessData, GetConsoleInputRequest->ConsoleHandle, &Console, GENERIC_READ);
|
||||||
Length = GetConsoleInputRequest->Length;
|
if(!NT_SUCCESS(Status)) return Status;
|
||||||
|
|
||||||
/*
|
GetConsoleInputRequest->InputsRead = 0;
|
||||||
if (!Win32CsrValidateBuffer(ProcessData->Process, InputRecord, Length, sizeof(INPUT_RECORD)))
|
|
||||||
{
|
|
||||||
ConioUnlockConsole(Console);
|
|
||||||
return STATUS_ACCESS_VIOLATION;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (GetConsoleInputRequest->bRead) // Read input.
|
InputInfo.ProcessData = ProcessData; // ConsoleGetPerProcessData(CsrGetClientThread()->Process);
|
||||||
{
|
InputInfo.Console = Console;
|
||||||
GetConsoleInputRequest->Event = ProcessData->ConsoleEvent;
|
|
||||||
|
|
||||||
while (Length > 0)
|
Status = ReadInputBuffer(&InputInfo,
|
||||||
{
|
GetConsoleInputRequest->bRead,
|
||||||
BOOLEAN Done = FALSE;
|
ApiMessage,
|
||||||
|
TRUE);
|
||||||
// GetConsoleInputRequest->Event = ProcessData->ConsoleEvent;
|
|
||||||
|
|
||||||
/* only get input if there is any */
|
|
||||||
CurrentInput = Console->InputEvents.Flink;
|
|
||||||
while (CurrentInput != &Console->InputEvents)
|
|
||||||
{
|
|
||||||
Input = CONTAINING_RECORD(CurrentInput, ConsoleInput, ListEntry);
|
|
||||||
CurrentInput = CurrentInput->Flink;
|
|
||||||
|
|
||||||
if (Done)
|
|
||||||
{
|
|
||||||
GetConsoleInputRequest->MoreEvents = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoveEntryList(&Input->ListEntry);
|
|
||||||
|
|
||||||
if (!Done)
|
|
||||||
{
|
|
||||||
GetConsoleInputRequest->InputsRead++;
|
|
||||||
*InputRecord = Input->InputEvent;
|
|
||||||
/* HACK */ Length--;
|
|
||||||
|
|
||||||
// GetConsoleInputRequest->Input = Input->InputEvent;
|
|
||||||
if (GetConsoleInputRequest->Unicode == FALSE)
|
|
||||||
{
|
|
||||||
// ConioInputEventToAnsi(Console, &GetConsoleInputRequest->Input);
|
|
||||||
ConioInputEventToAnsi(Console, InputRecord);
|
|
||||||
}
|
|
||||||
|
|
||||||
InputRecord++;
|
|
||||||
Done = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
HeapFree(ConSrvHeap, 0, Input);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Done)
|
|
||||||
Status = STATUS_SUCCESS;
|
|
||||||
else
|
|
||||||
Status = STATUS_PENDING;
|
|
||||||
|
|
||||||
if (IsListEmpty(&Console->InputEvents))
|
|
||||||
{
|
|
||||||
ResetEvent(Console->ActiveEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Status == STATUS_PENDING)
|
|
||||||
{
|
|
||||||
if (GetConsoleInputRequest->InputsRead == 0)
|
|
||||||
{
|
|
||||||
Status = NtWaitForSingleObject(GetConsoleInputRequest->Event, FALSE, 0);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
// BaseSetLastNTError(Status);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* nothing more to read (waiting for more input??), let's just bail */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // Status != STATUS_PENDING ; == STATUS_SUCCESS
|
|
||||||
{
|
|
||||||
if (!GetConsoleInputRequest->MoreEvents)
|
|
||||||
{
|
|
||||||
/* nothing more to read, bail */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // Peek input.
|
|
||||||
{
|
|
||||||
UINT NumInputs = 0;
|
|
||||||
|
|
||||||
if (!IsListEmpty(&Console->InputEvents))
|
|
||||||
{
|
|
||||||
CurrentInput = Console->InputEvents.Flink;
|
|
||||||
|
|
||||||
while (CurrentInput != &Console->InputEvents && NumInputs < Length)
|
|
||||||
{
|
|
||||||
Input = CONTAINING_RECORD(CurrentInput, ConsoleInput, ListEntry);
|
|
||||||
|
|
||||||
++NumInputs;
|
|
||||||
*InputRecord = Input->InputEvent;
|
|
||||||
|
|
||||||
if (GetConsoleInputRequest->Unicode == FALSE)
|
|
||||||
{
|
|
||||||
ConioInputEventToAnsi(Console, InputRecord);
|
|
||||||
}
|
|
||||||
|
|
||||||
InputRecord++;
|
|
||||||
CurrentInput = CurrentInput->Flink;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GetConsoleInputRequest->Length = NumInputs;
|
|
||||||
|
|
||||||
Status = STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConioUnlockConsole(Console);
|
ConioUnlockConsole(Console);
|
||||||
|
|
||||||
|
if (Status == STATUS_PENDING)
|
||||||
|
*ReplyCode = CsrReplyPending;
|
||||||
|
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,14 +686,6 @@ CSR_API(SrvWriteConsoleInput)
|
||||||
InputRecord = WriteConsoleInputRequest->InputRecord;
|
InputRecord = WriteConsoleInputRequest->InputRecord;
|
||||||
Length = WriteConsoleInputRequest->Length;
|
Length = WriteConsoleInputRequest->Length;
|
||||||
|
|
||||||
/*
|
|
||||||
if (!Win32CsrValidateBuffer(ProcessData->Process, InputRecord, Length, sizeof(INPUT_RECORD)))
|
|
||||||
{
|
|
||||||
ConioUnlockConsole(Console);
|
|
||||||
return STATUS_ACCESS_VIOLATION;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
for (i = 0; i < Length && NT_SUCCESS(Status); i++)
|
for (i = 0; i < Length && NT_SUCCESS(Status); i++)
|
||||||
{
|
{
|
||||||
if (!WriteConsoleInputRequest->Unicode &&
|
if (!WriteConsoleInputRequest->Unicode &&
|
||||||
|
@ -504,21 +711,12 @@ CSR_API(SrvReadConsole)
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
PCSRSS_READ_CONSOLE ReadConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleRequest;
|
PCSRSS_READ_CONSOLE ReadConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleRequest;
|
||||||
PLIST_ENTRY CurrentEntry;
|
|
||||||
ConsoleInput *Input;
|
|
||||||
PCHAR Buffer;
|
|
||||||
PWCHAR UnicodeBuffer;
|
|
||||||
ULONG i = 0;
|
|
||||||
ULONG nNumberOfCharsToRead, CharSize;
|
|
||||||
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
|
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
|
||||||
PCSRSS_CONSOLE Console;
|
PCSRSS_CONSOLE Console;
|
||||||
|
GET_INPUT_INFO InputInfo;
|
||||||
|
|
||||||
DPRINT("SrvReadConsole\n");
|
DPRINT("SrvReadConsole\n");
|
||||||
|
|
||||||
CharSize = (ReadConsoleRequest->Unicode ? sizeof(WCHAR) : sizeof(CHAR));
|
|
||||||
|
|
||||||
nNumberOfCharsToRead = ReadConsoleRequest->NrCharactersToRead;
|
|
||||||
|
|
||||||
if (!CsrValidateMessageBuffer(ApiMessage,
|
if (!CsrValidateMessageBuffer(ApiMessage,
|
||||||
(PVOID*)&ReadConsoleRequest->Buffer,
|
(PVOID*)&ReadConsoleRequest->Buffer,
|
||||||
ReadConsoleRequest->BufferSize,
|
ReadConsoleRequest->BufferSize,
|
||||||
|
@ -527,155 +725,29 @@ CSR_API(SrvReadConsole)
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer = (PCHAR)ReadConsoleRequest->Buffer;
|
// if (Request->Data.ReadConsoleRequest.NrCharactersRead * sizeof(WCHAR) > nNumberOfCharsToRead * CharSize)
|
||||||
UnicodeBuffer = (PWCHAR)Buffer;
|
if (ReadConsoleRequest->NrCharactersRead > ReadConsoleRequest->NrCharactersToRead)
|
||||||
|
{
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
Status = ConioLockConsole(ProcessData, ReadConsoleRequest->ConsoleHandle, &Console, GENERIC_READ);
|
||||||
if (!Win32CsrValidateBuffer(ProcessData->Process, Buffer, nNumberOfCharsToRead, CharSize))
|
|
||||||
return STATUS_ACCESS_VIOLATION;
|
|
||||||
*/
|
|
||||||
|
|
||||||
Status = ConioLockConsole(ProcessData, ReadConsoleRequest->ConsoleHandle,
|
|
||||||
&Console, GENERIC_READ);
|
|
||||||
if (!NT_SUCCESS(Status)) return Status;
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
|
|
||||||
Status = STATUS_SUCCESS;
|
ReadConsoleRequest->NrCharactersRead = 0;
|
||||||
ReadConsoleRequest->EventHandle = ProcessData->ConsoleEvent;
|
|
||||||
|
|
||||||
/*** HACK: Enclosing do { ... } while (...) loop coming from kernel32 ***/
|
InputInfo.ProcessData = ProcessData; // ConsoleGetPerProcessData(CsrGetClientThread()->Process);
|
||||||
do
|
InputInfo.Console = Console;
|
||||||
{
|
|
||||||
if (Status == STATUS_PENDING)
|
|
||||||
{
|
|
||||||
Status = NtWaitForSingleObject(ReadConsoleRequest->EventHandle,
|
|
||||||
FALSE,
|
|
||||||
0);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT1("Wait for console input failed!\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/******/
|
|
||||||
|
|
||||||
if (ReadConsoleRequest->NrCharactersRead * sizeof(WCHAR) > nNumberOfCharsToRead * CharSize)
|
Status = ReadChars(&InputInfo,
|
||||||
{
|
ApiMessage,
|
||||||
// return STATUS_INVALID_PARAMETER;
|
TRUE);
|
||||||
Status = STATUS_INVALID_PARAMETER;
|
|
||||||
break;
|
|
||||||
// goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadConsoleRequest->EventHandle = ProcessData->ConsoleEvent;
|
|
||||||
|
|
||||||
Status = STATUS_PENDING; /* we haven't read anything (yet) */
|
|
||||||
if (Console->Mode & ENABLE_LINE_INPUT)
|
|
||||||
{
|
|
||||||
if (Console->LineBuffer == NULL)
|
|
||||||
{
|
|
||||||
/* Starting a new line */
|
|
||||||
Console->LineMaxSize = max(256, nNumberOfCharsToRead);
|
|
||||||
Console->LineBuffer = HeapAlloc(ConSrvHeap, 0, Console->LineMaxSize * sizeof(WCHAR));
|
|
||||||
if (Console->LineBuffer == NULL)
|
|
||||||
{
|
|
||||||
Status = STATUS_NO_MEMORY;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
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 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(&Console->InputEvents))
|
|
||||||
{
|
|
||||||
/* remove input event from queue */
|
|
||||||
CurrentEntry = RemoveHeadList(&Console->InputEvents);
|
|
||||||
if (IsListEmpty(&Console->InputEvents))
|
|
||||||
{
|
|
||||||
ResetEvent(Console->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;
|
|
||||||
}
|
|
||||||
HeapFree(ConSrvHeap, 0, Input);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if we have a complete line to read from */
|
|
||||||
if (Console->LineComplete)
|
|
||||||
{
|
|
||||||
while (i < nNumberOfCharsToRead && Console->LinePos != Console->LineSize)
|
|
||||||
{
|
|
||||||
WCHAR Char = Console->LineBuffer[Console->LinePos++];
|
|
||||||
if (ReadConsoleRequest->Unicode)
|
|
||||||
UnicodeBuffer[i++] = Char;
|
|
||||||
else
|
|
||||||
ConsoleInputUnicodeCharToAnsiChar(Console, &Buffer[i++], &Char);
|
|
||||||
}
|
|
||||||
if (Console->LinePos == Console->LineSize)
|
|
||||||
{
|
|
||||||
/* Entire line has been read */
|
|
||||||
HeapFree(ConSrvHeap, 0, Console->LineBuffer);
|
|
||||||
Console->LineBuffer = NULL;
|
|
||||||
}
|
|
||||||
Status = STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Character input */
|
|
||||||
while (i < nNumberOfCharsToRead && !IsListEmpty(&Console->InputEvents))
|
|
||||||
{
|
|
||||||
/* remove input event from queue */
|
|
||||||
CurrentEntry = RemoveHeadList(&Console->InputEvents);
|
|
||||||
if (IsListEmpty(&Console->InputEvents))
|
|
||||||
{
|
|
||||||
ResetEvent(Console->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[i++] = Char;
|
|
||||||
else
|
|
||||||
ConsoleInputUnicodeCharToAnsiChar(Console, &Buffer[i++], &Char);
|
|
||||||
Status = STATUS_SUCCESS; /* did read something */
|
|
||||||
}
|
|
||||||
HeapFree(ConSrvHeap, 0, Input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
done:
|
|
||||||
ReadConsoleRequest->NrCharactersRead = i;
|
|
||||||
|
|
||||||
/******/
|
|
||||||
}
|
|
||||||
while (Status == STATUS_PENDING);
|
|
||||||
/*** HACK: Enclosing do { ... } while (...) loop coming from kernel32 ***/
|
|
||||||
|
|
||||||
ConioUnlockConsole(Console);
|
ConioUnlockConsole(Console);
|
||||||
|
|
||||||
|
if (Status == STATUS_PENDING)
|
||||||
|
*ReplyCode = CsrReplyPending;
|
||||||
|
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,9 @@ typedef struct tagCSRSS_CONSOLE
|
||||||
CRITICAL_SECTION Lock;
|
CRITICAL_SECTION Lock;
|
||||||
struct tagCSRSS_CONSOLE *Prev, *Next; /* Next and Prev consoles in console wheel */
|
struct tagCSRSS_CONSOLE *Prev, *Next; /* Next and Prev consoles in console wheel */
|
||||||
HANDLE ActiveEvent;
|
HANDLE ActiveEvent;
|
||||||
|
|
||||||
|
LIST_ENTRY ReadWaitQueue; /* List head for the queue of read wait blocks */
|
||||||
|
|
||||||
LIST_ENTRY InputEvents; /* List head for input event queue */
|
LIST_ENTRY InputEvents; /* List head for input event queue */
|
||||||
PWCHAR LineBuffer; /* current line being input, in line buffered mode */
|
PWCHAR LineBuffer; /* current line being input, in line buffered mode */
|
||||||
WORD LineMaxSize; /* maximum size of line in characters (including CR+LF) */
|
WORD LineMaxSize; /* maximum size of line in characters (including CR+LF) */
|
||||||
|
|
|
@ -114,6 +114,7 @@ CsrInitConsole(PCSRSS_CONSOLE Console, int ShowCmd)
|
||||||
Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
|
Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
|
||||||
InitializeListHead(&Console->BufferList);
|
InitializeListHead(&Console->BufferList);
|
||||||
Console->ActiveBuffer = NULL;
|
Console->ActiveBuffer = NULL;
|
||||||
|
InitializeListHead(&Console->ReadWaitQueue);
|
||||||
InitializeListHead(&Console->InputEvents);
|
InitializeListHead(&Console->InputEvents);
|
||||||
InitializeListHead(&Console->HistoryBuffers);
|
InitializeListHead(&Console->HistoryBuffers);
|
||||||
Console->CodePage = GetOEMCP();
|
Console->CodePage = GetOEMCP();
|
||||||
|
@ -424,6 +425,8 @@ ConioDeleteConsole(Object_t *Object)
|
||||||
|
|
||||||
DPRINT("ConioDeleteConsole\n");
|
DPRINT("ConioDeleteConsole\n");
|
||||||
|
|
||||||
|
/* TODO: Dereference all the waits in Console->ReadWaitQueue */
|
||||||
|
|
||||||
/* Drain input event queue */
|
/* Drain input event queue */
|
||||||
while (Console->InputEvents.Flink != &Console->InputEvents)
|
while (Console->InputEvents.Flink != &Console->InputEvents)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue