[KERNEL32]

Remove a spurious cast, and add a note for the pInputControl parameter of ReadConsole.

[CONSRV]
- Move some input/output console function helpers to condrv.
- The way we notify for the presence of new input data, or for console pausing/unpausing, should be reconsidered (who should do this? The console driver? The active front-end?)

svn path=/trunk/; revision=59345
This commit is contained in:
Hermès Bélusca-Maïto 2013-06-27 00:20:58 +00:00
parent 9f8ca2b24b
commit 98b3cac350
6 changed files with 475 additions and 382 deletions

View file

@ -60,11 +60,17 @@ IntReadConsole(HANDLE hConsoleInput,
/* Set up the data to send to the Console Server */
ReadConsoleRequest->InputHandle = hConsoleInput;
ReadConsoleRequest->Unicode = bUnicode;
ReadConsoleRequest->NrCharactersToRead = (WORD)nNumberOfCharsToRead;
ReadConsoleRequest->NrCharactersToRead = nNumberOfCharsToRead;
ReadConsoleRequest->NrCharactersRead = 0;
ReadConsoleRequest->CtrlWakeupMask = 0;
if (pInputControl && pInputControl->nLength == sizeof(CONSOLE_READCONSOLE_CONTROL))
{
/*
* From MSDN (ReadConsole function), the description
* for pInputControl says:
* "This parameter requires Unicode input by default.
* For ANSI mode, set this parameter to NULL."
*/
ReadConsoleRequest->NrCharactersRead = pInputControl->nInitialChars;
memcpy(ReadConsoleRequest->Buffer,
lpBuffer,

View file

@ -167,8 +167,8 @@ typedef struct
HANDLE InputHandle;
BOOL Unicode;
WORD NrCharactersToRead;
WORD NrCharactersRead;
ULONG NrCharactersToRead;
ULONG NrCharactersRead;
UNICODE_STRING ExeName;
DWORD CtrlWakeupMask;

View file

@ -43,17 +43,9 @@ typedef struct ConsoleInput_t
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 **********************************************************/
#if 0
static VOID FASTCALL
ConioInputEventToAnsi(PCONSOLE Console, PINPUT_RECORD InputEvent)
{
@ -66,7 +58,6 @@ ConioInputEventToAnsi(PCONSOLE Console, PINPUT_RECORD InputEvent)
&UnicodeChar);
}
}
#endif
NTSTATUS FASTCALL
ConioProcessInputEvent(PCONSOLE Console,
@ -211,13 +202,231 @@ ConDrvProcessKey(IN PCONSOLE Console,
/* PUBLIC SERVER 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 = ReadControl->nInitialChars;
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) */
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 = 0;
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 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;
if (WaitForMoreEvents) // TRUE --> Read, we remove inputs from the buffer ; FALSE --> Peek, we keep inputs.
{
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 PINPUT_RECORD InputRecord,
IN ULONG NumEventsToWrite,
OUT PULONG NumEventsWritten)
OUT PULONG NumEventsWritten OPTIONAL)
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG i;
@ -230,9 +439,10 @@ ConDrvWriteConsoleInput(IN PCONSOLE Console,
ASSERT( (InputRecord != NULL && NumEventsToWrite >= 0) ||
(InputRecord == NULL && NumEventsToWrite == 0) );
if (NumEventsWritten) *NumEventsWritten = 0;
// Do NOT do that !! Use the existing number of events already written, if any...
// if (NumEventsWritten) *NumEventsWritten = 0;
for (i = 0; i < NumEventsToWrite && NT_SUCCESS(Status); ++i)
for (i = (NumEventsWritten ? *NumEventsWritten : 0); i < NumEventsToWrite && NT_SUCCESS(Status); ++i)
{
if (InputRecord->EventType == KEY_EVENT && !Unicode)
{

View file

@ -751,9 +751,77 @@ ConDrvWriteConsoleOutput(IN PCONSOLE Console,
}
NTSTATUS NTAPI
ConDrvWriteConsole(IN PCONSOLE Console)
ConDrvWriteConsole(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
IN BOOLEAN Unicode,
IN PVOID StringBuffer,
IN ULONG NumCharsToWrite,
OUT PULONG NumCharsWritten OPTIONAL)
{
return STATUS_NOT_IMPLEMENTED;
NTSTATUS Status = STATUS_SUCCESS;
PWCHAR Buffer = NULL;
ULONG Written = 0;
ULONG Length;
if (Console == NULL || ScreenBuffer == NULL /* || StringBuffer == NULL */)
return STATUS_INVALID_PARAMETER;
/* Validity checks */
ASSERT(Console == ScreenBuffer->Header.Console);
ASSERT( (StringBuffer != NULL && NumCharsToWrite >= 0) ||
(StringBuffer == NULL && NumCharsToWrite == 0) );
// if (Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION))
if (Console->PauseFlags && Console->UnpauseEvent != NULL)
{
return STATUS_PENDING;
}
if (Unicode)
{
Buffer = StringBuffer;
}
else
{
Length = MultiByteToWideChar(Console->OutputCodePage, 0,
(PCHAR)StringBuffer,
NumCharsToWrite,
NULL, 0);
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
if (Buffer)
{
MultiByteToWideChar(Console->OutputCodePage, 0,
(PCHAR)StringBuffer,
NumCharsToWrite,
(PWCHAR)Buffer, Length);
}
else
{
Status = STATUS_NO_MEMORY;
}
}
if (Buffer)
{
if (NT_SUCCESS(Status))
{
Status = ConioWriteConsole(Console,
ScreenBuffer,
Buffer,
NumCharsToWrite,
TRUE);
if (NT_SUCCESS(Status))
{
Written = NumCharsToWrite;
}
}
if (!Unicode) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
}
if (NumCharsWritten) *NumCharsWritten = Written;
return Status;
}
NTSTATUS NTAPI

View file

@ -31,15 +31,6 @@
ConSrvReleaseObject(&(Buff)->Header, (IsConsoleLocked))
#define ConsoleInputUnicodeCharToAnsiChar(Console, dChar, sWChar) \
WideCharToMultiByte((Console)->CodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
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.
@ -50,19 +41,6 @@ typedef struct _GET_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);
}
}
static NTSTATUS
WaitBeforeReading(IN PGET_INPUT_INFO InputInfo,
IN PCSR_API_MESSAGE ApiMessage,
@ -94,6 +72,120 @@ WaitBeforeReading(IN PGET_INPUT_INFO InputInfo,
return STATUS_PENDING;
}
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;
ConsoleFreeHeap(InputInfo);
}
return (Status == STATUS_PENDING ? FALSE : TRUE);
}
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);
static NTSTATUS
ReadChars(IN PGET_INPUT_INFO InputInfo,
IN PCSR_API_MESSAGE ApiMessage,
IN BOOL CreateWaitBlock OPTIONAL)
{
NTSTATUS Status;
PCONSOLE_READCONSOLE ReadConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleRequest;
PCONSOLE_INPUT_BUFFER InputBuffer = InputInfo->InputBuffer;
CONSOLE_READCONSOLE_CONTROL ReadControl;
ReadControl.nLength = sizeof(CONSOLE_READCONSOLE_CONTROL);
ReadControl.nInitialChars = ReadConsoleRequest->NrCharactersRead;
ReadControl.dwCtrlWakeupMask = ReadConsoleRequest->CtrlWakeupMask;
ReadControl.dwControlKeyState = ReadConsoleRequest->ControlKeyState;
Status = ConDrvReadConsole(InputBuffer->Header.Console,
InputBuffer,
ReadConsoleRequest->Unicode,
ReadConsoleRequest->Buffer,
&ReadControl,
ReadConsoleRequest->NrCharactersToRead,
&ReadConsoleRequest->NrCharactersRead);
ReadConsoleRequest->ControlKeyState = ReadControl.dwControlKeyState;
if (Status == STATUS_PENDING)
{
/* We haven't completed a read, so start a wait */
return WaitBeforeReading(InputInfo,
ApiMessage,
ReadCharsThread,
CreateWaitBlock);
}
else
{
/* We read all what we wanted, we return the error code we were given */
return Status;
// return STATUS_SUCCESS;
}
}
static NTSTATUS
ReadInputBuffer(IN PGET_INPUT_INFO InputInfo,
IN BOOL Wait,
@ -162,292 +254,47 @@ Quit:
return (Status == STATUS_PENDING ? FALSE : TRUE);
}
NTSTATUS NTAPI
ConDrvGetConsoleInput(IN PCONSOLE Console,
IN PCONSOLE_INPUT_BUFFER InputBuffer,
IN BOOLEAN WaitForMoreEvents,
IN BOOLEAN Unicode,
OUT PINPUT_RECORD InputRecord,
IN ULONG NumEventsToRead,
OUT PULONG NumEventsRead);
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);
ConsoleFreeHeap(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;
ConsoleFreeHeap(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_GETINPUT GetInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetInputRequest;
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) */
// GetInputRequest->InputsRead = 0;
if (InputBuffer->Mode & ENABLE_LINE_INPUT)
{
if (Console->LineBuffer == NULL)
{
/* Starting a new line */
Console->LineMaxSize = (WORD)max(256, nNumberOfCharsToRead);
Console->LineBuffer = ConsoleAllocHeap(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;
}
ConsoleFreeHeap(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 */
ConsoleFreeHeap(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;
}
ConsoleFreeHeap(Input);
}
}
/* We haven't completed a read, so start a wait */
if (WaitForMoreToRead == TRUE)
Status = ConDrvGetConsoleInput(InputBuffer->Header.Console,
InputBuffer,
Wait,
GetInputRequest->Unicode,
GetInputRequest->InputRecord,
GetInputRequest->Length,
&GetInputRequest->InputsRead);
if (Status == STATUS_PENDING)
{
/* We haven't completed a read, so start a wait */
return WaitBeforeReading(InputInfo,
ApiMessage,
ReadCharsThread,
ReadInputBufferThread,
CreateWaitBlock);
}
else /* We read all what we wanted, we return success */
else
{
return STATUS_SUCCESS;
/* We read all what we wanted, we return the error code we were given */
return Status;
// return STATUS_SUCCESS;
}
}
@ -481,7 +328,8 @@ CSR_API(SrvReadConsole)
Status = ConSrvGetInputBufferAndHandleEntry(ProcessData, ReadConsoleRequest->InputHandle, &InputBuffer, &HandleEntry, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
ReadConsoleRequest->NrCharactersRead = 0;
// This member is set by the caller (IntReadConsole in kernel32)
// ReadConsoleRequest->NrCharactersRead = 0;
InputInfo.CallingThread = CsrGetClientThread();
InputInfo.HandleEntry = HandleEntry;
@ -493,8 +341,7 @@ CSR_API(SrvReadConsole)
ConSrvReleaseInputBuffer(InputBuffer, TRUE);
if (Status == STATUS_PENDING)
*ReplyCode = CsrReplyPending;
if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
return Status;
}
@ -518,11 +365,11 @@ CSR_API(SrvGetConsoleInput)
return STATUS_INVALID_PARAMETER;
}
GetInputRequest->InputsRead = 0;
Status = ConSrvGetInputBufferAndHandleEntry(ProcessData, GetInputRequest->InputHandle, &InputBuffer, &HandleEntry, GENERIC_READ, TRUE);
if (!NT_SUCCESS(Status)) return Status;
GetInputRequest->InputsRead = 0;
InputInfo.CallingThread = CsrGetClientThread();
InputInfo.HandleEntry = HandleEntry;
InputInfo.InputBuffer = InputBuffer;
@ -534,8 +381,7 @@ CSR_API(SrvGetConsoleInput)
ConSrvReleaseInputBuffer(InputBuffer, TRUE);
if (Status == STATUS_PENDING)
*ReplyCode = CsrReplyPending;
if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
return Status;
}
@ -546,13 +392,13 @@ ConDrvWriteConsoleInput(IN PCONSOLE Console,
IN BOOLEAN Unicode,
IN PINPUT_RECORD InputRecord,
IN ULONG NumEventsToWrite,
OUT PULONG NumEventsWritten);
OUT PULONG NumEventsWritten OPTIONAL);
CSR_API(SrvWriteConsoleInput)
{
NTSTATUS Status;
PCONSOLE_WRITEINPUT WriteInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteInputRequest;
PCONSOLE_INPUT_BUFFER InputBuffer;
ULONG NumEventsWritten = 0;
ULONG NumEventsWritten;
DPRINT("SrvWriteConsoleInput\n");
@ -569,6 +415,7 @@ CSR_API(SrvWriteConsoleInput)
&InputBuffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
NumEventsWritten = 0;
Status = ConDrvWriteConsoleInput(InputBuffer->Header.Console,
InputBuffer,
WriteInputRequest->Unicode,

View file

@ -314,30 +314,39 @@ Quit:
return (Status == STATUS_PENDING ? FALSE : TRUE);
}
NTSTATUS NTAPI
ConDrvWriteConsole(IN PCONSOLE Console,
IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
IN BOOLEAN Unicode,
IN PVOID StringBuffer,
IN ULONG NumCharsToWrite,
OUT PULONG NumCharsWritten OPTIONAL);
static NTSTATUS
DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
IN PCSR_THREAD ClientThread,
IN BOOL CreateWaitBlock OPTIONAL)
{
NTSTATUS Status = STATUS_SUCCESS;
NTSTATUS Status;
PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
PCONSOLE Console;
PTEXTMODE_SCREEN_BUFFER Buff;
PVOID Buffer;
DWORD Written = 0;
ULONG Length;
PTEXTMODE_SCREEN_BUFFER ScreenBuffer;
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(ClientThread->Process), WriteConsoleRequest->OutputHandle, &Buff, GENERIC_WRITE, FALSE);
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(ClientThread->Process),
WriteConsoleRequest->OutputHandle,
&ScreenBuffer, GENERIC_WRITE, FALSE);
if (!NT_SUCCESS(Status)) return Status;
Console = Buff->Header.Console;
Status = ConDrvWriteConsole(ScreenBuffer->Header.Console,
ScreenBuffer,
WriteConsoleRequest->Unicode,
WriteConsoleRequest->Buffer,
WriteConsoleRequest->NrCharactersToWrite,
&WriteConsoleRequest->NrCharactersWritten);
// if (Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION))
if (Console->PauseFlags && Console->UnpauseEvent != NULL)
if (Status == STATUS_PENDING)
{
if (CreateWaitBlock)
{
if (!CsrCreateWait(&Console->WriteWaitQueue,
if (!CsrCreateWait(&ScreenBuffer->Header.Console->WriteWaitQueue,
WriteConsoleThread,
ClientThread,
ApiMessage,
@ -345,63 +354,17 @@ DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
NULL))
{
/* Fail */
ConSrvReleaseScreenBuffer(Buff, FALSE);
return STATUS_NO_MEMORY;
Status = STATUS_NO_MEMORY;
goto Quit;
}
}
/* Wait until we un-pause the console */
Status = STATUS_PENDING;
}
else
{
if (WriteConsoleRequest->Unicode)
{
Buffer = WriteConsoleRequest->Buffer;
}
else
{
Length = MultiByteToWideChar(Console->OutputCodePage, 0,
(PCHAR)WriteConsoleRequest->Buffer,
WriteConsoleRequest->NrCharactersToWrite,
NULL, 0);
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
if (Buffer)
{
MultiByteToWideChar(Console->OutputCodePage, 0,
(PCHAR)WriteConsoleRequest->Buffer,
WriteConsoleRequest->NrCharactersToWrite,
(PWCHAR)Buffer, Length);
}
else
{
Status = STATUS_NO_MEMORY;
}
}
if (Buffer)
{
if (NT_SUCCESS(Status))
{
Status = ConioWriteConsole(Console,
Buff,
Buffer,
WriteConsoleRequest->NrCharactersToWrite,
TRUE);
if (NT_SUCCESS(Status))
{
Written = WriteConsoleRequest->NrCharactersToWrite;
}
}
if (!WriteConsoleRequest->Unicode)
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
}
WriteConsoleRequest->NrCharactersWritten = Written;
// Status = STATUS_PENDING;
}
ConSrvReleaseScreenBuffer(Buff, FALSE);
Quit:
ConSrvReleaseScreenBuffer(ScreenBuffer, FALSE);
return Status;
}
@ -509,8 +472,7 @@ CSR_API(SrvWriteConsole)
CsrGetClientThread(),
TRUE);
if (Status == STATUS_PENDING)
*ReplyCode = CsrReplyPending;
if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
return Status;
}