in src/host/readDataCooked.cpp [479:817]
bool COOKED_READ_DATA::ProcessInput(const wchar_t wchOrig,
const DWORD keyState,
NTSTATUS& status)
{
const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
size_t NumSpaces = 0;
SHORT ScrollY = 0;
size_t NumToWrite;
WCHAR wch = wchOrig;
bool fStartFromDelim;
status = STATUS_SUCCESS;
if (_bytesRead >= (_bufferSize - (2 * sizeof(WCHAR))) && wch != UNICODE_CARRIAGERETURN && wch != UNICODE_BACKSPACE)
{
return false;
}
if (_ctrlWakeupMask != 0 && wch < L' ' && (_ctrlWakeupMask & (1 << wch)))
{
*_bufPtr = wch;
_bytesRead += sizeof(WCHAR);
_bufPtr += 1;
_currentPosition += 1;
_controlKeyState = keyState;
return true;
}
if (wch == EXTKEY_ERASE_PREV_WORD)
{
wch = UNICODE_BACKSPACE;
}
if (AtEol())
{
// If at end of line, processing is relatively simple. Just store the character and write it to the screen.
if (wch == UNICODE_BACKSPACE2)
{
wch = UNICODE_BACKSPACE;
}
if (wch != UNICODE_BACKSPACE || _bufPtr != _backupLimit)
{
fStartFromDelim = IsWordDelim(_bufPtr[-1]);
bool loop = true;
while (loop)
{
loop = false;
if (_echoInput)
{
NumToWrite = sizeof(WCHAR);
status = WriteCharsLegacy(_screenInfo,
_backupLimit,
_bufPtr,
&wch,
&NumToWrite,
&NumSpaces,
_originalCursorPosition.X,
WC_DESTRUCTIVE_BACKSPACE | WC_KEEP_CURSOR_VISIBLE | WC_PRINTABLE_CONTROL_CHARS,
&ScrollY);
if (NT_SUCCESS(status))
{
_originalCursorPosition.Y += ScrollY;
}
else
{
RIPMSG1(RIP_WARNING, "WriteCharsLegacy failed %x", status);
}
}
_visibleCharCount += NumSpaces;
if (wch == UNICODE_BACKSPACE && _processedInput)
{
_bytesRead -= sizeof(WCHAR);
// clang-format off
#pragma prefast(suppress: __WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY, "This access is fine")
// clang-format on
*_bufPtr = (WCHAR)' ';
_bufPtr -= 1;
_currentPosition -= 1;
// Repeat until it hits the word boundary
if (wchOrig == EXTKEY_ERASE_PREV_WORD &&
_bufPtr != _backupLimit &&
fStartFromDelim ^ !IsWordDelim(_bufPtr[-1]))
{
loop = true;
}
}
else
{
*_bufPtr = wch;
_bytesRead += sizeof(WCHAR);
_bufPtr += 1;
_currentPosition += 1;
}
}
}
}
else
{
bool CallWrite = true;
const SHORT sScreenBufferSizeX = _screenInfo.GetBufferSize().Width();
// processing in the middle of the line is more complex:
// calculate new cursor position
// store new char
// clear the current command line from the screen
// write the new command line to the screen
// update the cursor position
if (wch == UNICODE_BACKSPACE && _processedInput)
{
// for backspace, use writechars to calculate the new cursor position.
// this call also sets the cursor to the right position for the
// second call to writechars.
if (_bufPtr != _backupLimit)
{
fStartFromDelim = IsWordDelim(_bufPtr[-1]);
bool loop = true;
while (loop)
{
loop = false;
// we call writechar here so that cursor position gets updated
// correctly. we also call it later if we're not at eol so
// that the remainder of the string can be updated correctly.
if (_echoInput)
{
NumToWrite = sizeof(WCHAR);
status = WriteCharsLegacy(_screenInfo,
_backupLimit,
_bufPtr,
&wch,
&NumToWrite,
nullptr,
_originalCursorPosition.X,
WC_DESTRUCTIVE_BACKSPACE | WC_KEEP_CURSOR_VISIBLE | WC_PRINTABLE_CONTROL_CHARS,
nullptr);
if (!NT_SUCCESS(status))
{
RIPMSG1(RIP_WARNING, "WriteCharsLegacy failed %x", status);
}
}
_bytesRead -= sizeof(WCHAR);
_bufPtr -= 1;
_currentPosition -= 1;
memmove(_bufPtr,
_bufPtr + 1,
_bytesRead - (_currentPosition * sizeof(WCHAR)));
{
PWCHAR buf = (PWCHAR)((PBYTE)_backupLimit + _bytesRead);
*buf = (WCHAR)' ';
}
NumSpaces = 0;
// Repeat until it hits the word boundary
if (wchOrig == EXTKEY_ERASE_PREV_WORD &&
_bufPtr != _backupLimit &&
fStartFromDelim ^ !IsWordDelim(_bufPtr[-1]))
{
loop = true;
}
}
}
else
{
CallWrite = false;
}
}
else
{
// store the char
if (wch == UNICODE_CARRIAGERETURN)
{
_bufPtr = (PWCHAR)((PBYTE)_backupLimit + _bytesRead);
*_bufPtr = wch;
_bufPtr += 1;
_bytesRead += sizeof(WCHAR);
_currentPosition += 1;
}
else
{
bool fBisect = false;
if (_echoInput)
{
if (CheckBisectProcessW(_screenInfo,
_backupLimit,
_currentPosition + 1,
sScreenBufferSizeX - _originalCursorPosition.X,
_originalCursorPosition.X,
TRUE))
{
fBisect = true;
}
}
if (_insertMode)
{
memmove(_bufPtr + 1,
_bufPtr,
_bytesRead - (_currentPosition * sizeof(WCHAR)));
_bytesRead += sizeof(WCHAR);
}
*_bufPtr = wch;
_bufPtr += 1;
_currentPosition += 1;
// calculate new cursor position
if (_echoInput)
{
NumSpaces = RetrieveNumberOfSpaces(_originalCursorPosition.X,
_backupLimit,
_currentPosition - 1);
if (NumSpaces > 0 && fBisect)
NumSpaces--;
}
}
}
if (_echoInput && CallWrite)
{
COORD CursorPosition;
// save cursor position
CursorPosition = _screenInfo.GetTextBuffer().GetCursor().GetPosition();
CursorPosition.X = (SHORT)(CursorPosition.X + NumSpaces);
// clear the current command line from the screen
// clang-format off
#pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "Not sure why prefast doesn't like this call.")
// clang-format on
DeleteCommandLine(*this, FALSE);
// write the new command line to the screen
NumToWrite = _bytesRead;
DWORD dwFlags = WC_DESTRUCTIVE_BACKSPACE | WC_PRINTABLE_CONTROL_CHARS;
if (wch == UNICODE_CARRIAGERETURN)
{
dwFlags |= WC_KEEP_CURSOR_VISIBLE;
}
status = WriteCharsLegacy(_screenInfo,
_backupLimit,
_backupLimit,
_backupLimit,
&NumToWrite,
&_visibleCharCount,
_originalCursorPosition.X,
dwFlags,
&ScrollY);
if (!NT_SUCCESS(status))
{
RIPMSG1(RIP_WARNING, "WriteCharsLegacy failed 0x%x", status);
_bytesRead = 0;
return true;
}
// update cursor position
if (wch != UNICODE_CARRIAGERETURN)
{
if (CheckBisectProcessW(_screenInfo,
_backupLimit,
_currentPosition + 1,
sScreenBufferSizeX - _originalCursorPosition.X,
_originalCursorPosition.X,
TRUE))
{
if (CursorPosition.X == (sScreenBufferSizeX - 1))
{
CursorPosition.X++;
}
}
// adjust cursor position for WriteChars
_originalCursorPosition.Y += ScrollY;
CursorPosition.Y += ScrollY;
status = AdjustCursorPosition(_screenInfo, CursorPosition, TRUE, nullptr);
if (!NT_SUCCESS(status))
{
_bytesRead = 0;
return true;
}
}
}
}
// in cooked mode, enter (carriage return) is converted to
// carriage return linefeed (0xda). carriage return is always
// stored at the end of the buffer.
if (wch == UNICODE_CARRIAGERETURN)
{
if (_processedInput)
{
if (_bytesRead < _bufferSize)
{
*_bufPtr = UNICODE_LINEFEED;
if (_echoInput)
{
NumToWrite = sizeof(WCHAR);
status = WriteCharsLegacy(_screenInfo,
_backupLimit,
_bufPtr,
_bufPtr,
&NumToWrite,
nullptr,
_originalCursorPosition.X,
WC_DESTRUCTIVE_BACKSPACE | WC_KEEP_CURSOR_VISIBLE | WC_PRINTABLE_CONTROL_CHARS,
nullptr);
if (!NT_SUCCESS(status))
{
RIPMSG1(RIP_WARNING, "WriteCharsLegacy failed 0x%x", status);
}
}
_bytesRead += sizeof(WCHAR);
_bufPtr++;
_currentPosition += 1;
}
}
// reset the cursor back to 25% if necessary
if (_lineInput)
{
if (_insertMode != gci.GetInsertMode())
{
// Make cursor small.
LOG_IF_FAILED(CommandLine::Instance().ProcessCommandLine(*this, VK_INSERT, 0));
}
status = STATUS_SUCCESS;
return true;
}
}
return false;
}