terminal/src/cascadia/TerminalCore/TerminalDispatch.cpp
James Holderness 7b7dea009c
Consolidate the interfaces for setting VT input modes (#11384)
Instead of having a separate method for setting each mouse and keyboard
mode, this PR consolidates them all into a single method which takes a
mode parameter, and stores the modes in a `til::enumset` rather than
having a separate `bool` for each mode.

This enables us to get rid of a lot of boilerplate code, and makes the
code easier to extend when we want to introduce additional modes in the
future. It'll also makes it easier to read back the state of the various
modes when implementing the `DECRQM` query.

Most of the complication is in the `TerminalInput` class, which had to
be adjusted to work with an `enumset` in place of all the `bool` fields.
For the rest, it was largely a matter of replacing calls to all the old
mode setting methods with the new `SetInputMode` method, and deleting a
bunch of unused code.

One thing worth mentioning is that the `AdaptDispatch` implementation
used to have a `_ShouldPassThroughInputModeChange` method that was
called after every mode change. This code has now been moved up into the
`SetInputMode` implementation in `ConhostInternalGetSet` so it's just
handled in one place. Keeping this out of the dispatch class will also
be beneficial for sharing the implementation with `TerminalDispatch`.

## Validation

The updated interface necessitated some adjustments to the tests in
`AdapterTest` and `MouseInputTest`, but the essential structure of the
tests remains unchanged, and everything still passes.

I've also tested the keyboard and mouse modes in Vttest and confirmed
they still work at least as well as they did before (both conhost and
Windows Terminal), and I tested the alternate scroll mode manually
(conhost only).

Simplifying the `ConGetSet` and `ITerminalApi` is also part of the plan
to de-duplicate the `AdaptDispatch` and `TerminalDispatch`
implementation (#3849).
2021-10-26 21:12:22 +00:00

745 lines
24 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "TerminalDispatch.hpp"
#include "../../types/inc/utils.hpp"
using namespace Microsoft::Console;
using namespace ::Microsoft::Terminal::Core;
using namespace ::Microsoft::Console::VirtualTerminal;
// NOTE:
// Functions related to Set Graphics Renditions (SGR) are in
// TerminalDispatchGraphics.cpp, not this file
TerminalDispatch::TerminalDispatch(ITerminalApi& terminalApi) noexcept :
_terminalApi{ terminalApi }
{
}
void TerminalDispatch::Execute(const wchar_t wchControl) noexcept
{
_terminalApi.ExecuteChar(wchControl);
}
void TerminalDispatch::Print(const wchar_t wchPrintable) noexcept
{
_terminalApi.PrintString({ &wchPrintable, 1 });
}
void TerminalDispatch::PrintString(const std::wstring_view string) noexcept
{
_terminalApi.PrintString(string);
}
bool TerminalDispatch::CursorPosition(const size_t line,
const size_t column) noexcept
try
{
SHORT x{ 0 };
SHORT y{ 0 };
RETURN_BOOL_IF_FALSE(SUCCEEDED(SizeTToShort(column, &x)) &&
SUCCEEDED(SizeTToShort(line, &y)));
RETURN_BOOL_IF_FALSE(SUCCEEDED(ShortSub(x, 1, &x)) &&
SUCCEEDED(ShortSub(y, 1, &y)));
return _terminalApi.SetCursorPosition(x, y);
}
CATCH_LOG_RETURN_FALSE()
bool TerminalDispatch::CursorVisibility(const bool isVisible) noexcept
{
return _terminalApi.SetCursorVisibility(isVisible);
}
bool TerminalDispatch::EnableCursorBlinking(const bool enable) noexcept
{
return _terminalApi.EnableCursorBlinking(enable);
}
bool TerminalDispatch::CursorForward(const size_t distance) noexcept
try
{
const auto cursorPos = _terminalApi.GetCursorPosition();
const COORD newCursorPos{ cursorPos.X + gsl::narrow<short>(distance), cursorPos.Y };
return _terminalApi.SetCursorPosition(newCursorPos.X, newCursorPos.Y);
}
CATCH_LOG_RETURN_FALSE()
bool TerminalDispatch::CursorBackward(const size_t distance) noexcept
try
{
const auto cursorPos = _terminalApi.GetCursorPosition();
const COORD newCursorPos{ cursorPos.X - gsl::narrow<short>(distance), cursorPos.Y };
return _terminalApi.SetCursorPosition(newCursorPos.X, newCursorPos.Y);
}
CATCH_LOG_RETURN_FALSE()
bool TerminalDispatch::CursorUp(const size_t distance) noexcept
try
{
const auto cursorPos = _terminalApi.GetCursorPosition();
const COORD newCursorPos{ cursorPos.X, cursorPos.Y + gsl::narrow<short>(distance) };
return _terminalApi.SetCursorPosition(newCursorPos.X, newCursorPos.Y);
}
CATCH_LOG_RETURN_FALSE()
bool TerminalDispatch::LineFeed(const DispatchTypes::LineFeedType lineFeedType) noexcept
try
{
switch (lineFeedType)
{
case DispatchTypes::LineFeedType::DependsOnMode:
// There is currently no need for mode-specific line feeds in the Terminal,
// so for now we just treat them as a line feed without carriage return.
case DispatchTypes::LineFeedType::WithoutReturn:
return _terminalApi.CursorLineFeed(false);
case DispatchTypes::LineFeedType::WithReturn:
return _terminalApi.CursorLineFeed(true);
default:
return false;
}
}
CATCH_LOG_RETURN_FALSE()
bool TerminalDispatch::EraseCharacters(const size_t numChars) noexcept
try
{
return _terminalApi.EraseCharacters(numChars);
}
CATCH_LOG_RETURN_FALSE()
bool TerminalDispatch::WarningBell() noexcept
try
{
return _terminalApi.WarningBell();
}
CATCH_LOG_RETURN_FALSE()
bool TerminalDispatch::CarriageReturn() noexcept
try
{
const auto cursorPos = _terminalApi.GetCursorPosition();
return _terminalApi.SetCursorPosition(0, cursorPos.Y);
}
CATCH_LOG_RETURN_FALSE()
bool TerminalDispatch::SetWindowTitle(std::wstring_view title) noexcept
try
{
return _terminalApi.SetWindowTitle(title);
}
CATCH_LOG_RETURN_FALSE()
bool TerminalDispatch::HorizontalTabSet() noexcept
{
const auto width = _terminalApi.GetBufferSize().Dimensions().X;
const auto column = _terminalApi.GetCursorPosition().X;
_InitTabStopsForWidth(width);
_tabStopColumns.at(column) = true;
return true;
}
bool TerminalDispatch::ForwardTab(const size_t numTabs) noexcept
{
const auto width = _terminalApi.GetBufferSize().Dimensions().X;
const auto cursorPosition = _terminalApi.GetCursorPosition();
auto column = cursorPosition.X;
const auto row = cursorPosition.Y;
auto tabsPerformed = 0u;
_InitTabStopsForWidth(width);
while (column + 1 < width && tabsPerformed < numTabs)
{
column++;
if (til::at(_tabStopColumns, column))
{
tabsPerformed++;
}
}
return _terminalApi.SetCursorPosition(column, row);
}
bool TerminalDispatch::BackwardsTab(const size_t numTabs) noexcept
{
const auto width = _terminalApi.GetBufferSize().Dimensions().X;
const auto cursorPosition = _terminalApi.GetCursorPosition();
auto column = cursorPosition.X;
const auto row = cursorPosition.Y;
auto tabsPerformed = 0u;
_InitTabStopsForWidth(width);
while (column > 0 && tabsPerformed < numTabs)
{
column--;
if (til::at(_tabStopColumns, column))
{
tabsPerformed++;
}
}
return _terminalApi.SetCursorPosition(column, row);
}
bool TerminalDispatch::TabClear(const DispatchTypes::TabClearType clearType) noexcept
{
bool success = false;
switch (clearType)
{
case DispatchTypes::TabClearType::ClearCurrentColumn:
success = _ClearSingleTabStop();
break;
case DispatchTypes::TabClearType::ClearAllColumns:
success = _ClearAllTabStops();
break;
default:
success = false;
break;
}
return success;
}
// Method Description:
// - Sets a single entry of the colortable to a new value
// Arguments:
// - tableIndex: The VT color table index
// - color: The new RGB color value to use.
// Return Value:
// True if handled successfully. False otherwise.
bool TerminalDispatch::SetColorTableEntry(const size_t tableIndex,
const DWORD color) noexcept
try
{
return _terminalApi.SetColorTableEntry(tableIndex, color);
}
CATCH_LOG_RETURN_FALSE()
bool TerminalDispatch::SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle) noexcept
try
{
return _terminalApi.SetCursorStyle(cursorStyle);
}
CATCH_LOG_RETURN_FALSE()
bool TerminalDispatch::SetCursorColor(const DWORD color) noexcept
try
{
return _terminalApi.SetCursorColor(color);
}
CATCH_LOG_RETURN_FALSE()
bool TerminalDispatch::SetClipboard(std::wstring_view content) noexcept
try
{
return _terminalApi.CopyToClipboard(content);
}
CATCH_LOG_RETURN_FALSE()
// Method Description:
// - Sets the default foreground color to a new value
// Arguments:
// - color: The new RGB color value to use, in 0x00BBGGRR form
// Return Value:
// True if handled successfully. False otherwise.
bool TerminalDispatch::SetDefaultForeground(const DWORD color) noexcept
try
{
return _terminalApi.SetDefaultForeground(color);
}
CATCH_LOG_RETURN_FALSE()
// Method Description:
// - Sets the default background color to a new value
// Arguments:
// - color: The new RGB color value to use, in 0x00BBGGRR form
// Return Value:
// True if handled successfully. False otherwise.
bool TerminalDispatch::SetDefaultBackground(const DWORD color) noexcept
try
{
return _terminalApi.SetDefaultBackground(color);
}
CATCH_LOG_RETURN_FALSE()
// Method Description:
// - Erases characters in the buffer depending on the erase type
// Arguments:
// - eraseType: the erase type (from beginning, to end, or all)
// Return Value:
// True if handled successfully. False otherwise.
bool TerminalDispatch::EraseInLine(const DispatchTypes::EraseType eraseType) noexcept
try
{
return _terminalApi.EraseInLine(eraseType);
}
CATCH_LOG_RETURN_FALSE()
// Method Description:
// - Deletes count number of characters starting from where the cursor is currently
// Arguments:
// - count, the number of characters to delete
// Return Value:
// True if handled successfully. False otherwise.
bool TerminalDispatch::DeleteCharacter(const size_t count) noexcept
try
{
return _terminalApi.DeleteCharacter(count);
}
CATCH_LOG_RETURN_FALSE()
// Method Description:
// - Adds count number of spaces starting from where the cursor is currently
// Arguments:
// - count, the number of spaces to add
// Return Value:
// True if handled successfully, false otherwise
bool TerminalDispatch::InsertCharacter(const size_t count) noexcept
try
{
return _terminalApi.InsertCharacter(count);
}
CATCH_LOG_RETURN_FALSE()
// Method Description:
// - Moves the viewport and erases text from the buffer depending on the eraseType
// Arguments:
// - eraseType: the desired erase type
// Return Value:
// True if handled successfully. False otherwise
bool TerminalDispatch::EraseInDisplay(const DispatchTypes::EraseType eraseType) noexcept
try
{
return _terminalApi.EraseInDisplay(eraseType);
}
CATCH_LOG_RETURN_FALSE()
// - DECKPAM, DECKPNM - Sets the keypad input mode to either Application mode or Numeric mode (true, false respectively)
// Arguments:
// - applicationMode - set to true to enable Application Mode Input, false for Numeric Mode Input.
// Return Value:
// - True if handled successfully. False otherwise.
bool TerminalDispatch::SetKeypadMode(const bool applicationMode) noexcept
{
_terminalApi.SetInputMode(TerminalInput::Mode::Keypad, applicationMode);
return true;
}
// - DECCKM - Sets the cursor keys input mode to either Application mode or Normal mode (true, false respectively)
// Arguments:
// - applicationMode - set to true to enable Application Mode Input, false for Normal Mode Input.
// Return Value:
// - True if handled successfully. False otherwise.
bool TerminalDispatch::SetCursorKeysMode(const bool applicationMode) noexcept
{
_terminalApi.SetInputMode(TerminalInput::Mode::CursorKey, applicationMode);
return true;
}
// Routine Description:
// - DECSCNM - Sets the screen mode to either normal or reverse.
// When in reverse screen mode, the background and foreground colors are switched.
// Arguments:
// - reverseMode - set to true to enable reverse screen mode, false for normal mode.
// Return Value:
// - True if handled successfully. False otherwise.
bool TerminalDispatch::SetScreenMode(const bool reverseMode) noexcept
{
return _terminalApi.SetScreenMode(reverseMode);
}
// Method Description:
// - win32-input-mode: Enable sending full input records encoded as a string of
// characters to the client application.
// Arguments:
// - win32InputMode - set to true to enable win32-input-mode, false to disable.
// Return Value:
// - True if handled successfully. False otherwise.
bool TerminalDispatch::EnableWin32InputMode(const bool win32Mode) noexcept
{
_terminalApi.SetInputMode(TerminalInput::Mode::Win32, win32Mode);
return true;
}
//Routine Description:
// Enable VT200 Mouse Mode - Enables/disables the mouse input handler in default tracking mode.
//Arguments:
// - enabled - true to enable, false to disable.
// Return value:
// True if handled successfully. False otherwise.
bool TerminalDispatch::EnableVT200MouseMode(const bool enabled) noexcept
{
_terminalApi.SetInputMode(TerminalInput::Mode::DefaultMouseTracking, enabled);
return true;
}
//Routine Description:
// Enable UTF-8 Extended Encoding - this changes the encoding scheme for sequences
// emitted by the mouse input handler. Does not enable/disable mouse mode on its own.
//Arguments:
// - enabled - true to enable, false to disable.
// Return value:
// True if handled successfully. False otherwise.
bool TerminalDispatch::EnableUTF8ExtendedMouseMode(const bool enabled) noexcept
{
_terminalApi.SetInputMode(TerminalInput::Mode::Utf8MouseEncoding, enabled);
return true;
}
//Routine Description:
// Enable SGR Extended Encoding - this changes the encoding scheme for sequences
// emitted by the mouse input handler. Does not enable/disable mouse mode on its own.
//Arguments:
// - enabled - true to enable, false to disable.
// Return value:
// True if handled successfully. False otherwise.
bool TerminalDispatch::EnableSGRExtendedMouseMode(const bool enabled) noexcept
{
_terminalApi.SetInputMode(TerminalInput::Mode::SgrMouseEncoding, enabled);
return true;
}
//Routine Description:
// Enable Button Event mode - send mouse move events WITH A BUTTON PRESSED to the input.
//Arguments:
// - enabled - true to enable, false to disable.
// Return value:
// True if handled successfully. False otherwise.
bool TerminalDispatch::EnableButtonEventMouseMode(const bool enabled) noexcept
{
_terminalApi.SetInputMode(TerminalInput::Mode::ButtonEventMouseTracking, enabled);
return true;
}
//Routine Description:
// Enable Any Event mode - send all mouse events to the input.
//Arguments:
// - enabled - true to enable, false to disable.
// Return value:
// True if handled successfully. False otherwise.
bool TerminalDispatch::EnableAnyEventMouseMode(const bool enabled) noexcept
{
_terminalApi.SetInputMode(TerminalInput::Mode::AnyEventMouseTracking, enabled);
return true;
}
//Routine Description:
// Enable Alternate Scroll Mode - When in the Alt Buffer, send CUP and CUD on
// scroll up/down events instead of the usual sequences
//Arguments:
// - enabled - true to enable, false to disable.
// Return value:
// True if handled successfully. False otherwise.
bool TerminalDispatch::EnableAlternateScroll(const bool enabled) noexcept
{
_terminalApi.SetInputMode(TerminalInput::Mode::AlternateScroll, enabled);
return true;
}
//Routine Description:
// Enable Bracketed Paste Mode - this changes the behavior of pasting.
// See: https://www.xfree86.org/current/ctlseqs.html#Bracketed%20Paste%20Mode
//Arguments:
// - enabled - true to enable, false to disable.
// Return value:
// True if handled successfully. False otherwise.
bool TerminalDispatch::EnableXtermBracketedPasteMode(const bool enabled) noexcept
{
_terminalApi.EnableXtermBracketedPasteMode(enabled);
return true;
}
bool TerminalDispatch::SetMode(const DispatchTypes::ModeParams param) noexcept
{
return _ModeParamsHelper(param, true);
}
bool TerminalDispatch::ResetMode(const DispatchTypes::ModeParams param) noexcept
{
return _ModeParamsHelper(param, false);
}
// Method Description:
// - Start a hyperlink
// Arguments:
// - uri - the hyperlink URI
// - params - the optional custom ID
// Return Value:
// - true
bool TerminalDispatch::AddHyperlink(const std::wstring_view uri, const std::wstring_view params) noexcept
{
return _terminalApi.AddHyperlink(uri, params);
}
// Method Description:
// - End a hyperlink
// Return Value:
// - true
bool TerminalDispatch::EndHyperlink() noexcept
{
return _terminalApi.EndHyperlink();
}
// Method Description:
// - Performs a ConEmu action
// - Currently, the only action we support is setting the taskbar state/progress
// Arguments:
// - string: contains the parameters that define which action we do
// Return Value:
// - true
bool TerminalDispatch::DoConEmuAction(const std::wstring_view string) noexcept
{
unsigned int state = 0;
unsigned int progress = 0;
const auto parts = Utils::SplitString(string, L';');
unsigned int subParam = 0;
if (parts.size() < 1 || !Utils::StringToUint(til::at(parts, 0), subParam))
{
return false;
}
// 4 is SetProgressBar, which sets the taskbar state/progress.
if (subParam == 4)
{
if (parts.size() >= 2)
{
// A state parameter is defined, parse it out
const auto stateSuccess = Utils::StringToUint(til::at(parts, 1), state);
if (!stateSuccess && !til::at(parts, 1).empty())
{
return false;
}
if (parts.size() >= 3)
{
// A progress parameter is also defined, parse it out
const auto progressSuccess = Utils::StringToUint(til::at(parts, 2), progress);
if (!progressSuccess && !til::at(parts, 2).empty())
{
return false;
}
}
}
if (state > TaskbarMaxState)
{
// state is out of bounds, return false
return false;
}
if (progress > TaskbarMaxProgress)
{
// progress is greater than the maximum allowed value, clamp it to the max
progress = TaskbarMaxProgress;
}
return _terminalApi.SetTaskbarProgress(static_cast<DispatchTypes::TaskbarState>(state), progress);
}
// 9 is SetWorkingDirectory, which informs the terminal about the current working directory.
else if (subParam == 9)
{
if (parts.size() >= 2)
{
const auto path = til::at(parts, 1);
// The path should be surrounded with '"' according to the documentation of ConEmu.
// An example: 9;"D:/"
if (path.at(0) == L'"' && path.at(path.size() - 1) == L'"' && path.size() >= 3)
{
return _terminalApi.SetWorkingDirectory(path.substr(1, path.size() - 2));
}
else
{
// If we fail to find the surrounding quotation marks, we'll give the path a try anyway.
// ConEmu also does this.
return _terminalApi.SetWorkingDirectory(path);
}
}
}
return false;
}
// Routine Description:
// - Support routine for routing private mode parameters to be set/reset as flags
// Arguments:
// - param - mode parameter to set/reset
// - enable - True for set, false for unset.
// Return Value:
// - True if handled successfully. False otherwise.
bool TerminalDispatch::_ModeParamsHelper(const DispatchTypes::ModeParams param, const bool enable) noexcept
{
bool success = false;
switch (param)
{
case DispatchTypes::ModeParams::DECCKM_CursorKeysMode:
// set - Enable Application Mode, reset - Normal mode
success = SetCursorKeysMode(enable);
break;
case DispatchTypes::ModeParams::DECSCNM_ScreenMode:
success = SetScreenMode(enable);
break;
case DispatchTypes::ModeParams::VT200_MOUSE_MODE:
success = EnableVT200MouseMode(enable);
break;
case DispatchTypes::ModeParams::BUTTON_EVENT_MOUSE_MODE:
success = EnableButtonEventMouseMode(enable);
break;
case DispatchTypes::ModeParams::ANY_EVENT_MOUSE_MODE:
success = EnableAnyEventMouseMode(enable);
break;
case DispatchTypes::ModeParams::UTF8_EXTENDED_MODE:
success = EnableUTF8ExtendedMouseMode(enable);
break;
case DispatchTypes::ModeParams::SGR_EXTENDED_MODE:
success = EnableSGRExtendedMouseMode(enable);
break;
case DispatchTypes::ModeParams::ALTERNATE_SCROLL:
success = EnableAlternateScroll(enable);
break;
case DispatchTypes::ModeParams::DECTCEM_TextCursorEnableMode:
success = CursorVisibility(enable);
break;
case DispatchTypes::ModeParams::ATT610_StartCursorBlink:
success = EnableCursorBlinking(enable);
break;
case DispatchTypes::ModeParams::XTERM_BracketedPasteMode:
success = EnableXtermBracketedPasteMode(enable);
break;
case DispatchTypes::ModeParams::W32IM_Win32InputMode:
success = EnableWin32InputMode(enable);
break;
default:
// If no functions to call, overall dispatch was a failure.
success = false;
break;
}
return success;
}
bool TerminalDispatch::_ClearSingleTabStop() noexcept
{
const auto width = _terminalApi.GetBufferSize().Dimensions().X;
const auto column = _terminalApi.GetCursorPosition().X;
_InitTabStopsForWidth(width);
_tabStopColumns.at(column) = false;
return true;
}
bool TerminalDispatch::_ClearAllTabStops() noexcept
{
_tabStopColumns.clear();
_initDefaultTabStops = false;
return true;
}
void TerminalDispatch::_ResetTabStops() noexcept
{
_tabStopColumns.clear();
_initDefaultTabStops = true;
}
void TerminalDispatch::_InitTabStopsForWidth(const size_t width)
{
const auto initialWidth = _tabStopColumns.size();
if (width > initialWidth)
{
_tabStopColumns.resize(width);
if (_initDefaultTabStops)
{
for (auto column = 8u; column < _tabStopColumns.size(); column += 8)
{
if (column >= initialWidth)
{
til::at(_tabStopColumns, column) = true;
}
}
}
}
}
bool TerminalDispatch::SoftReset() noexcept
{
// TODO:GH#1883 much of this method is not yet implemented in the Terminal,
// because the Terminal _doesn't need to_ yet. The terminal is only ever
// connected to conpty, so it doesn't implement most of these things that
// Hard/Soft Reset would reset. As those things are implemented, they should
// also get cleared here.
//
// This code is left here (from its original form in conhost) as a reminder
// of what needs to be done.
bool success = CursorVisibility(true); // Cursor enabled.
// success = SetOriginMode(false) && success; // Absolute cursor addressing.
// success = SetAutoWrapMode(true) && success; // Wrap at end of line.
success = SetCursorKeysMode(false) && success; // Normal characters.
success = SetKeypadMode(false) && success; // Numeric characters.
// // Top margin = 1; bottom margin = page length.
// success = _DoSetTopBottomScrollingMargins(0, 0) && success;
// _termOutput = {}; // Reset all character set designations.
// if (_initialCodePage.has_value())
// {
// // Restore initial code page if previously changed by a DOCS sequence.
// success = _pConApi->SetConsoleOutputCP(_initialCodePage.value()) && success;
// }
success = SetGraphicsRendition({}) && success; // Normal rendition.
// // Reset the saved cursor state.
// // Note that XTerm only resets the main buffer state, but that
// // seems likely to be a bug. Most other terminals reset both.
// _savedCursorState.at(0) = {}; // Main buffer
// _savedCursorState.at(1) = {}; // Alt buffer
return success;
}
bool TerminalDispatch::HardReset() noexcept
{
// TODO:GH#1883 much of this method is not yet implemented in the Terminal,
// because the Terminal _doesn't need to_ yet. The terminal is only ever
// connected to conpty, so it doesn't implement most of these things that
// Hard/Soft Reset would reset. As those things ar implemented, they should
// also get cleared here.
//
// This code is left here (from its original form in conhost) as a reminder
// of what needs to be done.
bool success = true;
// // If in the alt buffer, switch back to main before doing anything else.
// if (_usingAltBuffer)
// {
// success = _pConApi->PrivateUseMainScreenBuffer();
// _usingAltBuffer = !success;
// }
// Sets the SGR state to normal - this must be done before EraseInDisplay
// to ensure that it clears with the default background color.
success = SoftReset() && success;
// Clears the screen - Needs to be done in two operations.
success = EraseInDisplay(DispatchTypes::EraseType::All) && success;
success = EraseInDisplay(DispatchTypes::EraseType::Scrollback) && success;
// Set the DECSCNM screen mode back to normal.
success = SetScreenMode(false) && success;
// Cursor to 1,1 - the Soft Reset guarantees this is absolute
success = CursorPosition(1, 1) && success;
// Reset the mouse mode
success = EnableSGRExtendedMouseMode(false) && success;
success = EnableAnyEventMouseMode(false) && success;
// Delete all current tab stops and reapply
_ResetTabStops();
return success;
}