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.
This commit is contained in:
James Holderness 2020-07-09 12:25:30 +01:00 committed by GitHub
parent 9e26c020e4
commit 695ebffca1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 60 additions and 7 deletions

View File

@ -46,6 +46,7 @@ namespace Microsoft::Terminal::Core
virtual bool EnableWin32InputMode(const bool win32InputMode) noexcept = 0;
virtual bool SetCursorKeysMode(const bool applicationMode) noexcept = 0;
virtual bool SetKeypadMode(const bool applicationMode) noexcept = 0;
virtual bool SetScreenMode(const bool reverseMode) noexcept = 0;
virtual bool EnableVT200MouseMode(const bool enabled) noexcept = 0;
virtual bool EnableUTF8ExtendedMouseMode(const bool enabled) noexcept = 0;
virtual bool EnableSGRExtendedMouseMode(const bool enabled) noexcept = 0;

View File

@ -41,6 +41,7 @@ Terminal::Terminal() :
_colorTable{},
_defaultFg{ RGB(255, 255, 255) },
_defaultBg{ ARGB(0, 0, 0, 0) },
_screenReversed{ false },
_pfnWriteInput{ nullptr },
_scrollOffset{ 0 },
_snapOnInput{ true },

View File

@ -99,6 +99,7 @@ public:
bool EnableWin32InputMode(const bool win32InputMode) noexcept override;
bool SetCursorKeysMode(const bool applicationMode) noexcept override;
bool SetKeypadMode(const bool applicationMode) noexcept override;
bool SetScreenMode(const bool reverseMode) noexcept override;
bool EnableVT200MouseMode(const bool enabled) noexcept override;
bool EnableUTF8ExtendedMouseMode(const bool enabled) noexcept override;
bool EnableSGRExtendedMouseMode(const bool enabled) noexcept override;
@ -208,6 +209,7 @@ private:
std::array<COLORREF, XTERM_COLOR_TABLE_SIZE> _colorTable;
COLORREF _defaultFg;
COLORREF _defaultBg;
bool _screenReversed;
bool _snapOnInput;
bool _altGrAliasing;

View File

@ -471,6 +471,17 @@ bool Terminal::SetKeypadMode(const bool applicationMode) noexcept
return true;
}
bool Terminal::SetScreenMode(const bool reverseMode) noexcept
try
{
_screenReversed = reverseMode;
// Repaint everything - the colors will have changed
_buffer->GetRenderTarget().TriggerRedrawAll();
return true;
}
CATCH_LOG_RETURN_FALSE()
bool Terminal::EnableVT200MouseMode(const bool enabled) noexcept
{
_terminalInput->EnableDefaultTracking(enabled);

View File

@ -253,6 +253,18 @@ bool TerminalDispatch::SetCursorKeysMode(const bool applicationMode) noexcept
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.
@ -390,6 +402,9 @@ bool TerminalDispatch::_PrivateModeParamsHelper(const DispatchTypes::PrivateMode
// set - Enable Application Mode, reset - Normal mode
success = SetCursorKeysMode(enable);
break;
case DispatchTypes::PrivateModeParams::DECSCNM_ScreenMode:
success = SetScreenMode(enable);
break;
case DispatchTypes::PrivateModeParams::VT200_MOUSE_MODE:
success = EnableVT200MouseMode(enable);
break;
@ -493,8 +508,8 @@ bool TerminalDispatch::HardReset() noexcept
success = EraseInDisplay(DispatchTypes::EraseType::All) && success;
success = EraseInDisplay(DispatchTypes::EraseType::Scrollback) && success;
// // Set the DECSCNM screen mode back to normal.
// success = SetScreenMode(false) && 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;

View File

@ -47,6 +47,7 @@ public:
bool SetCursorKeysMode(const bool applicationMode) noexcept override; // DECCKM
bool SetKeypadMode(const bool applicationMode) noexcept override; // DECKPAM, DECKPNM
bool SetScreenMode(const bool reverseMode) noexcept override; // DECSCNM
bool SoftReset() noexcept override; // DECSTR
bool HardReset() noexcept override; // RIS

View File

@ -52,15 +52,32 @@ const TextAttribute Terminal::GetDefaultBrushColors() noexcept
const COLORREF Terminal::GetForegroundColor(const TextAttribute& attr) const noexcept
{
return 0xff000000 | attr.CalculateRgbForeground({ _colorTable.data(), _colorTable.size() }, _defaultFg, _defaultBg);
COLORREF fgColor{};
if (_screenReversed)
{
fgColor = attr.CalculateRgbBackground({ _colorTable.data(), _colorTable.size() }, _defaultFg, _defaultBg);
}
else
{
fgColor = attr.CalculateRgbForeground({ _colorTable.data(), _colorTable.size() }, _defaultFg, _defaultBg);
}
return 0xff000000 | fgColor;
}
const COLORREF Terminal::GetBackgroundColor(const TextAttribute& attr) const noexcept
{
const auto bgColor = attr.CalculateRgbBackground({ _colorTable.data(), _colorTable.size() }, _defaultFg, _defaultBg);
COLORREF bgColor{};
if (_screenReversed)
{
bgColor = attr.CalculateRgbForeground({ _colorTable.data(), _colorTable.size() }, _defaultFg, _defaultBg);
}
else
{
bgColor = attr.CalculateRgbBackground({ _colorTable.data(), _colorTable.size() }, _defaultFg, _defaultBg);
}
// We only care about alpha for the default BG (which enables acrylic)
// If the bg isn't the default bg color, or reverse video is enabled, make it fully opaque.
if (!attr.BackgroundIsDefault() || attr.IsReverseVideo())
if (!attr.BackgroundIsDefault() || (attr.IsReverseVideo() ^ _screenReversed))
{
return 0xff000000 | bgColor;
}
@ -213,10 +230,9 @@ void Terminal::UnlockConsole() noexcept
// Method Description:
// - Returns whether the screen is inverted;
// This state is not currently known to Terminal.
// Return Value:
// - false.
bool Terminal::IsScreenReversed() const noexcept
{
return false;
return _screenReversed;
}

View File

@ -1205,6 +1205,12 @@ bool AdaptDispatch::SetAnsiMode(const bool ansiMode)
// - True if handled successfully. False otherwise.
bool AdaptDispatch::SetScreenMode(const bool reverseMode)
{
// If we're a conpty, always return false
if (_pConApi->IsConsolePty())
{
return false;
}
return _pConApi->PrivateSetScreenMode(reverseMode);
}