Skip to content

Commit

Permalink
Add support for DECSCNM in Windows Terminal (#6809)
Browse files Browse the repository at this point in the history
## 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.
  • Loading branch information
j4james authored Jul 9, 2020
1 parent 9e26c02 commit 695ebff
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 7 deletions.
1 change: 1 addition & 0 deletions src/cascadia/TerminalCore/ITerminalApi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalCore/Terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalCore/Terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ class Microsoft::Terminal::Core::Terminal final :
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;
Expand Down Expand Up @@ -208,6 +209,7 @@ class Microsoft::Terminal::Core::Terminal final :
std::array<COLORREF, XTERM_COLOR_TABLE_SIZE> _colorTable;
COLORREF _defaultFg;
COLORREF _defaultBg;
bool _screenReversed;

bool _snapOnInput;
bool _altGrAliasing;
Expand Down
11 changes: 11 additions & 0 deletions src/cascadia/TerminalCore/TerminalApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
19 changes: 17 additions & 2 deletions src/cascadia/TerminalCore/TerminalDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalCore/TerminalDispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class TerminalDispatch : public Microsoft::Console::VirtualTerminal::TermDispatc

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
Expand Down
26 changes: 21 additions & 5 deletions src/cascadia/TerminalCore/terminalrenderdata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
6 changes: 6 additions & 0 deletions src/terminal/adapter/adaptDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down

0 comments on commit 695ebff

Please sign in to comment.