mirror of
https://github.com/reactos/reactos.git
synced 2025-01-13 01:22:03 +00:00
[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:
parent
4625d1efa0
commit
9f7057e9f2
8 changed files with 120 additions and 68 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue