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 коммит произвёл GitHub
Родитель bc6f3e2275
Коммит 5e8e10fdc0
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
9 изменённых файлов: 67 добавлений и 2 удалений

Просмотреть файл

@ -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 };

Просмотреть файл

@ -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();

Просмотреть файл

@ -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;

Просмотреть файл

@ -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;

Просмотреть файл

@ -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()

Просмотреть файл

@ -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() });

Просмотреть файл

@ -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:

Просмотреть файл

@ -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;

Просмотреть файл

@ -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);