terminal/src/cascadia/TerminalCore/TerminalDispatch.cpp

745 lines
24 KiB
C++
Raw Normal View History

// 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()
Add support for all the line feed control sequences (#3271) ## Summary of the Pull Request This adds support for the `FF` (form feed) and `VT` (vertical tab) [control characters](https://vt100.net/docs/vt510-rm/chapter4.html#T4-1), as well as the [`NEL` (Next Line)](https://vt100.net/docs/vt510-rm/NEL.html) and [`IND` (Index)](https://vt100.net/docs/vt510-rm/IND.html) escape sequences. ## References #976 discusses the conflict between VT100 Index sequence and the VT52 cursor back sequence. ## PR Checklist * [x] Closes #3189 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed * [ ] Requires documentation to be updated * [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #3189 ## Detailed Description of the Pull Request / Additional comments I've added a `LineFeed` method to the `ITermDispatch` interface, with an enum parameter specifying the required line feed type (i.e. with carriage return, without carriage return, or dependent on the [`LNM` mode](https://vt100.net/docs/vt510-rm/LNM.html)). The output state machine can then call that method to handle the various line feed control characters (parsed in the `ActionExecute` method), as well the `NEL` and `IND` escape sequences (parsed in the `ActionEscDispatch` method). The `AdaptDispatch` implementation of `LineFeed` then forwards the call to a new `PrivateLineFeed` method in the `ConGetSet` interface, which simply takes a bool parameter specifying whether a carriage return is required or not. In the case of mode-dependent line feeds, the `AdaptDispatch` implementation determines whether the return is necessary or not, based on the existing _AutoReturnOnNewLine_ setting (which I'm obtaining via another new `PrivateGetLineFeedMode` method). Ultimately we'll want to support changing the mode via the [`LNM` escape sequence](https://vt100.net/docs/vt510-rm/LNM.html), but there's no urgent need for that now. And using the existing _AutoReturnOnNewLine_ setting as a substitute for the mode gives us backwards compatible behaviour, since that will be true for the Windows shells (which expect a linefeed to also generate a carriage return), and false in a WSL bash shell (which won't want the carriage return by default). As for the actual `PrivateLineFeed` implementation, that is just a simplified version of how the line feed would previously have been executed in the `WriteCharsLegacy` function. This includes setting the cursor to "On" (with `Cursor::SetIsOn`), potentially clearing the wrap property of the line being left (with `CharRow::SetWrapForced` false), and then setting the new position using `AdjustCursorPosition` with the _fKeepCursorVisible_ parameter set to false. I'm unsure whether the `SetIsOn` call is really necessary, and I think the way the forced wrap is handled needs a rethink in general, but for now this should at least be compatible with the existing behaviour. Finally, in order to make this all work in the _Windows Terminal_ app, I also had to add a basic implementation of the `ITermDispatch::LineFeed` method in the `TerminalDispatch` class. There is currently no need to support mode-specific line feeds here, so this simply forwards a `\n` or `\r\n` to the `Execute` method, which is ultimately handled by the `Terminal::_WriteBuffer` implementation. ## Validation Steps Performed I've added output engine tests which confirm that the various control characters and escape sequences trigger the dispatch method correctly. Then I've added adapter tests which confirm the various dispatch options trigger the `PrivateLineFeed` API correctly. And finally I added some screen buffer tests that check the actual results of the `NEL` and `IND` sequences, which covers both forms of the `PrivateLineFeed` API (i.e. with and without a carriage return). I've also run the _Test of cursor movements_ in the [Vttest](https://invisible-island.net/vttest/) utility, and confirmed that screens 1, 2, and 5 are now working correctly. The first two depend on `NEL` and `IND` being supported, and screen 5 requires the `VT` control character.
2020-01-15 14:41:55 +01:00
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:
Remove unneeded VT-specific control character handling (#4289) ## Summary of the Pull Request This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason. ## References This is a followup to PR #4171 ## PR Checklist * [x] Closes #3971 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be updated * [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435 ## Detailed Description of the Pull Request / Additional comments There are four changes to the `WriteCharsLegacy` implementation: 1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971. 2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version. 3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled. 4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line. Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR. Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private. ## Validation Steps Performed I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 20:18:46 +01:00
return _terminalApi.CursorLineFeed(false);
Add support for all the line feed control sequences (#3271) ## Summary of the Pull Request This adds support for the `FF` (form feed) and `VT` (vertical tab) [control characters](https://vt100.net/docs/vt510-rm/chapter4.html#T4-1), as well as the [`NEL` (Next Line)](https://vt100.net/docs/vt510-rm/NEL.html) and [`IND` (Index)](https://vt100.net/docs/vt510-rm/IND.html) escape sequences. ## References #976 discusses the conflict between VT100 Index sequence and the VT52 cursor back sequence. ## PR Checklist * [x] Closes #3189 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed * [ ] Requires documentation to be updated * [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #3189 ## Detailed Description of the Pull Request / Additional comments I've added a `LineFeed` method to the `ITermDispatch` interface, with an enum parameter specifying the required line feed type (i.e. with carriage return, without carriage return, or dependent on the [`LNM` mode](https://vt100.net/docs/vt510-rm/LNM.html)). The output state machine can then call that method to handle the various line feed control characters (parsed in the `ActionExecute` method), as well the `NEL` and `IND` escape sequences (parsed in the `ActionEscDispatch` method). The `AdaptDispatch` implementation of `LineFeed` then forwards the call to a new `PrivateLineFeed` method in the `ConGetSet` interface, which simply takes a bool parameter specifying whether a carriage return is required or not. In the case of mode-dependent line feeds, the `AdaptDispatch` implementation determines whether the return is necessary or not, based on the existing _AutoReturnOnNewLine_ setting (which I'm obtaining via another new `PrivateGetLineFeedMode` method). Ultimately we'll want to support changing the mode via the [`LNM` escape sequence](https://vt100.net/docs/vt510-rm/LNM.html), but there's no urgent need for that now. And using the existing _AutoReturnOnNewLine_ setting as a substitute for the mode gives us backwards compatible behaviour, since that will be true for the Windows shells (which expect a linefeed to also generate a carriage return), and false in a WSL bash shell (which won't want the carriage return by default). As for the actual `PrivateLineFeed` implementation, that is just a simplified version of how the line feed would previously have been executed in the `WriteCharsLegacy` function. This includes setting the cursor to "On" (with `Cursor::SetIsOn`), potentially clearing the wrap property of the line being left (with `CharRow::SetWrapForced` false), and then setting the new position using `AdjustCursorPosition` with the _fKeepCursorVisible_ parameter set to false. I'm unsure whether the `SetIsOn` call is really necessary, and I think the way the forced wrap is handled needs a rethink in general, but for now this should at least be compatible with the existing behaviour. Finally, in order to make this all work in the _Windows Terminal_ app, I also had to add a basic implementation of the `ITermDispatch::LineFeed` method in the `TerminalDispatch` class. There is currently no need to support mode-specific line feeds here, so this simply forwards a `\n` or `\r\n` to the `Execute` method, which is ultimately handled by the `Terminal::_WriteBuffer` implementation. ## Validation Steps Performed I've added output engine tests which confirm that the various control characters and escape sequences trigger the dispatch method correctly. Then I've added adapter tests which confirm the various dispatch options trigger the `PrivateLineFeed` API correctly. And finally I added some screen buffer tests that check the actual results of the `NEL` and `IND` sequences, which covers both forms of the `PrivateLineFeed` API (i.e. with and without a carriage return). I've also run the _Test of cursor movements_ in the [Vttest](https://invisible-island.net/vttest/) utility, and confirmed that screens 1, 2, and 5 are now working correctly. The first two depend on `NEL` and `IND` being supported, and screen 5 requires the `VT` control character.
2020-01-15 14:41:55 +01:00
case DispatchTypes::LineFeedType::WithReturn:
Remove unneeded VT-specific control character handling (#4289) ## Summary of the Pull Request This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason. ## References This is a followup to PR #4171 ## PR Checklist * [x] Closes #3971 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be updated * [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435 ## Detailed Description of the Pull Request / Additional comments There are four changes to the `WriteCharsLegacy` implementation: 1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971. 2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version. 3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled. 4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line. Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR. Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private. ## Validation Steps Performed I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 20:18:46 +01:00
return _terminalApi.CursorLineFeed(true);
Add support for all the line feed control sequences (#3271) ## Summary of the Pull Request This adds support for the `FF` (form feed) and `VT` (vertical tab) [control characters](https://vt100.net/docs/vt510-rm/chapter4.html#T4-1), as well as the [`NEL` (Next Line)](https://vt100.net/docs/vt510-rm/NEL.html) and [`IND` (Index)](https://vt100.net/docs/vt510-rm/IND.html) escape sequences. ## References #976 discusses the conflict between VT100 Index sequence and the VT52 cursor back sequence. ## PR Checklist * [x] Closes #3189 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed * [ ] Requires documentation to be updated * [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #3189 ## Detailed Description of the Pull Request / Additional comments I've added a `LineFeed` method to the `ITermDispatch` interface, with an enum parameter specifying the required line feed type (i.e. with carriage return, without carriage return, or dependent on the [`LNM` mode](https://vt100.net/docs/vt510-rm/LNM.html)). The output state machine can then call that method to handle the various line feed control characters (parsed in the `ActionExecute` method), as well the `NEL` and `IND` escape sequences (parsed in the `ActionEscDispatch` method). The `AdaptDispatch` implementation of `LineFeed` then forwards the call to a new `PrivateLineFeed` method in the `ConGetSet` interface, which simply takes a bool parameter specifying whether a carriage return is required or not. In the case of mode-dependent line feeds, the `AdaptDispatch` implementation determines whether the return is necessary or not, based on the existing _AutoReturnOnNewLine_ setting (which I'm obtaining via another new `PrivateGetLineFeedMode` method). Ultimately we'll want to support changing the mode via the [`LNM` escape sequence](https://vt100.net/docs/vt510-rm/LNM.html), but there's no urgent need for that now. And using the existing _AutoReturnOnNewLine_ setting as a substitute for the mode gives us backwards compatible behaviour, since that will be true for the Windows shells (which expect a linefeed to also generate a carriage return), and false in a WSL bash shell (which won't want the carriage return by default). As for the actual `PrivateLineFeed` implementation, that is just a simplified version of how the line feed would previously have been executed in the `WriteCharsLegacy` function. This includes setting the cursor to "On" (with `Cursor::SetIsOn`), potentially clearing the wrap property of the line being left (with `CharRow::SetWrapForced` false), and then setting the new position using `AdjustCursorPosition` with the _fKeepCursorVisible_ parameter set to false. I'm unsure whether the `SetIsOn` call is really necessary, and I think the way the forced wrap is handled needs a rethink in general, but for now this should at least be compatible with the existing behaviour. Finally, in order to make this all work in the _Windows Terminal_ app, I also had to add a basic implementation of the `ITermDispatch::LineFeed` method in the `TerminalDispatch` class. There is currently no need to support mode-specific line feeds here, so this simply forwards a `\n` or `\r\n` to the `Execute` method, which is ultimately handled by the `Terminal::_WriteBuffer` implementation. ## Validation Steps Performed I've added output engine tests which confirm that the various control characters and escape sequences trigger the dispatch method correctly. Then I've added adapter tests which confirm the various dispatch options trigger the `PrivateLineFeed` API correctly. And finally I added some screen buffer tests that check the actual results of the `NEL` and `IND` sequences, which covers both forms of the `PrivateLineFeed` API (i.e. with and without a carriage return). I've also run the _Test of cursor movements_ in the [Vttest](https://invisible-island.net/vttest/) utility, and confirmed that screens 1, 2, and 5 are now working correctly. The first two depend on `NEL` and `IND` being supported, and screen 5 requires the `VT` control character.
2020-01-15 14:41:55 +01:00
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()
Dispatch more C0 control characters from the VT state machine (#4171) This commit moves the handling of the `BEL`, `BS`, `TAB`, and `CR` controls characters into the state machine (when in VT mode), instead of forwarding them on to the default string writer, which would otherwise have to parse them out all over again. This doesn't cover all the control characters, but `ESC`, `SUB`, and `CAN` are already an integral part of the `StateMachine` itself; `NUL` is filtered out by the `OutputStateMachineEngine`; and `LF`, `FF`, and `VT` are due to be implemented as part of PR #3271. Once all of these controls are handled at the state machine level, we can strip out all the VT-specific code from the `WriteCharsLegacy` function, which should simplify it considerably. This would also let us simplify the `Terminal::_WriteBuffer` implementation, and the planned replacement stream writer for issue #780. On the conhost side, the implementation is handled as follows: * The `BS` control is dispatched to the existing `CursorBackward` method, with a distance of 1. * The `TAB` control is dispatched to the existing `ForwardTab` method, with a tab count of 1. * The `CR` control required a new dispatch method, but the implementation was a simple call to the new `_CursorMovePosition` method from PR #3628. * The `BEL` control also required a new dispatch method, as well as an additional private API in the `ConGetSet` interface. But that's mostly boilerplate code - ultimately it just calls the `SendNotifyBeep` method. On the Windows Terminal side, not all dispatch methods are implemented. * There is an existing `CursorBackward` implementation, so `BS` works OK. * There isn't a `ForwardTab` implementation, but `TAB` isn't currently required by the conpty protocol. * I had to implement the `CarriageReturn` dispatch method, but that was a simple call to `Terminal::SetCursorPosition`. * The `WarningBell` method I've left unimplemented, because that functionality wasn't previously supported anyway, and there's an existing issue for that (#4046). ## Validation Steps Performed I've added a state machine test to confirm that the updated control characters are now forwarded to the appropriate dispatch handlers. But since the actual implementation is mostly relying on existing functionality, I'm assuming that code is already adequately tested elsewhere. That said, I have also run various manual tests of my own, and confirmed that everything still worked as well as before. References #3271 References #780 References #3628 References #4046
2020-01-17 02:43:21 +01:00
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.
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 23:12:22 +02:00
bool TerminalDispatch::SetKeypadMode(const bool applicationMode) noexcept
{
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 23:12:22 +02:00
_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
{
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 23:12:22 +02:00
_terminalApi.SetInputMode(TerminalInput::Mode::CursorKey, applicationMode);
return true;
}
Add support for DECSCNM in Windows Terminal (#6809) ## Summary of the Pull Request This PR adds full support for the `DECSCNM` reverse screen mode in the Windows Terminal to align with the implementation in conhost. ## References * The conhost implementation of `DECSCNM` was in PR #3817. * WT originally inherited that functionality via the colors being passed through, but that behaviour was lost in PR #6506. ## PR Checklist * [x] Closes #6622 * [x] CLA signed. * [ ] Tests added/passed * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [ ] Schema updated. * [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #6622 ## Detailed Description of the Pull Request / Additional comments The `AdaptDispatch::SetScreenMode` now checks if it's in conpty mode and simply returns false to force a pass-through of the mode change. And the `TerminalDispatch` now has its own `SetScreenMode` implementation that tracks any changes to the reversed state, and triggers a redraw in the renderer. To make the renderer work, we just needed to update the `GetForegroundColor` and `GetBackgroundColor` methods of the terminal's `IRenderData` implementation to check the reversed state, and switch the colors being calculated, the same way the `LookupForegroundColor` and `LookupBackgroundColor` methods work in the conhost `Settings` class. ## Validation Steps Performed I've manually tested the `DECSCNM` functionality for Windows Terminal in Vttest, and also with some of my own test scripts.
2020-07-09 13:25:30 +02:00
// 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
{
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 23:12:22 +02:00
_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
{
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 23:12:22 +02:00
_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
{
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 23:12:22 +02:00
_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
{
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 23:12:22 +02:00
_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
{
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 23:12:22 +02:00
_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
{
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 23:12:22 +02:00
_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
{
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 23:12:22 +02:00
_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);
}
OSC 8 support for conhost and terminal (#7251) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Conhost can now support OSC8 sequences (as specified [here](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda)). Terminal also supports those sequences and additionally hyperlinks can be opened by Ctrl+LeftClicking on them. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #204 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [X] Closes #204 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [ ] Schema updated. * [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Added support to: - parse OSC8 sequences and extract URIs from them (conhost and terminal) - add hyperlink uri data to textbuffer/screeninformation, associated with a hyperlink id (conhost and terminal) - attach hyperlink ids to text to allow for uri extraction from the textbuffer/screeninformation (conhost and terminal) - process ctrl+leftclick to open a hyperlink in the clicked region if present <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Open up a PowerShell tab and type ```PowerShell ${ESC}=[char]27 Write-Host "${ESC}]8;;https://github.com/microsoft/terminal${ESC}\This is a link!${ESC}]8;;${ESC}\" ``` Ctrl+LeftClick on the link correctly brings you to the terminal page on github ![hyperlink](https://user-images.githubusercontent.com/26824113/89953536-45a6f580-dbfd-11ea-8e0d-8a3cd25c634a.gif)
2020-09-03 19:52:39 +02:00
// 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;
2021-01-11 19:01:38 +01:00
if (parts.size() < 1 || !Utils::StringToUint(til::at(parts, 0), subParam))
{
return false;
}
2021-01-11 19:01:38 +01:00
// 4 is SetProgressBar, which sets the taskbar state/progress.
if (subParam == 4)
{
2021-01-11 19:01:38 +01:00
if (parts.size() >= 2)
{
2021-01-11 19:01:38 +01:00
// 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;
}
2021-01-11 19:01:38 +01:00
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())
2021-01-11 19:01:38 +01:00
{
return false;
}
}
}
2021-01-11 19:01:38 +01:00
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);
}
2021-01-11 19:01:38 +01:00
// 9 is SetWorkingDirectory, which informs the terminal about the current working directory.
else if (subParam == 9)
{
2021-01-11 19:01:38 +01:00
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);
}
2021-01-11 19:01:38 +01:00
}
}
2021-01-11 19:01:38 +01:00
return false;
}
// Routine Description:
// - Support routine for routing private mode parameters to be set/reset as flags
// Arguments:
Refactor VT parameter handling (#7799) This PR introduces a pair of classes for managing VT parameters that automatically handle range checking and default fallback values, so the individual operations don't have to do that validation themselves. In addition to simplifying the code, this fixes a few cases where we were mishandling missing or extraneous parameters, and adds support for parameter sequences on commands that couldn't previously handle them. This PR also sets a limit on the number of parameters allowed, to help thwart DoS memory consumption attacks. ## References * The new parameter class also introduces the concept of an omitted/default parameter which is not necessarily zero, which is a prerequisite for addressing issue #4417. ## Detailed Description of the Pull Request / Additional comments There are two new classes provide by this PR: a `VTParameter` class, similar in function to a `std::optional<size_t>`, which holds an individual parameter (which may be an omitted/default value); and a `VTParameters` class, similar in function to `gsl:span<VTParameter>`, which holds a sequence of those parameters. Where `VTParameter` differs from `std::optional` is with the inclusion of two cast operators. There is a `size_t` cast that interprets omitted and zero values as 1 (the expected behaviour for most numeric parameters). And there is a generic cast, for use with the enum parameter types, which interprets omitted values as 0 (the expected behaviour for most selective parameters). The advantage of `VTParameters` class is that it has an `at` method that can never fail - out of range values simply return the a default `VTParameter` instance (this is standard behaviour in VT terminals). It also has a `size` method that will always return a minimum count of 1, since an empty parameter list is typically the equivalent of a single "default" parameter, so this guarantees you'll get at least one value when iterating over the list with `size()`. For cases where we just need to call the same dispatch method for every parameter, there is a helper `for_each` method, which repeatedly calls a given predicate function with each value in the sequence. It also collates the returned success values to determine the overall result of the sequence. As with the `size` method, this will always make at least one call, so it correctly handles empty sequences. With those two classes in place, we could get rid of all the parameter validation and default handling code in the `OutputStateMachineEngine`. We now just use the `VTParameters::at` method to grab a parameter and typically pass it straight to the appropriate dispatch method, letting the cast operators automatically handle the assignment of default values. Occasionally we might need a `value_or` call to specify a non-standard default value, but those cases are fairly rare. In some case the `OutputStateMachineEngine` was also checking whether parameters values were in range, but for the most part this shouldn't have been necessary, since that is something the dispatch classes would already have been doing themselves (in the few cases that they weren't, I've now updated them to do so). I've also updated the `InputStateMachineEngine` in a similar way to the `OutputStateMachineEngine`, getting rid of a few of the parameter extraction methods, and simplifying other parts of the implementation. It's not as clean a replacement as the output engine, but there are still benefits in using the new classes. ## Validation Steps Performed For the most part I haven't had to alter existing tests other than accounting for changes to the API. There were a couple of tests I needed to drop because they were checking for failure cases which shouldn't have been failing (unexpected parameters should never be an error), or testing output engine validation that is no longer handled at that level. I've added a few new tests to cover operations that take sequences of selective parameters (`ED`, `EL`, `TBC`, `SM`, and `RM`). And I've extended the cursor movement tests to make sure those operations can handle extraneous parameters that weren't expected. I've also added a test to verify that the state machine will correctly ignore parameters beyond the maximum 32 parameter count limit. I've also manual confirmed that the various test cases given in issues #2101 are now working as expected. Closes #2101
2020-10-15 18:12:52 +02:00
// - 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:
Add support for DECSCNM in Windows Terminal (#6809) ## Summary of the Pull Request This PR adds full support for the `DECSCNM` reverse screen mode in the Windows Terminal to align with the implementation in conhost. ## References * The conhost implementation of `DECSCNM` was in PR #3817. * WT originally inherited that functionality via the colors being passed through, but that behaviour was lost in PR #6506. ## PR Checklist * [x] Closes #6622 * [x] CLA signed. * [ ] Tests added/passed * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [ ] Schema updated. * [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #6622 ## Detailed Description of the Pull Request / Additional comments The `AdaptDispatch::SetScreenMode` now checks if it's in conpty mode and simply returns false to force a pass-through of the mode change. And the `TerminalDispatch` now has its own `SetScreenMode` implementation that tracks any changes to the reversed state, and triggers a redraw in the renderer. To make the renderer work, we just needed to update the `GetForegroundColor` and `GetBackgroundColor` methods of the terminal's `IRenderData` implementation to check the reversed state, and switch the colors being calculated, the same way the `LookupForegroundColor` and `LookupBackgroundColor` methods work in the conhost `Settings` class. ## Validation Steps Performed I've manually tested the `DECSCNM` functionality for Windows Terminal in Vttest, and also with some of my own test scripts.
2020-07-09 13:25:30 +02:00
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.
Don't abort early in VT reset operations if one of the steps fails (#6763) The VT reset operations `RIS` and `DECSTR` are implemented as a series of steps, each of which could potentially fail. Currently these operations abort as soon as an error is detected, which is particularly problematic in conpty mode, where some steps deliberately "fail" to indicate that they need to be "passed through" to the conpty client. As a result, the reset won't be fully executed. This PR changes that behaviour, so the error state is recorded for any failures, but the subsequent steps are still run. Originally the structure of these operations was of the form: bool success = DoSomething(); if (success) { success = DoSomethingElse(); } But I've now changed the code so it looks more like this: bool success = DoSomething(); success = DoSomethingElse() && success; This means that every one of the steps should execute, regardless of whether previous steps were successful, but the final _success_ state will only be true if none of the steps has failed. While this is only really an issue in the conhost code, I've updated both the `AdaptDispatch` and `TerminalDispatch` classes, since I thought it would be best to have them in sync, and in general this seems like a better way to handle multi-step operations anyway. VALIDATION I've manually tested the `RIS` escape sequence (`\ec`) in the Windows Terminal, and confirmed that it now correctly resets the cursor position, which it wasn't doing before. Closes #6545
2020-07-06 16:09:03 +02:00
// 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())
// {
Don't abort early in VT reset operations if one of the steps fails (#6763) The VT reset operations `RIS` and `DECSTR` are implemented as a series of steps, each of which could potentially fail. Currently these operations abort as soon as an error is detected, which is particularly problematic in conpty mode, where some steps deliberately "fail" to indicate that they need to be "passed through" to the conpty client. As a result, the reset won't be fully executed. This PR changes that behaviour, so the error state is recorded for any failures, but the subsequent steps are still run. Originally the structure of these operations was of the form: bool success = DoSomething(); if (success) { success = DoSomethingElse(); } But I've now changed the code so it looks more like this: bool success = DoSomething(); success = DoSomethingElse() && success; This means that every one of the steps should execute, regardless of whether previous steps were successful, but the final _success_ state will only be true if none of the steps has failed. While this is only really an issue in the conhost code, I've updated both the `AdaptDispatch` and `TerminalDispatch` classes, since I thought it would be best to have them in sync, and in general this seems like a better way to handle multi-step operations anyway. VALIDATION I've manually tested the `RIS` escape sequence (`\ec`) in the Windows Terminal, and confirmed that it now correctly resets the cursor position, which it wasn't doing before. Closes #6545
2020-07-06 16:09:03 +02:00
// // Restore initial code page if previously changed by a DOCS sequence.
// success = _pConApi->SetConsoleOutputCP(_initialCodePage.value()) && success;
// }
Refactor VT parameter handling (#7799) This PR introduces a pair of classes for managing VT parameters that automatically handle range checking and default fallback values, so the individual operations don't have to do that validation themselves. In addition to simplifying the code, this fixes a few cases where we were mishandling missing or extraneous parameters, and adds support for parameter sequences on commands that couldn't previously handle them. This PR also sets a limit on the number of parameters allowed, to help thwart DoS memory consumption attacks. ## References * The new parameter class also introduces the concept of an omitted/default parameter which is not necessarily zero, which is a prerequisite for addressing issue #4417. ## Detailed Description of the Pull Request / Additional comments There are two new classes provide by this PR: a `VTParameter` class, similar in function to a `std::optional<size_t>`, which holds an individual parameter (which may be an omitted/default value); and a `VTParameters` class, similar in function to `gsl:span<VTParameter>`, which holds a sequence of those parameters. Where `VTParameter` differs from `std::optional` is with the inclusion of two cast operators. There is a `size_t` cast that interprets omitted and zero values as 1 (the expected behaviour for most numeric parameters). And there is a generic cast, for use with the enum parameter types, which interprets omitted values as 0 (the expected behaviour for most selective parameters). The advantage of `VTParameters` class is that it has an `at` method that can never fail - out of range values simply return the a default `VTParameter` instance (this is standard behaviour in VT terminals). It also has a `size` method that will always return a minimum count of 1, since an empty parameter list is typically the equivalent of a single "default" parameter, so this guarantees you'll get at least one value when iterating over the list with `size()`. For cases where we just need to call the same dispatch method for every parameter, there is a helper `for_each` method, which repeatedly calls a given predicate function with each value in the sequence. It also collates the returned success values to determine the overall result of the sequence. As with the `size` method, this will always make at least one call, so it correctly handles empty sequences. With those two classes in place, we could get rid of all the parameter validation and default handling code in the `OutputStateMachineEngine`. We now just use the `VTParameters::at` method to grab a parameter and typically pass it straight to the appropriate dispatch method, letting the cast operators automatically handle the assignment of default values. Occasionally we might need a `value_or` call to specify a non-standard default value, but those cases are fairly rare. In some case the `OutputStateMachineEngine` was also checking whether parameters values were in range, but for the most part this shouldn't have been necessary, since that is something the dispatch classes would already have been doing themselves (in the few cases that they weren't, I've now updated them to do so). I've also updated the `InputStateMachineEngine` in a similar way to the `OutputStateMachineEngine`, getting rid of a few of the parameter extraction methods, and simplifying other parts of the implementation. It's not as clean a replacement as the output engine, but there are still benefits in using the new classes. ## Validation Steps Performed For the most part I haven't had to alter existing tests other than accounting for changes to the API. There were a couple of tests I needed to drop because they were checking for failure cases which shouldn't have been failing (unexpected parameters should never be an error), or testing output engine validation that is no longer handled at that level. I've added a few new tests to cover operations that take sequences of selective parameters (`ED`, `EL`, `TBC`, `SM`, and `RM`). And I've extended the cursor movement tests to make sure those operations can handle extraneous parameters that weren't expected. I've also added a test to verify that the state machine will correctly ignore parameters beyond the maximum 32 parameter count limit. I've also manual confirmed that the various test cases given in issues #2101 are now working as expected. Closes #2101
2020-10-15 18:12:52 +02:00
success = SetGraphicsRendition({}) && success; // Normal rendition.
Don't abort early in VT reset operations if one of the steps fails (#6763) The VT reset operations `RIS` and `DECSTR` are implemented as a series of steps, each of which could potentially fail. Currently these operations abort as soon as an error is detected, which is particularly problematic in conpty mode, where some steps deliberately "fail" to indicate that they need to be "passed through" to the conpty client. As a result, the reset won't be fully executed. This PR changes that behaviour, so the error state is recorded for any failures, but the subsequent steps are still run. Originally the structure of these operations was of the form: bool success = DoSomething(); if (success) { success = DoSomethingElse(); } But I've now changed the code so it looks more like this: bool success = DoSomething(); success = DoSomethingElse() && success; This means that every one of the steps should execute, regardless of whether previous steps were successful, but the final _success_ state will only be true if none of the steps has failed. While this is only really an issue in the conhost code, I've updated both the `AdaptDispatch` and `TerminalDispatch` classes, since I thought it would be best to have them in sync, and in general this seems like a better way to handle multi-step operations anyway. VALIDATION I've manually tested the `RIS` escape sequence (`\ec`) in the Windows Terminal, and confirmed that it now correctly resets the cursor position, which it wasn't doing before. Closes #6545
2020-07-06 16:09:03 +02:00
// // 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.
Don't abort early in VT reset operations if one of the steps fails (#6763) The VT reset operations `RIS` and `DECSTR` are implemented as a series of steps, each of which could potentially fail. Currently these operations abort as soon as an error is detected, which is particularly problematic in conpty mode, where some steps deliberately "fail" to indicate that they need to be "passed through" to the conpty client. As a result, the reset won't be fully executed. This PR changes that behaviour, so the error state is recorded for any failures, but the subsequent steps are still run. Originally the structure of these operations was of the form: bool success = DoSomething(); if (success) { success = DoSomethingElse(); } But I've now changed the code so it looks more like this: bool success = DoSomething(); success = DoSomethingElse() && success; This means that every one of the steps should execute, regardless of whether previous steps were successful, but the final _success_ state will only be true if none of the steps has failed. While this is only really an issue in the conhost code, I've updated both the `AdaptDispatch` and `TerminalDispatch` classes, since I thought it would be best to have them in sync, and in general this seems like a better way to handle multi-step operations anyway. VALIDATION I've manually tested the `RIS` escape sequence (`\ec`) in the Windows Terminal, and confirmed that it now correctly resets the cursor position, which it wasn't doing before. Closes #6545
2020-07-06 16:09:03 +02:00
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.
Don't abort early in VT reset operations if one of the steps fails (#6763) The VT reset operations `RIS` and `DECSTR` are implemented as a series of steps, each of which could potentially fail. Currently these operations abort as soon as an error is detected, which is particularly problematic in conpty mode, where some steps deliberately "fail" to indicate that they need to be "passed through" to the conpty client. As a result, the reset won't be fully executed. This PR changes that behaviour, so the error state is recorded for any failures, but the subsequent steps are still run. Originally the structure of these operations was of the form: bool success = DoSomething(); if (success) { success = DoSomethingElse(); } But I've now changed the code so it looks more like this: bool success = DoSomething(); success = DoSomethingElse() && success; This means that every one of the steps should execute, regardless of whether previous steps were successful, but the final _success_ state will only be true if none of the steps has failed. While this is only really an issue in the conhost code, I've updated both the `AdaptDispatch` and `TerminalDispatch` classes, since I thought it would be best to have them in sync, and in general this seems like a better way to handle multi-step operations anyway. VALIDATION I've manually tested the `RIS` escape sequence (`\ec`) in the Windows Terminal, and confirmed that it now correctly resets the cursor position, which it wasn't doing before. Closes #6545
2020-07-06 16:09:03 +02:00
success = SoftReset() && success;
// Clears the screen - Needs to be done in two operations.
Don't abort early in VT reset operations if one of the steps fails (#6763) The VT reset operations `RIS` and `DECSTR` are implemented as a series of steps, each of which could potentially fail. Currently these operations abort as soon as an error is detected, which is particularly problematic in conpty mode, where some steps deliberately "fail" to indicate that they need to be "passed through" to the conpty client. As a result, the reset won't be fully executed. This PR changes that behaviour, so the error state is recorded for any failures, but the subsequent steps are still run. Originally the structure of these operations was of the form: bool success = DoSomething(); if (success) { success = DoSomethingElse(); } But I've now changed the code so it looks more like this: bool success = DoSomething(); success = DoSomethingElse() && success; This means that every one of the steps should execute, regardless of whether previous steps were successful, but the final _success_ state will only be true if none of the steps has failed. While this is only really an issue in the conhost code, I've updated both the `AdaptDispatch` and `TerminalDispatch` classes, since I thought it would be best to have them in sync, and in general this seems like a better way to handle multi-step operations anyway. VALIDATION I've manually tested the `RIS` escape sequence (`\ec`) in the Windows Terminal, and confirmed that it now correctly resets the cursor position, which it wasn't doing before. Closes #6545
2020-07-06 16:09:03 +02:00
success = EraseInDisplay(DispatchTypes::EraseType::All) && success;
success = EraseInDisplay(DispatchTypes::EraseType::Scrollback) && success;
Add support for DECSCNM in Windows Terminal (#6809) ## Summary of the Pull Request This PR adds full support for the `DECSCNM` reverse screen mode in the Windows Terminal to align with the implementation in conhost. ## References * The conhost implementation of `DECSCNM` was in PR #3817. * WT originally inherited that functionality via the colors being passed through, but that behaviour was lost in PR #6506. ## PR Checklist * [x] Closes #6622 * [x] CLA signed. * [ ] Tests added/passed * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [ ] Schema updated. * [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #6622 ## Detailed Description of the Pull Request / Additional comments The `AdaptDispatch::SetScreenMode` now checks if it's in conpty mode and simply returns false to force a pass-through of the mode change. And the `TerminalDispatch` now has its own `SetScreenMode` implementation that tracks any changes to the reversed state, and triggers a redraw in the renderer. To make the renderer work, we just needed to update the `GetForegroundColor` and `GetBackgroundColor` methods of the terminal's `IRenderData` implementation to check the reversed state, and switch the colors being calculated, the same way the `LookupForegroundColor` and `LookupBackgroundColor` methods work in the conhost `Settings` class. ## Validation Steps Performed I've manually tested the `DECSCNM` functionality for Windows Terminal in Vttest, and also with some of my own test scripts.
2020-07-09 13:25:30 +02:00
// Set the DECSCNM screen mode back to normal.
success = SetScreenMode(false) && success;
// Cursor to 1,1 - the Soft Reset guarantees this is absolute
Don't abort early in VT reset operations if one of the steps fails (#6763) The VT reset operations `RIS` and `DECSTR` are implemented as a series of steps, each of which could potentially fail. Currently these operations abort as soon as an error is detected, which is particularly problematic in conpty mode, where some steps deliberately "fail" to indicate that they need to be "passed through" to the conpty client. As a result, the reset won't be fully executed. This PR changes that behaviour, so the error state is recorded for any failures, but the subsequent steps are still run. Originally the structure of these operations was of the form: bool success = DoSomething(); if (success) { success = DoSomethingElse(); } But I've now changed the code so it looks more like this: bool success = DoSomething(); success = DoSomethingElse() && success; This means that every one of the steps should execute, regardless of whether previous steps were successful, but the final _success_ state will only be true if none of the steps has failed. While this is only really an issue in the conhost code, I've updated both the `AdaptDispatch` and `TerminalDispatch` classes, since I thought it would be best to have them in sync, and in general this seems like a better way to handle multi-step operations anyway. VALIDATION I've manually tested the `RIS` escape sequence (`\ec`) in the Windows Terminal, and confirmed that it now correctly resets the cursor position, which it wasn't doing before. Closes #6545
2020-07-06 16:09:03 +02:00
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;
}