Add support for resetting the color scheme with RIS (#17879)

## Summary of the Pull Request

This improves our `RIS` (hard reset) implementation, so it now also
resets any changes that are made to the color table and color aliases,
which is one of the things it's supposed to be doing.

## References and Relevant Issues

This is also a small step towards implementing the `OSC` sequences that
reset individual color table entries (issue #3719).

## Detailed Description of the Pull Request / Additional comments

The way this works is by having a second copy of the color table and
alias indices to hold the default values in the `RenderSettings` class.
This default set is initially populated at startup with the user's
chosen color scheme, but can also potentially be updated if the user
changes their settings while a session is already in progress.

When we receive an `RIS` request, we just copy the default values back
over the active settings, and refresh the renderer.

## Validation Steps Performed

I've manually tested both OpenConsole and Windows Terminal by changing
my color scheme programmatically, and then confirming that the original
colors are restored when an `RIS` sequence is received.

I've also added some basic unit tests that check both the color aliases
and color table are restored by `RIS`.

## PR Checklist
- [x] Tests added/passed
This commit is contained in:
James Holderness 2024-09-16 19:59:12 +01:00 committed by GitHub
parent bc6f3e2275
commit 5e8e10fdc0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 67 additions and 2 deletions

View File

@ -891,6 +891,9 @@ void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR font
renderSettings.SetColorTableEntry(tableIndex, gsl::at(theme.ColorTable, tableIndex));
}
// Save these values as the new default render settings.
renderSettings.SaveDefaultSettings();
publicTerminal->_terminal->SetCursorStyle(static_cast<Microsoft::Console::VirtualTerminal::DispatchTypes::CursorStyle>(theme.CursorStyle));
publicTerminal->_desiredFont = { fontFamily, 0, DEFAULT_FONT_WEIGHT, static_cast<float>(fontSize), CP_UTF8 };

View File

@ -101,6 +101,9 @@ void Terminal::UpdateSettings(ICoreSettings settings)
GetRenderSettings().SetColorTableEntry(TextColor::FRAME_BACKGROUND, til::color{ settings.TabColor().Value() });
}
// Save the changes made above and in UpdateAppearance as the new default render settings.
GetRenderSettings().SaveDefaultSettings();
if (!_startingTabColor && settings.StartingTabColor())
{
_startingTabColor = settings.StartingTabColor().Value();

View File

@ -349,6 +349,8 @@ void Settings::Validate()
TextAttribute::SetLegacyDefaultAttributes(_wFillAttribute);
// And calculate the position of the default colors in the color table.
CalculateDefaultColorIndices();
// We can also then save these values as the default render settings.
SaveDefaultRenderSettings();
FAIL_FAST_IF(!(_dwWindowSize.X > 0));
FAIL_FAST_IF(!(_dwWindowSize.Y > 0));
@ -755,6 +757,11 @@ void Settings::CalculateDefaultColorIndices() noexcept
_renderSettings.SetColorAliasIndex(ColorAlias::DefaultBackground, backgroundAlias);
}
void Settings::SaveDefaultRenderSettings() noexcept
{
_renderSettings.SaveDefaultSettings();
}
bool Settings::IsTerminalScrolling() const noexcept
{
return _TerminalScrolling;

View File

@ -172,6 +172,7 @@ public:
void SetInterceptCopyPaste(const bool interceptCopyPaste) noexcept;
void CalculateDefaultColorIndices() noexcept;
void SaveDefaultRenderSettings() noexcept;
bool IsTerminalScrolling() const noexcept;
void SetTerminalScrolling(const bool terminalScrollingEnabled) noexcept;

View File

@ -16,6 +16,7 @@
#include "../interactivity/inc/ServiceLocator.hpp"
#include "../../inc/conattrs.hpp"
#include "../../types/inc/colorTable.hpp"
#include "../../types/inc/Viewport.hpp"
#include "../../inc/TestUtils.h"
@ -2070,6 +2071,15 @@ void ScreenBufferTests::VtRestoreColorTableReport()
// Blue component is clamped at 100%, so 150% interpreted as 100%
stateMachine.ProcessString(L"\033P2$p14;2;0;0;150\033\\");
VERIFY_ARE_EQUAL(RGB(0, 0, 255), gci.GetColorTableEntry(14));
Log::Comment(L"RIS restores initial Campbell color scheme");
stateMachine.ProcessString(L"\033c");
for (auto i = 0; i < 16; i++)
{
const COLORREF expectedColor = Microsoft::Console::Utils::CampbellColorTable()[i];
VERIFY_ARE_EQUAL(expectedColor, gci.GetColorTableEntry(i));
}
}
void ScreenBufferTests::ResizeTraditionalDoesNotDoubleFreeAttrRows()
@ -3352,6 +3362,13 @@ void ScreenBufferTests::AssignColorAliases()
stateMachine.ProcessString(L"\033[2;34;56,|");
VERIFY_ARE_EQUAL(34u, renderSettings.GetColorAliasIndex(ColorAlias::FrameForeground));
VERIFY_ARE_EQUAL(56u, renderSettings.GetColorAliasIndex(ColorAlias::FrameBackground));
Log::Comment(L"Test RIS restores initial color assignments");
stateMachine.ProcessString(L"\033c");
VERIFY_ARE_EQUAL(defaultFg, renderSettings.GetColorAliasIndex(ColorAlias::DefaultForeground));
VERIFY_ARE_EQUAL(defaultBg, renderSettings.GetColorAliasIndex(ColorAlias::DefaultBackground));
VERIFY_ARE_EQUAL(frameFg, renderSettings.GetColorAliasIndex(ColorAlias::FrameForeground));
VERIFY_ARE_EQUAL(frameBg, renderSettings.GetColorAliasIndex(ColorAlias::FrameBackground));
}
void ScreenBufferTests::DeleteCharsNearEndOfLine()

View File

@ -576,6 +576,8 @@ void Menu::s_PropertiesUpdate(PCONSOLE_STATE_INFO pStateInfo)
TextAttribute::SetLegacyDefaultAttributes(pStateInfo->ScreenAttributes);
// And recalculate the position of the default colors in the color table.
gci.CalculateDefaultColorIndices();
// Then save these values as the new default render settings.
gci.SaveDefaultRenderSettings();
// Set the screen info's default text attributes to defaults -
ScreenInfo.SetDefaultAttributes({}, TextAttribute{ gci.GetPopupFillAttribute() });

View File

@ -26,6 +26,29 @@ RenderSettings::RenderSettings() noexcept
SetColorAliasIndex(ColorAlias::DefaultBackground, TextColor::DARK_BLACK);
SetColorAliasIndex(ColorAlias::FrameForeground, TextColor::FRAME_FOREGROUND);
SetColorAliasIndex(ColorAlias::FrameBackground, TextColor::FRAME_BACKGROUND);
SaveDefaultSettings();
}
// Routine Description:
// - Saves the current color table and color aliases as the default values, so
// we can later restore them when a hard reset (RIS) is requested.
void RenderSettings::SaveDefaultSettings() noexcept
{
_defaultColorTable = _colorTable;
_defaultColorAliasIndices = _colorAliasIndices;
}
// Routine Description:
// - Resets the render settings to their default values. which is typically
// what they were set to at startup.
void RenderSettings::RestoreDefaultSettings() noexcept
{
_colorTable = _defaultColorTable;
_colorAliasIndices = _defaultColorAliasIndices;
// For now, DECSCNM is the only render mode we need to reset. The others are
// all user preferences that can't be changed programmatically.
_renderMode.reset(Mode::ScreenReversed);
}
// Routine Description:

View File

@ -29,6 +29,8 @@ namespace Microsoft::Console::Render
};
RenderSettings() noexcept;
void SaveDefaultSettings() noexcept;
void RestoreDefaultSettings() noexcept;
void SetRenderMode(const Mode mode, const bool enabled) noexcept;
bool GetRenderMode(const Mode mode) const noexcept;
const std::array<COLORREF, TextColor::TABLE_SIZE>& GetColorTable() const noexcept;
@ -48,6 +50,8 @@ namespace Microsoft::Console::Render
til::enumset<Mode> _renderMode{ Mode::BlinkAllowed, Mode::IntenseIsBright };
std::array<COLORREF, TextColor::TABLE_SIZE> _colorTable;
std::array<size_t, static_cast<size_t>(ColorAlias::ENUM_COUNT)> _colorAliasIndices;
std::array<COLORREF, TextColor::TABLE_SIZE> _defaultColorTable;
std::array<size_t, static_cast<size_t>(ColorAlias::ENUM_COUNT)> _defaultColorAliasIndices;
size_t _blinkCycle = 0;
mutable bool _blinkIsInUse = false;
bool _blinkShouldBeFaint = false;

View File

@ -3019,8 +3019,13 @@ void AdaptDispatch::HardReset()
EraseInDisplay(DispatchTypes::EraseType::All);
EraseInDisplay(DispatchTypes::EraseType::Scrollback);
// Set the DECSCNM screen mode back to normal.
_renderSettings.SetRenderMode(RenderSettings::Mode::ScreenReversed, false);
// Set the color table and render modes back to their initial startup values.
_renderSettings.RestoreDefaultSettings();
// Let the renderer know that the background and frame colors may have changed.
if (_renderer)
{
_renderer->TriggerRedrawAll(true, true);
}
// Cursor to 1,1 - the Soft Reset guarantees this is absolute
CursorPosition(1, 1);