From b82d365f08f6fb2dcebec8b1eeb3e137da63475f Mon Sep 17 00:00:00 2001 From: Aloke Desai Date: Sat, 12 Oct 2024 17:51:30 -0400 Subject: [PATCH 1/2] ConPTY changes to support Windows --- src/host/ut_host/VtRendererTests.cpp | 113 ++++++++++++++++++ src/renderer/base/renderer.cpp | 2 +- src/renderer/vt/state.cpp | 2 +- src/terminal/adapter/ITermDispatch.hpp | 6 + src/terminal/adapter/adaptDispatch.cpp | 68 +++++++++++ src/terminal/adapter/adaptDispatch.hpp | 6 + src/terminal/adapter/termDispatch.hpp | 5 + .../parser/OutputStateMachineEngine.cpp | 27 +++++ .../parser/OutputStateMachineEngine.hpp | 4 + 9 files changed, 231 insertions(+), 2 deletions(-) diff --git a/src/host/ut_host/VtRendererTests.cpp b/src/host/ut_host/VtRendererTests.cpp index 279012e71fe..40fb47040f7 100644 --- a/src/host/ut_host/VtRendererTests.cpp +++ b/src/host/ut_host/VtRendererTests.cpp @@ -69,6 +69,7 @@ class Microsoft::Console::Render::VtRendererTest TEST_METHOD(Xterm256TestInvalidate); TEST_METHOD(Xterm256TestColors); TEST_METHOD(Xterm256TestITUColors); + TEST_METHOD(Xterm256TestAloke); TEST_METHOD(Xterm256TestCursor); TEST_METHOD(Xterm256TestExtendedAttributes); TEST_METHOD(Xterm256TestAttributesAcrossReset); @@ -217,6 +218,9 @@ void VtRendererTest::VtSequenceHelperTests() qExpectedInput.push_back("\x1b[10C"); VERIFY_SUCCEEDED(engine->_CursorForward(10)); + + qExpectedInput.push_back("\x1b[10C"); + VERIFY_SUCCEEDED(engine->_CursorForward(10)); } void VtRendererTest::Xterm256TestInvalidate() @@ -691,6 +695,115 @@ void VtRendererTest::Xterm256TestITUColors() }); } +void VtRendererTest::Xterm256TestAloke() +{ + auto hFile = wil::unique_hfile(INVALID_HANDLE_VALUE); + auto engine = std::make_unique(std::move(hFile), SetUpViewport()); + auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2); + engine->SetTestCallback(pfn); + RenderSettings renderSettings; + RenderData renderData; + + VerifyFirstPaint(*engine); + + auto view = SetUpViewport(); + + Log::Comment(NoThrowString().Format( + L"Test changing the text attributes")); + + // Internally _lastTextAttributes starts with a fg and bg set to INVALID_COLOR(s), + // and initializing textAttributes with the default colors will output "\e[39m\e[49m" + // in the beginning. + auto textAttributes = TextAttribute{}; + qExpectedInput.push_back("\x1b[39m"); + qExpectedInput.push_back("\x1b[49m"); + + Log::Comment(NoThrowString().Format( + L"Begin by setting some test values - UL = (1,2,3) to start. " + L"This value is picked for ease of formatting raw COLORREF values.")); + qExpectedInput.push_back("\x1b[58:2::1:2:3m"); + textAttributes.SetUnderlineColor(RGB(1, 2, 3)); + VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, + renderSettings, + &renderData, + false, + false)); + + TestPaint(*engine, [&]() { + Log::Comment(NoThrowString().Format( + L"----Change the color----")); + qExpectedInput.push_back("\x1b[58:2::7:8:9m"); + textAttributes.SetUnderlineColor(RGB(7, 8, 9)); + VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, + renderSettings, + &renderData, + false, + false)); + }); + + TestPaint(*engine, [&]() { + Log::Comment(NoThrowString().Format( + L"Make sure that color setting persists across EndPaint/StartPaint")); + qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL); + VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, + renderSettings, + &renderData, + false, + false)); + WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback + }); + + TestPaint(*engine, [&]() { + Log::Comment(NoThrowString().Format( + L"----Change the UL color to a 256-color index----")); + textAttributes.SetUnderlineColor(TextColor{ TextColor::DARK_RED, true }); + qExpectedInput.push_back("\x1b[58:5:1m"); + VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, + renderSettings, + &renderData, + false, + false)); + + // to test the sequence for the default underline color, temporarily modify fg and bg to be something else. + textAttributes.SetForeground(RGB(9, 10, 11)); + qExpectedInput.push_back("\x1b[38;2;9;10;11m"); + textAttributes.SetBackground(RGB(5, 6, 7)); + qExpectedInput.push_back("\x1b[48;2;5;6;7m"); + + Log::Comment(NoThrowString().Format( + L"----Change only the UL color to the 'Default'----")); + textAttributes.SetDefaultUnderlineColor(); + qExpectedInput.push_back("\x1b[59m"); + VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, + renderSettings, + &renderData, + false, + false)); + + Log::Comment(NoThrowString().Format( + L"----Back to defaults (all colors)----")); + textAttributes = {}; + qExpectedInput.push_back("\x1b[m"); + VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, + renderSettings, + &renderData, + false, + false)); + }); + + TestPaint(*engine, [&]() { + Log::Comment(NoThrowString().Format( + L"Make sure that color setting persists across EndPaint/StartPaint")); + qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL); + VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes({}, + renderSettings, + &renderData, + false, + false)); + WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback + }); +} + void VtRendererTest::Xterm256TestCursor() { auto hFile = wil::unique_hfile(INVALID_HANDLE_VALUE); diff --git a/src/renderer/base/renderer.cpp b/src/renderer/base/renderer.cpp index 7d7a4b356eb..8939d6b03b6 100644 --- a/src/renderer/base/renderer.cpp +++ b/src/renderer/base/renderer.cpp @@ -733,7 +733,7 @@ void Renderer::_PaintBufferOutput(_In_ IRenderEngine* const pEngine) auto resetLineTransform = wil::scope_exit([&]() { LOG_IF_FAILED(pEngine->ResetLineTransform()); }); - + for (const auto& dirtyRect : dirtyAreas) { if (!dirtyRect) diff --git a/src/renderer/vt/state.cpp b/src/renderer/vt/state.cpp index f192536e3e6..a9905d88032 100644 --- a/src/renderer/vt/state.cpp +++ b/src/renderer/vt/state.cpp @@ -269,8 +269,8 @@ void VtEngine::Cork(bool corked) noexcept // Method Description: // - This method will modify the DPI we're using for scaling calculations. -// Does nothing for vt, the dpi is handed by the terminal. // Arguments: +// Does nothing for vt, the dpi is handed by the terminal. // - iDpi - The Dots Per Inch to use for scaling. We will use this relative to // the system default DPI defined in Windows headers as a constant. // Return Value: diff --git a/src/terminal/adapter/ITermDispatch.hpp b/src/terminal/adapter/ITermDispatch.hpp index e3976996433..c597b53657b 100644 --- a/src/terminal/adapter/ITermDispatch.hpp +++ b/src/terminal/adapter/ITermDispatch.hpp @@ -143,6 +143,12 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch virtual bool DoITerm2Action(const std::wstring_view string) = 0; + virtual bool DoWarpInBandGeneratorAction() = 0; + + virtual bool DoWarpAction() = 0; + + virtual bool DoWarpResetGridAction() = 0; + virtual bool DoFinalTermAction(const std::wstring_view string) = 0; virtual bool DoVsCodeAction(const std::wstring_view string) = 0; diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp index 74ede69b53f..05ed9c6a453 100644 --- a/src/terminal/adapter/adaptDispatch.cpp +++ b/src/terminal/adapter/adaptDispatch.cpp @@ -3253,6 +3253,7 @@ bool AdaptDispatch::HardReset() // Routine Description: // - DECALN - Fills the entire screen with a test pattern of uppercase Es, +// // resets the margins and rendition attributes, and moves the cursor to // the home position. // Arguments: @@ -3756,6 +3757,73 @@ bool AdaptDispatch::DoConEmuAction(const std::wstring_view string) return false; } +// Method Description: +// - Performs a iTerm2 action +// - Ascribes to the ITermDispatch interface +// - Currently, the actions we support are: +// * `OSC1337;SetMark`: mark a line as a prompt line +// - Not actually used in conhost +// Arguments: +// - string: contains the parameters that define which action we do +// Return Value: +// - false in conhost, true for the SetMark action, otherwise false. +bool AdaptDispatch::DoWarpAction() +{ + const auto isConPty = _api.IsConsolePty(); + if (isConPty) + { + // Flush the frame manually, to make sure marks end up on the right + // line, like the alt buffer sequence. + _renderer.TriggerFlush(false); + //CursorPosition(1, 1); + } + + return !isConPty; +} + +// Method Description: +// - Performs a iTerm2 action +// - Ascribes to the ITermDispatch interface +// - Currently, the actions we support are: +// * `OSC1337;SetMark`: mark a line as a prompt line +// - Not actually used in conhost +// Arguments: +// - string: contains the parameters that define which action we do +// Return Value: +// - false in conhost, true for the SetMark action, otherwise false. +bool AdaptDispatch::DoWarpInBandGeneratorAction() +{ + const auto isConPty = _api.IsConsolePty(); + if (isConPty) + { + // Flush the frame manually, to make sure marks end up on the right + // line, like the alt buffer sequence. + _renderer.TriggerFlush(false); + } + + return !isConPty; +} + +bool AdaptDispatch::DoWarpResetGridAction() +{ + const auto isConPty = _api.IsConsolePty(); + if (isConPty) + { + // Flush the frame manually, to make sure marks end up on the right + // line, like the alt buffer sequence. + _renderer.TriggerFlush(false); + + // Clear grid without painting. + // ATODO: Anything else we need to reset here? + CursorPosition(1, 1); + _pages.ActivePage().Buffer().Reset(); + _renderer.TriggerFlush(false); + //_pages.ActivePage().Buffer().Reset(); + } + + return !isConPty; +} + // Method Description: // - Performs a iTerm2 action // - Ascribes to the ITermDispatch interface diff --git a/src/terminal/adapter/adaptDispatch.hpp b/src/terminal/adapter/adaptDispatch.hpp index 76e32d0fdd5..d6b8c747436 100644 --- a/src/terminal/adapter/adaptDispatch.hpp +++ b/src/terminal/adapter/adaptDispatch.hpp @@ -146,6 +146,12 @@ namespace Microsoft::Console::VirtualTerminal bool DoITerm2Action(const std::wstring_view string) override; + bool DoWarpInBandGeneratorAction() override; + + bool DoWarpAction() override; + + bool DoWarpResetGridAction() override; + bool DoFinalTermAction(const std::wstring_view string) override; bool DoVsCodeAction(const std::wstring_view string) override; diff --git a/src/terminal/adapter/termDispatch.hpp b/src/terminal/adapter/termDispatch.hpp index 3a1d19a0964..422f80043bd 100644 --- a/src/terminal/adapter/termDispatch.hpp +++ b/src/terminal/adapter/termDispatch.hpp @@ -138,6 +138,11 @@ class Microsoft::Console::VirtualTerminal::TermDispatch : public Microsoft::Cons bool DoFinalTermAction(const std::wstring_view /*string*/) override { return false; } + bool DoWarpInBandGeneratorAction() override { return false; } + bool DoWarpAction() override { return false; } + + bool DoWarpResetGridAction() override { return false; } + bool DoVsCodeAction(const std::wstring_view /*string*/) override { return false; } StringHandler DownloadDRCS(const VTInt /*fontNumber*/, diff --git a/src/terminal/parser/OutputStateMachineEngine.cpp b/src/terminal/parser/OutputStateMachineEngine.cpp index 7568f154677..62a774df673 100644 --- a/src/terminal/parser/OutputStateMachineEngine.cpp +++ b/src/terminal/parser/OutputStateMachineEngine.cpp @@ -742,6 +742,10 @@ IStateMachineEngine::StringHandler OutputStateMachineEngine::ActionDcsDispatch(c case DcsActionCodes::DECRQSS_RequestSetting: handler = _dispatch->RequestSetting(); break; + case DcsActionCodes::DCS_WARP: + _dispatch->DoWarpAction(); + handler = nullptr; + break; case DcsActionCodes::DECRSPS_RestorePresentationState: handler = _dispatch->RestorePresentationState(parameters.at(0)); break; @@ -750,6 +754,13 @@ IStateMachineEngine::StringHandler OutputStateMachineEngine::ActionDcsDispatch(c break; } + // If we were unable to process the string, and there's a TTY attached to us, + // trigger the state machine to flush the string to the terminal. + if (_pfnFlushToTerminal != nullptr && handler == nullptr) + { + _pfnFlushToTerminal(); + } + _ClearLastChar(); return handler; @@ -903,6 +914,22 @@ bool OutputStateMachineEngine::ActionOscDispatch(const size_t parameter, const s success = _dispatch->DoITerm2Action(string); break; } + + case OscActionCodes::WarpInBandGeneratorAction: + { + success = _dispatch->DoWarpInBandGeneratorAction(); + break; + } + case OscActionCodes::WarpAction: + { + success = _dispatch->DoWarpAction(); + break; + } + case OscActionCodes::WarpResetGridAction: + { + success = _dispatch->DoWarpResetGridAction(); + break; + } case OscActionCodes::FinalTermAction: { success = _dispatch->DoFinalTermAction(string); diff --git a/src/terminal/parser/OutputStateMachineEngine.hpp b/src/terminal/parser/OutputStateMachineEngine.hpp index 0970e45dee2..e9783d130a8 100644 --- a/src/terminal/parser/OutputStateMachineEngine.hpp +++ b/src/terminal/parser/OutputStateMachineEngine.hpp @@ -188,6 +188,7 @@ namespace Microsoft::Console::VirtualTerminal DECRSTS_RestoreTerminalState = VTID("$p"), DECRQSS_RequestSetting = VTID("$q"), DECRSPS_RestorePresentationState = VTID("$t"), + DCS_WARP = VTID("d"), }; enum Vt52ActionCodes : uint64_t @@ -229,6 +230,9 @@ namespace Microsoft::Console::VirtualTerminal FinalTermAction = 133, VsCodeAction = 633, ITerm2Action = 1337, + WarpInBandGeneratorAction = 9277, + WarpAction = 9278, + WarpResetGridAction = 9279, }; bool _GetOscSetColorTable(const std::wstring_view string, From ab525862b728a1c61e0c7ee7f837fa1d3f61c849 Mon Sep 17 00:00:00 2001 From: Aloke Desai Date: Sat, 12 Oct 2024 17:54:31 -0400 Subject: [PATCH 2/2] Reset tests --- src/host/ut_host/VtRendererTests.cpp | 113 --------------------------- 1 file changed, 113 deletions(-) diff --git a/src/host/ut_host/VtRendererTests.cpp b/src/host/ut_host/VtRendererTests.cpp index 40fb47040f7..279012e71fe 100644 --- a/src/host/ut_host/VtRendererTests.cpp +++ b/src/host/ut_host/VtRendererTests.cpp @@ -69,7 +69,6 @@ class Microsoft::Console::Render::VtRendererTest TEST_METHOD(Xterm256TestInvalidate); TEST_METHOD(Xterm256TestColors); TEST_METHOD(Xterm256TestITUColors); - TEST_METHOD(Xterm256TestAloke); TEST_METHOD(Xterm256TestCursor); TEST_METHOD(Xterm256TestExtendedAttributes); TEST_METHOD(Xterm256TestAttributesAcrossReset); @@ -218,9 +217,6 @@ void VtRendererTest::VtSequenceHelperTests() qExpectedInput.push_back("\x1b[10C"); VERIFY_SUCCEEDED(engine->_CursorForward(10)); - - qExpectedInput.push_back("\x1b[10C"); - VERIFY_SUCCEEDED(engine->_CursorForward(10)); } void VtRendererTest::Xterm256TestInvalidate() @@ -695,115 +691,6 @@ void VtRendererTest::Xterm256TestITUColors() }); } -void VtRendererTest::Xterm256TestAloke() -{ - auto hFile = wil::unique_hfile(INVALID_HANDLE_VALUE); - auto engine = std::make_unique(std::move(hFile), SetUpViewport()); - auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2); - engine->SetTestCallback(pfn); - RenderSettings renderSettings; - RenderData renderData; - - VerifyFirstPaint(*engine); - - auto view = SetUpViewport(); - - Log::Comment(NoThrowString().Format( - L"Test changing the text attributes")); - - // Internally _lastTextAttributes starts with a fg and bg set to INVALID_COLOR(s), - // and initializing textAttributes with the default colors will output "\e[39m\e[49m" - // in the beginning. - auto textAttributes = TextAttribute{}; - qExpectedInput.push_back("\x1b[39m"); - qExpectedInput.push_back("\x1b[49m"); - - Log::Comment(NoThrowString().Format( - L"Begin by setting some test values - UL = (1,2,3) to start. " - L"This value is picked for ease of formatting raw COLORREF values.")); - qExpectedInput.push_back("\x1b[58:2::1:2:3m"); - textAttributes.SetUnderlineColor(RGB(1, 2, 3)); - VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, - renderSettings, - &renderData, - false, - false)); - - TestPaint(*engine, [&]() { - Log::Comment(NoThrowString().Format( - L"----Change the color----")); - qExpectedInput.push_back("\x1b[58:2::7:8:9m"); - textAttributes.SetUnderlineColor(RGB(7, 8, 9)); - VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, - renderSettings, - &renderData, - false, - false)); - }); - - TestPaint(*engine, [&]() { - Log::Comment(NoThrowString().Format( - L"Make sure that color setting persists across EndPaint/StartPaint")); - qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL); - VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, - renderSettings, - &renderData, - false, - false)); - WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback - }); - - TestPaint(*engine, [&]() { - Log::Comment(NoThrowString().Format( - L"----Change the UL color to a 256-color index----")); - textAttributes.SetUnderlineColor(TextColor{ TextColor::DARK_RED, true }); - qExpectedInput.push_back("\x1b[58:5:1m"); - VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, - renderSettings, - &renderData, - false, - false)); - - // to test the sequence for the default underline color, temporarily modify fg and bg to be something else. - textAttributes.SetForeground(RGB(9, 10, 11)); - qExpectedInput.push_back("\x1b[38;2;9;10;11m"); - textAttributes.SetBackground(RGB(5, 6, 7)); - qExpectedInput.push_back("\x1b[48;2;5;6;7m"); - - Log::Comment(NoThrowString().Format( - L"----Change only the UL color to the 'Default'----")); - textAttributes.SetDefaultUnderlineColor(); - qExpectedInput.push_back("\x1b[59m"); - VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, - renderSettings, - &renderData, - false, - false)); - - Log::Comment(NoThrowString().Format( - L"----Back to defaults (all colors)----")); - textAttributes = {}; - qExpectedInput.push_back("\x1b[m"); - VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, - renderSettings, - &renderData, - false, - false)); - }); - - TestPaint(*engine, [&]() { - Log::Comment(NoThrowString().Format( - L"Make sure that color setting persists across EndPaint/StartPaint")); - qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL); - VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes({}, - renderSettings, - &renderData, - false, - false)); - WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback - }); -} - void VtRendererTest::Xterm256TestCursor() { auto hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);