[KERNEL32], [WIN32CSR]

- Implement ReadConsoleW's CONSOLE_READCONSOLE_CONTROL structure.
- Make pressing Insert during line input work

svn path=/trunk/; revision=47693
This commit is contained in:
Jeffrey Morlan 2010-06-08 06:38:14 +00:00
parent 4625d1efa0
commit 9f7057e9f2
8 changed files with 120 additions and 68 deletions

View file

@ -1698,37 +1698,45 @@ IntReadConsole(HANDLE hConsoleInput,
PVOID lpBuffer,
DWORD nNumberOfCharsToRead,
LPDWORD lpNumberOfCharsRead,
PCONSOLE_READCONSOLE_CONTROL lpReserved,
PCONSOLE_READCONSOLE_CONTROL pInputControl,
BOOL bUnicode)
{
PCSR_API_MESSAGE Request;
ULONG CsrRequest;
NTSTATUS Status;
ULONG CharSize, CharsRead = 0;
CSR_API_MESSAGE Request;
PCSR_CAPTURE_BUFFER CaptureBuffer;
ULONG CsrRequest = MAKE_CSR_API(READ_CONSOLE, CSR_CONSOLE);
NTSTATUS Status = STATUS_SUCCESS;
ULONG CharSize = (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
CharSize = (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
Request = RtlAllocateHeap(RtlGetProcessHeap(),
0,
max(sizeof(CSR_API_MESSAGE),
CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE) + min(nNumberOfCharsToRead,
CSRSS_MAX_READ_CONSOLE / CharSize) * CharSize));
if (Request == NULL)
CaptureBuffer = CsrAllocateCaptureBuffer(1, nNumberOfCharsToRead * CharSize);
if (CaptureBuffer == NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
Request->Status = STATUS_SUCCESS;
Request->Data.ReadConsoleRequest.ConsoleHandle = hConsoleInput;
Request->Data.ReadConsoleRequest.Unicode = bUnicode;
Request->Data.ReadConsoleRequest.FullReadSize = (WORD)nNumberOfCharsToRead;
CsrRequest = MAKE_CSR_API(READ_CONSOLE, CSR_CONSOLE);
CsrAllocateMessagePointer(CaptureBuffer,
nNumberOfCharsToRead * CharSize,
&Request.Data.ReadConsoleRequest.Buffer);
Request.Data.ReadConsoleRequest.ConsoleHandle = hConsoleInput;
Request.Data.ReadConsoleRequest.Unicode = bUnicode;
Request.Data.ReadConsoleRequest.NrCharactersToRead = (WORD)nNumberOfCharsToRead;
Request.Data.ReadConsoleRequest.NrCharactersRead = 0;
Request.Data.ReadConsoleRequest.CtrlWakeupMask = 0;
if (pInputControl && pInputControl->nLength == sizeof(CONSOLE_READCONSOLE_CONTROL))
{
Request.Data.ReadConsoleRequest.NrCharactersRead = pInputControl->nInitialChars;
memcpy(Request.Data.ReadConsoleRequest.Buffer,
lpBuffer,
pInputControl->nInitialChars * sizeof(WCHAR));
Request.Data.ReadConsoleRequest.CtrlWakeupMask = pInputControl->dwCtrlWakeupMask;
}
do
{
if (Request->Status == STATUS_PENDING)
if (Status == STATUS_PENDING)
{
Status = NtWaitForSingleObject(Request->Data.ReadConsoleRequest.EventHandle,
Status = NtWaitForSingleObject(Request.Data.ReadConsoleRequest.EventHandle,
FALSE,
0);
if (!NT_SUCCESS(Status))
@ -1738,37 +1746,28 @@ IntReadConsole(HANDLE hConsoleInput,
}
}
Request->Data.ReadConsoleRequest.NrCharactersToRead = (WORD)min(nNumberOfCharsToRead, CSRSS_MAX_READ_CONSOLE / CharSize);
Status = CsrClientCallServer(Request,
NULL,
CsrRequest,
max(sizeof(CSR_API_MESSAGE),
CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE)
+ Request->Data.ReadConsoleRequest.NrCharactersToRead * CharSize));
if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Request->Status))
Status = CsrClientCallServer(&Request, CaptureBuffer, CsrRequest, sizeof(CSR_API_MESSAGE));
if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Request.Status))
{
DPRINT1("CSR returned error in ReadConsole\n");
RtlFreeHeap(RtlGetProcessHeap(), 0, Request);
CsrFreeCaptureBuffer(CaptureBuffer);
SetLastErrorByStatus(Status);
return FALSE;
}
nNumberOfCharsToRead -= Request->Data.ReadConsoleRequest.NrCharactersRead;
memcpy((PVOID)((ULONG_PTR)lpBuffer + (ULONG_PTR)(CharsRead * CharSize)),
Request->Data.ReadConsoleRequest.Buffer,
Request->Data.ReadConsoleRequest.NrCharactersRead * CharSize);
CharsRead += Request->Data.ReadConsoleRequest.NrCharactersRead;
}
while (Request->Status == STATUS_PENDING && nNumberOfCharsToRead > 0);
while (Status == STATUS_PENDING);
memcpy(lpBuffer,
Request.Data.ReadConsoleRequest.Buffer,
Request.Data.ReadConsoleRequest.NrCharactersRead * CharSize);
if (lpNumberOfCharsRead != NULL)
{
*lpNumberOfCharsRead = CharsRead;
}
*lpNumberOfCharsRead = Request.Data.ReadConsoleRequest.NrCharactersRead;
RtlFreeHeap(RtlGetProcessHeap(), 0, Request);
if (pInputControl && pInputControl->nLength == sizeof(CONSOLE_READCONSOLE_CONTROL))
pInputControl->dwControlKeyState = Request.Data.ReadConsoleRequest.ControlKeyState;
CsrFreeCaptureBuffer(CaptureBuffer);
return TRUE;
}
@ -1791,7 +1790,7 @@ ReadConsoleA(HANDLE hConsoleInput,
lpBuffer,
nNumberOfCharsToRead,
lpNumberOfCharsRead,
pInputControl,
NULL,
FALSE);
}

View file

@ -70,11 +70,13 @@ typedef struct
{
HANDLE ConsoleHandle;
BOOL Unicode;
WORD FullReadSize;
WORD NrCharactersToRead;
WORD NrCharactersRead;
HANDLE EventHandle;
ULONG NrCharactersRead;
BYTE Buffer[0];
PVOID Buffer;
UNICODE_STRING ExeName;
DWORD CtrlWakeupMask;
DWORD ControlKeyState;
} CSRSS_READ_CONSOLE, *PCSRSS_READ_CONSOLE;
typedef struct
@ -515,7 +517,6 @@ typedef struct
#define CSRSS_MAX_WRITE_CONSOLE (LPC_MAX_DATA_LENGTH - CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE))
#define CSRSS_MAX_WRITE_CONSOLE_OUTPUT_CHAR (LPC_MAX_DATA_LENGTH - CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE_OUTPUT_CHAR))
#define CSRSS_MAX_WRITE_CONSOLE_OUTPUT_ATTRIB (LPC_MAX_DATA_LENGTH - CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE_OUTPUT_ATTRIB))
#define CSRSS_MAX_READ_CONSOLE (LPC_MAX_DATA_LENGTH - CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE))
#define CSRSS_MAX_READ_CONSOLE_OUTPUT_CHAR (LPC_MAX_DATA_LENGTH - CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_CHAR))
#define CSRSS_MAX_READ_CONSOLE_OUTPUT_ATTRIB (LPC_MAX_DATA_LENGTH - CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_ATTRIB))

View file

@ -37,13 +37,18 @@ CSR_API(CsrReadConsole)
CharSize = (Request->Data.ReadConsoleRequest.Unicode ? sizeof(WCHAR) : sizeof(CHAR));
/* truncate length to CSRSS_MAX_READ_CONSOLE_REQUEST */
nNumberOfCharsToRead = min(Request->Data.ReadConsoleRequest.NrCharactersToRead, CSRSS_MAX_READ_CONSOLE / CharSize);
nNumberOfCharsToRead = Request->Data.ReadConsoleRequest.NrCharactersToRead;
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
Buffer = (PCHAR)Request->Data.ReadConsoleRequest.Buffer;
UnicodeBuffer = (PWCHAR)Buffer;
if (!Win32CsrValidateBuffer(ProcessData, Buffer, nNumberOfCharsToRead, CharSize))
return STATUS_ACCESS_VIOLATION;
if (Request->Data.ReadConsoleRequest.NrCharactersRead * sizeof(WCHAR) > nNumberOfCharsToRead * CharSize)
return STATUS_INVALID_PARAMETER;
Status = ConioLockConsole(ProcessData, Request->Data.ReadConsoleRequest.ConsoleHandle,
&Console, GENERIC_READ);
if (! NT_SUCCESS(Status))
@ -58,7 +63,7 @@ CSR_API(CsrReadConsole)
if (Console->LineBuffer == NULL)
{
/* Starting a new line */
Console->LineMaxSize = max(256, Request->Data.ReadConsoleRequest.FullReadSize);
Console->LineMaxSize = max(256, nNumberOfCharsToRead);
Console->LineBuffer = HeapAlloc(Win32CsrApiHeap, 0, Console->LineMaxSize * sizeof(WCHAR));
if (Console->LineBuffer == NULL)
{
@ -66,9 +71,19 @@ CSR_API(CsrReadConsole)
goto done;
}
Console->LineComplete = FALSE;
Console->LineSize = 0;
Console->LinePos = 0;
Console->LineUpPressed = FALSE;
Console->LineInsertToggle = 0;
Console->LineWakeupMask = Request->Data.ReadConsoleRequest.CtrlWakeupMask;
Console->LineSize = Request->Data.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 */
@ -87,6 +102,7 @@ CSR_API(CsrReadConsole)
&& Input->InputEvent.Event.KeyEvent.bKeyDown)
{
LineInputKeyDown(Console, &Input->InputEvent.Event.KeyEvent);
Request->Data.ReadConsoleRequest.ControlKeyState = Input->InputEvent.Event.KeyEvent.dwControlKeyState;
}
HeapFree(Win32CsrApiHeap, 0, Input);
}
@ -104,10 +120,11 @@ CSR_API(CsrReadConsole)
}
if (Console->LinePos == Console->LineSize)
{
/* Entire line has been read */
HeapFree(Win32CsrApiHeap, 0, Console->LineBuffer);
Console->LineBuffer = NULL;
Status = STATUS_SUCCESS; /* Entire line has been read */
}
Status = STATUS_SUCCESS;
}
}
else
@ -142,12 +159,6 @@ done:
Request->Data.ReadConsoleRequest.NrCharactersRead = i;
ConioUnlockConsole(Console);
if (CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE) + i * CharSize > sizeof(CSR_API_MESSAGE))
{
Request->Header.u1.s1.TotalLength = CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE) + i * CharSize;
Request->Header.u1.s1.DataLength = Request->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
}
return Status;
}
@ -355,6 +366,12 @@ ConioProcessKey(MSG *msg, PCSRSS_CONSOLE Console, BOOL TextMode)
current_entry = current_entry->Flink;
ConioConsoleCtrlEvent((DWORD)CTRL_C_EVENT, current);
}
if (Console->LineBuffer && !Console->LineComplete)
{
/* Line input is in progress; end it */
Console->LinePos = Console->LineSize = 0;
Console->LineComplete = TRUE;
}
return;
}

View file

@ -81,6 +81,8 @@ typedef struct tagCSRSS_CONSOLE
WORD LinePos; /* current position within line */
BOOLEAN LineComplete; /* user pressed enter, ready to send back to client */
BOOLEAN LineUpPressed;
BOOLEAN LineInsertToggle; /* replace character over cursor instead of inserting */
ULONG LineWakeupMask; /* bitmap of which control characters will end line input */
LIST_ENTRY HistoryBuffers;
WORD HistoryBufferSize; /* size for newly created history buffers */
WORD NumberOfHistoryBuffers; /* maximum number of history buffers allowed */
@ -192,6 +194,7 @@ NTSTATUS FASTCALL ConioWriteConsole(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER
CHAR *Buffer, DWORD Length, BOOL Attrib);
NTSTATUS FASTCALL CsrInitConsoleScreenBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buffer);
VOID WINAPI ConioDeleteScreenBuffer(PCSRSS_SCREEN_BUFFER Buffer);
DWORD FASTCALL ConioEffectiveCursorSize(PCSRSS_CONSOLE Console, DWORD Scale);
CSR_API(CsrWriteConsole);
CSR_API(CsrGetScreenBufferInfo);

View file

@ -865,6 +865,16 @@ CSR_API(CsrFillOutputAttrib)
return STATUS_SUCCESS;
}
DWORD FASTCALL
ConioEffectiveCursorSize(PCSRSS_CONSOLE Console, DWORD Scale)
{
DWORD Size = (Console->ActiveBuffer->CursorInfo.dwSize * Scale + 99) / 100;
/* If line input in progress, perhaps adjust for insert toggle */
if (Console->LineBuffer && !Console->LineComplete && Console->LineInsertToggle)
return (Size * 2 <= Scale) ? (Size * 2) : (Size / 2);
return Size;
}
CSR_API(CsrGetCursorInfo)
{
PCSRSS_SCREEN_BUFFER Buff;

View file

@ -946,11 +946,7 @@ GuiConsolePaint(PCSRSS_CONSOLE Console,
if (LeftChar <= CursorX && CursorX <= RightChar &&
TopLine <= CursorY && CursorY <= BottomLine)
{
CursorHeight = (GuiData->CharHeight * Buff->CursorInfo.dwSize) / 100;
if (CursorHeight < 1)
{
CursorHeight = 1;
}
CursorHeight = ConioEffectiveCursorSize(Console, GuiData->CharHeight);
From = ConioCoordToPointer(Buff, Buff->CurrentX, Buff->CurrentY) + 1;
if (*From != DEFAULT_ATTRIB)

View file

@ -459,6 +459,11 @@ LineInputKeyDown(PCSRSS_CONSOLE Console, KEY_EVENT_RECORD *KeyEvent)
LineInputEdit(Console, 0, 1, &Entry.Buffer[Pos]);
}
return;
case VK_INSERT:
/* Toggle between insert and overstrike */
Console->LineInsertToggle = !Console->LineInsertToggle;
ConioSetCursorInfo(Console, Console->ActiveBuffer);
return;
case VK_DELETE:
/* Remove character to right of cursor */
if (Pos != Console->LineSize)
@ -555,7 +560,12 @@ LineInputKeyDown(PCSRSS_CONSOLE Console, KEY_EVENT_RECORD *KeyEvent)
Console->LineBuffer[Console->LineSize++] = L'\r';
if (Console->Mode & ENABLE_ECHO_INPUT)
ConioWriteConsole(Console, Console->ActiveBuffer, "\r", 1, TRUE);
if (Console->Mode & ENABLE_PROCESSED_INPUT)
/* Add \n if processed input. There should usually be room for it,
* but an exception to the rule exists: the buffer could have been
* pre-filled with LineMaxSize - 1 characters. */
if (Console->Mode & ENABLE_PROCESSED_INPUT &&
Console->LineSize < Console->LineMaxSize)
{
Console->LineBuffer[Console->LineSize++] = L'\n';
if (Console->Mode & ENABLE_ECHO_INPUT)
@ -566,8 +576,21 @@ LineInputKeyDown(PCSRSS_CONSOLE Console, KEY_EVENT_RECORD *KeyEvent)
}
else if (KeyEvent->uChar.UnicodeChar != L'\0')
{
/* Normal character */
LineInputEdit(Console, 0, 1, &KeyEvent->uChar.UnicodeChar);
if (KeyEvent->uChar.UnicodeChar < 0x20 &&
Console->LineWakeupMask & (1 << KeyEvent->uChar.UnicodeChar))
{
/* Control key client wants to handle itself (e.g. for tab completion) */
Console->LineBuffer[Console->LineSize++] = L' ';
Console->LineBuffer[Console->LinePos] = KeyEvent->uChar.UnicodeChar;
Console->LineComplete = TRUE;
Console->LinePos = 0;
}
else
{
/* Normal character */
BOOL Overstrike = Console->LineInsertToggle && Console->LinePos != Console->LineSize;
LineInputEdit(Console, Overstrike, 1, &KeyEvent->uChar.UnicodeChar);
}
}
}

View file

@ -208,6 +208,7 @@ TuiWriteStream(PCSRSS_CONSOLE Console, SMALL_RECT *Region, LONG CursorStartX, LO
static BOOL WINAPI
TuiSetCursorInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff)
{
CONSOLE_CURSOR_INFO Info;
DWORD BytesReturned;
if (ActiveConsole->ActiveBuffer != Buff)
@ -215,9 +216,11 @@ TuiSetCursorInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff)
return TRUE;
}
Info.dwSize = ConioEffectiveCursorSize(Console, 100);
Info.bVisible = Buff->CursorInfo.bVisible;
if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_CURSOR_INFO,
&Buff->CursorInfo, sizeof(Buff->CursorInfo), NULL, 0,
&BytesReturned, NULL))
&Info, sizeof(Info), NULL, 0, &BytesReturned, NULL))
{
DPRINT1( "Failed to set cursor info\n" );
return FALSE;