From dfb52331f8f57784f51cef78c704f181221a90da Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Tue, 6 Aug 2024 14:23:03 +0200 Subject: [PATCH] Remove VT color quirk for PowerShell (#17666) Roughly 4 years ago we gave Windows Terminal the ability to differentiate between black/white and the default colors. One of the victims was PowerShell and most importantly PSReadLine, which emit SRG 37 & 40 when what they really want is 38 & 48. We fixed this on our side by adding a shim. Since the addition of VT passthrough in #17510 we now intentionally lost the ability to translate VT sequences from one thing to another. This meant we also lost the ability to do this shim and as such this PR removes it. Luckily Windows 11 now ships PSReadLine 2.0.0, which contains a proper fix for this. Unfortunately, this is not the case for Windows 10, which ships PSReadLine 2.0.0-beta2. Users affected by this will have to install a newer version of PSReadLine or use the default black/white theme. See 1bf4c082b4586dd056a9e67e363b5ab22197b09f Closes #13037 --- src/buffer/out/TextAttribute.cpp | 41 -------- src/buffer/out/TextAttribute.hpp | 1 - src/host/ApiRoutines.h | 2 - src/host/_stream.cpp | 24 +---- src/host/_stream.h | 1 - src/host/screenInfo.cpp | 24 +---- src/host/screenInfo.hpp | 5 - src/host/ut_host/ApiRoutinesTests.cpp | 4 +- src/host/ut_host/ScreenBufferTests.cpp | 129 +------------------------ src/host/ut_host/TextBufferTests.cpp | 12 +-- src/host/ut_host/VtIoTests.cpp | 6 +- src/host/writeData.cpp | 5 +- src/host/writeData.hpp | 4 +- src/server/ApiDispatchers.cpp | 6 +- src/server/ConsoleShimPolicy.cpp | 30 ------ src/server/ConsoleShimPolicy.h | 2 - src/server/IApiRoutines.h | 2 - 17 files changed, 23 insertions(+), 275 deletions(-) diff --git a/src/buffer/out/TextAttribute.cpp b/src/buffer/out/TextAttribute.cpp index 65799d1d6f..f95edf6bea 100644 --- a/src/buffer/out/TextAttribute.cpp +++ b/src/buffer/out/TextAttribute.cpp @@ -65,47 +65,6 @@ void TextAttribute::SetLegacyDefaultAttributes(const WORD defaultAttributes) noe gsl::at(s_legacyBackgroundColorMap, s_legacyDefaultBackground) = TextColor{}; } -// Routine Description: -// Pursuant to GH#6807 -// This routine replaces VT colors from the 16-color set with the "default" -// flag. It is intended to be used as part of the "VT Quirk" in -// WriteConsole[AW]. -// -// There is going to be a very long tail of applications that will -// explicitly request VT SGR 40/37 when what they really want is to -// SetConsoleTextAttribute() with a black background/white foreground. -// Instead of making those applications look bad (and therefore making us -// look bad, because we're releasing this as an update to something that -// "looks good" already), we're introducing this compatibility hack. Before -// the color reckoning in GH#6698 + GH#6506, *every* color was subject to -// being spontaneously and erroneously turned into the default color. Now, -// only the 16-color palette value that matches the active console -// background color will be destroyed when the quirk is enabled. -// -// This is not intended to be a long-term solution. This comment will be -// discovered in forty years(*) time and people will laugh at our hubris. -// -// *it doesn't matter when you're reading this, it will always be 40 years -// from now. -TextAttribute TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults(const TextAttribute& attribute) noexcept -{ - const auto fg{ attribute.GetForeground() }; - const auto bg{ attribute.GetBackground() }; - auto copy{ attribute }; - if (fg.IsIndex16() && - attribute.IsIntense() == WI_IsFlagSet(s_ansiDefaultForeground, FOREGROUND_INTENSITY) && - fg.GetIndex() == (s_ansiDefaultForeground & ~FOREGROUND_INTENSITY)) - { - // We don't want to turn 1;37m into 39m (or even 1;39m), as this was meant to mimic a legacy color. - copy.SetDefaultForeground(); - } - if (bg.IsIndex16() && bg.GetIndex() == s_ansiDefaultBackground) - { - copy.SetDefaultBackground(); - } - return copy; -} - // Routine Description: // - Returns a WORD with legacy-style attributes for this textattribute. // Parameters: diff --git a/src/buffer/out/TextAttribute.hpp b/src/buffer/out/TextAttribute.hpp index 44d8563176..b1d69d1f3b 100644 --- a/src/buffer/out/TextAttribute.hpp +++ b/src/buffer/out/TextAttribute.hpp @@ -93,7 +93,6 @@ public: } static void SetLegacyDefaultAttributes(const WORD defaultAttributes) noexcept; - static TextAttribute StripErroneousVT16VersionsOfLegacyDefaults(const TextAttribute& attribute) noexcept; WORD GetLegacyAttributes() const noexcept; bool IsTopHorizontalDisplayed() const noexcept; diff --git a/src/host/ApiRoutines.h b/src/host/ApiRoutines.h index 7301c17219..3187f8ff9d 100644 --- a/src/host/ApiRoutines.h +++ b/src/host/ApiRoutines.h @@ -72,13 +72,11 @@ public: [[nodiscard]] HRESULT WriteConsoleAImpl(IConsoleOutputObject& context, const std::string_view buffer, size_t& read, - bool requiresVtQuirk, std::unique_ptr& waiter) noexcept override; [[nodiscard]] HRESULT WriteConsoleWImpl(IConsoleOutputObject& context, const std::wstring_view buffer, size_t& read, - bool requiresVtQuirk, std::unique_ptr& waiter) noexcept override; #pragma region ThreadCreationInfo diff --git a/src/host/_stream.cpp b/src/host/_stream.cpp index 9c3d3378a8..4dc98cae90 100644 --- a/src/host/_stream.cpp +++ b/src/host/_stream.cpp @@ -406,7 +406,6 @@ void WriteClearScreen(SCREEN_INFORMATION& screenInfo) [[nodiscard]] NTSTATUS DoWriteConsole(_In_reads_bytes_(*pcbBuffer) PCWCHAR pwchBuffer, _Inout_ size_t* const pcbBuffer, SCREEN_INFORMATION& screenInfo, - bool requiresVtQuirk, std::unique_ptr& waiter) try { @@ -416,22 +415,10 @@ try waiter = std::make_unique(screenInfo, pwchBuffer, *pcbBuffer, - gci.OutputCP, - requiresVtQuirk); + gci.OutputCP); return CONSOLE_STATUS_WAIT; } - const auto restoreVtQuirk = wil::scope_exit([&]() { - if (requiresVtQuirk) - { - screenInfo.ResetIgnoreLegacyEquivalentVTAttributes(); - } - }); - if (requiresVtQuirk) - { - screenInfo.SetIgnoreLegacyEquivalentVTAttributes(); - } - const std::wstring_view str{ pwchBuffer, *pcbBuffer / sizeof(WCHAR) }; if (WI_IsAnyFlagClear(screenInfo.OutputMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT)) @@ -464,7 +451,6 @@ NT_CATCH_RETURN() [[nodiscard]] HRESULT WriteConsoleWImplHelper(IConsoleOutputObject& context, const std::wstring_view buffer, size_t& read, - bool requiresVtQuirk, std::unique_ptr& waiter) noexcept { try @@ -477,7 +463,7 @@ NT_CATCH_RETURN() size_t cbTextBufferLength; RETURN_IF_FAILED(SizeTMult(buffer.size(), sizeof(wchar_t), &cbTextBufferLength)); - auto Status = DoWriteConsole(const_cast(buffer.data()), &cbTextBufferLength, context, requiresVtQuirk, waiter); + auto Status = DoWriteConsole(const_cast(buffer.data()), &cbTextBufferLength, context, waiter); // Convert back from bytes to characters for the resulting string length written. read = cbTextBufferLength / sizeof(wchar_t); @@ -510,7 +496,6 @@ NT_CATCH_RETURN() [[nodiscard]] HRESULT ApiRoutines::WriteConsoleAImpl(IConsoleOutputObject& context, const std::string_view buffer, size_t& read, - bool requiresVtQuirk, std::unique_ptr& waiter) noexcept { try @@ -622,7 +607,7 @@ NT_CATCH_RETURN() // Make the W version of the call size_t wcBufferWritten{}; - const auto hr{ WriteConsoleWImplHelper(screenInfo, wstr, wcBufferWritten, requiresVtQuirk, writeDataWaiter) }; + const auto hr{ WriteConsoleWImplHelper(screenInfo, wstr, wcBufferWritten, writeDataWaiter) }; // If there is no waiter, process the byte count now. if (nullptr == writeDataWaiter.get()) @@ -700,7 +685,6 @@ NT_CATCH_RETURN() [[nodiscard]] HRESULT ApiRoutines::WriteConsoleWImpl(IConsoleOutputObject& context, const std::wstring_view buffer, size_t& read, - bool requiresVtQuirk, std::unique_ptr& waiter) noexcept { try @@ -709,7 +693,7 @@ NT_CATCH_RETURN() auto unlock = wil::scope_exit([&] { UnlockConsole(); }); std::unique_ptr writeDataWaiter; - RETURN_IF_FAILED(WriteConsoleWImplHelper(context.GetActiveBuffer(), buffer, read, requiresVtQuirk, writeDataWaiter)); + RETURN_IF_FAILED(WriteConsoleWImplHelper(context.GetActiveBuffer(), buffer, read, writeDataWaiter)); // Transfer specific waiter pointer into the generic interface wrapper. waiter.reset(writeDataWaiter.release()); diff --git a/src/host/_stream.h b/src/host/_stream.h index 351b917301..4651deb800 100644 --- a/src/host/_stream.h +++ b/src/host/_stream.h @@ -28,5 +28,4 @@ void WriteClearScreen(SCREEN_INFORMATION& screenInfo); [[nodiscard]] NTSTATUS DoWriteConsole(_In_reads_bytes_(pcbBuffer) const wchar_t* pwchBuffer, _Inout_ size_t* const pcbBuffer, SCREEN_INFORMATION& screenInfo, - bool requiresVtQuirk, std::unique_ptr& waiter); diff --git a/src/host/screenInfo.cpp b/src/host/screenInfo.cpp index 0084dc5bce..8d5e921724 100644 --- a/src/host/screenInfo.cpp +++ b/src/host/screenInfo.cpp @@ -41,8 +41,7 @@ SCREEN_INFORMATION::SCREEN_INFORMATION( _PopupAttributes{ popupAttributes }, _virtualBottom{ 0 }, _currentFont{ fontInfo }, - _desiredFont{ fontInfo }, - _ignoreLegacyEquivalentVTAttributes{ false } + _desiredFont{ fontInfo } { // Check if VT mode should be enabled by default. This can be true if // VirtualTerminalLevel is set to !=0 in the registry, or when conhost @@ -2014,13 +2013,6 @@ const TextAttribute& SCREEN_INFORMATION::GetPopupAttributes() const noexcept // void SCREEN_INFORMATION::SetAttributes(const TextAttribute& attributes) { - if (_ignoreLegacyEquivalentVTAttributes) - { - // See the comment on StripErroneousVT16VersionsOfLegacyDefaults for more info. - _textBuffer->SetCurrentAttributes(TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults(attributes)); - return; - } - _textBuffer->SetCurrentAttributes(attributes); // If we're an alt buffer, DON'T propagate this setting up to the main buffer. @@ -2466,17 +2458,3 @@ const FontInfoDesired& SCREEN_INFORMATION::GetDesiredFont() const noexcept { return _desiredFont; } - -// Routine Description: -// - Engages the legacy VT handling quirk; see TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults -void SCREEN_INFORMATION::SetIgnoreLegacyEquivalentVTAttributes() noexcept -{ - _ignoreLegacyEquivalentVTAttributes = true; -} - -// Routine Description: -// - Disengages the legacy VT handling quirk; see TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults -void SCREEN_INFORMATION::ResetIgnoreLegacyEquivalentVTAttributes() noexcept -{ - _ignoreLegacyEquivalentVTAttributes = false; -} diff --git a/src/host/screenInfo.hpp b/src/host/screenInfo.hpp index 7f0b9357a1..4ecd1a4e3e 100644 --- a/src/host/screenInfo.hpp +++ b/src/host/screenInfo.hpp @@ -213,9 +213,6 @@ public: FontInfoDesired& GetDesiredFont() noexcept; const FontInfoDesired& GetDesiredFont() const noexcept; - void SetIgnoreLegacyEquivalentVTAttributes() noexcept; - void ResetIgnoreLegacyEquivalentVTAttributes() noexcept; - [[nodiscard]] NTSTATUS ResizeWithReflow(const til::size coordnewScreenSize); [[nodiscard]] NTSTATUS ResizeTraditional(const til::size coordNewScreenSize); @@ -277,8 +274,6 @@ private: // the viewport to move (SetBufferInfo, WriteConsole, etc) til::CoordType _virtualBottom; - bool _ignoreLegacyEquivalentVTAttributes; - std::optional _deferredPtyResize{ std::nullopt }; static void _handleDeferredResize(SCREEN_INFORMATION& siMain); diff --git a/src/host/ut_host/ApiRoutinesTests.cpp b/src/host/ut_host/ApiRoutinesTests.cpp index c0edafe11d..37e6ec62fd 100644 --- a/src/host/ut_host/ApiRoutinesTests.cpp +++ b/src/host/ut_host/ApiRoutinesTests.cpp @@ -385,7 +385,7 @@ class ApiRoutinesTests const auto cchWriteLength = std::min(cchIncrement, cchTestText - i); // Run the test method - const auto hr = _pApiRoutines->WriteConsoleAImpl(si, { pszTestText + i, cchWriteLength }, cchRead, false, waiter); + const auto hr = _pApiRoutines->WriteConsoleAImpl(si, { pszTestText + i, cchWriteLength }, cchRead, waiter); VERIFY_ARE_EQUAL(S_OK, hr, L"Successful result code from writing."); if (!fInduceWait) @@ -441,7 +441,7 @@ class ApiRoutinesTests size_t cchRead = 0; std::unique_ptr waiter; - const auto hr = _pApiRoutines->WriteConsoleWImpl(si, testText, cchRead, false, waiter); + const auto hr = _pApiRoutines->WriteConsoleWImpl(si, testText, cchRead, waiter); VERIFY_ARE_EQUAL(S_OK, hr, L"Successful result code from writing."); if (!fInduceWait) diff --git a/src/host/ut_host/ScreenBufferTests.cpp b/src/host/ut_host/ScreenBufferTests.cpp index a4a57e53f5..d1fe5a3196 100644 --- a/src/host/ut_host/ScreenBufferTests.cpp +++ b/src/host/ut_host/ScreenBufferTests.cpp @@ -248,8 +248,6 @@ class ScreenBufferTests TEST_METHOD(DontChangeVirtualBottomWithMakeCursorVisible); TEST_METHOD(RetainHorizontalOffsetWhenMovingToBottom); - TEST_METHOD(TestWriteConsoleVTQuirkMode); - TEST_METHOD(TestReflowEndOfLineColor); TEST_METHOD(TestReflowSmallerLongLineWithColor); TEST_METHOD(TestReflowBiggerLongLineWithColor); @@ -2548,7 +2546,7 @@ void ScreenBufferTests::TestAltBufferVtDispatching() std::unique_ptr waiter; std::wstring seq = L"\x1b[5;6H"; auto seqCb = 2 * seq.size(); - VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, false, waiter)); + VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, waiter)); VERIFY_ARE_EQUAL(til::point(0, 0), mainCursor.GetPosition()); // recall: vt coordinates are (row, column), 1-indexed @@ -2563,14 +2561,14 @@ void ScreenBufferTests::TestAltBufferVtDispatching() seq = L"\x1b[48;2;255;0;255m"; seqCb = 2 * seq.size(); - VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, false, waiter)); + VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, waiter)); VERIFY_ARE_EQUAL(expectedDefaults, mainBuffer.GetAttributes()); VERIFY_ARE_EQUAL(expectedRgb, alternate.GetAttributes()); seq = L"X"; seqCb = 2 * seq.size(); - VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, false, waiter)); + VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, waiter)); VERIFY_ARE_EQUAL(til::point(0, 0), mainCursor.GetPosition()); VERIFY_ARE_EQUAL(til::point(6, 4), altCursor.GetPosition()); @@ -7565,127 +7563,6 @@ void ScreenBufferTests::RetainHorizontalOffsetWhenMovingToBottom() VERIFY_ARE_EQUAL(initialOrigin.x, si.GetViewport().Left()); } -void ScreenBufferTests::TestWriteConsoleVTQuirkMode() -{ - BEGIN_TEST_METHOD_PROPERTIES() - TEST_METHOD_PROPERTY(L"Data:useQuirk", L"{false, true}") - END_TEST_METHOD_PROPERTIES() - - bool useQuirk; - VERIFY_SUCCEEDED(TestData::TryGetValue(L"useQuirk", useQuirk), L"whether to enable the quirk"); - - auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); - gci.LockConsole(); // Lock must be taken to manipulate buffer. - auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); }); - - auto& mainBuffer = gci.GetActiveOutputBuffer(); - auto& cursor = mainBuffer.GetTextBuffer().GetCursor(); - // Make sure we're in VT mode - WI_SetFlag(mainBuffer.OutputMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING); - - const TextAttribute defaultAttribute{}; - // Make sure we're using the default attributes at the start of the test, - // Otherwise they could be polluted from a previous test. - mainBuffer.SetAttributes(defaultAttribute); - - const auto verifyLastAttribute = [&](const TextAttribute& expected) { - const auto& row = mainBuffer.GetTextBuffer().GetRowByOffset(cursor.GetPosition().y); - auto iter{ row.AttrBegin() }; - iter += cursor.GetPosition().x - 1; - VERIFY_ARE_EQUAL(expected, *iter); - }; - - std::unique_ptr waiter; - - std::wstring seq{}; - size_t seqCb{ 0 }; - - /* Write red on blue, verify that it comes through */ - { - TextAttribute vtRedOnBlueAttribute{}; - vtRedOnBlueAttribute.SetForeground(TextColor{ TextColor::DARK_RED, false }); - vtRedOnBlueAttribute.SetBackground(TextColor{ TextColor::DARK_BLUE, false }); - - seq = L"\x1b[31;44m"; - seqCb = 2 * seq.size(); - VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, useQuirk, waiter)); - - VERIFY_ARE_EQUAL(vtRedOnBlueAttribute, mainBuffer.GetAttributes()); - - seq = L"X"; - seqCb = 2 * seq.size(); - VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, useQuirk, waiter)); - - verifyLastAttribute(vtRedOnBlueAttribute); - } - - /* Write white on black, verify that it acts as expected for the quirk mode */ - { - TextAttribute vtWhiteOnBlackAttribute{}; - vtWhiteOnBlackAttribute.SetForeground(TextColor{ TextColor::DARK_WHITE, false }); - vtWhiteOnBlackAttribute.SetBackground(TextColor{ TextColor::DARK_BLACK, false }); - - const auto quirkExpectedAttribute{ useQuirk ? defaultAttribute : vtWhiteOnBlackAttribute }; - - seq = L"\x1b[37;40m"; // the quirk should suppress this, turning it into "defaults" - seqCb = 2 * seq.size(); - VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, useQuirk, waiter)); - - VERIFY_ARE_EQUAL(quirkExpectedAttribute, mainBuffer.GetAttributes()); - - seq = L"X"; - seqCb = 2 * seq.size(); - VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, useQuirk, waiter)); - - verifyLastAttribute(quirkExpectedAttribute); - } - - /* Write bright white on black, verify that it acts as expected for the quirk mode */ - { - TextAttribute vtBrightWhiteOnBlackAttribute{}; - vtBrightWhiteOnBlackAttribute.SetForeground(TextColor{ TextColor::DARK_WHITE, false }); - vtBrightWhiteOnBlackAttribute.SetBackground(TextColor{ TextColor::DARK_BLACK, false }); - vtBrightWhiteOnBlackAttribute.SetIntense(true); - - auto vtBrightWhiteOnDefaultAttribute{ vtBrightWhiteOnBlackAttribute }; // copy the above attribute - vtBrightWhiteOnDefaultAttribute.SetDefaultBackground(); - - const auto quirkExpectedAttribute{ useQuirk ? vtBrightWhiteOnDefaultAttribute : vtBrightWhiteOnBlackAttribute }; - - seq = L"\x1b[1;37;40m"; // the quirk should suppress black only, turning it into "default background" - seqCb = 2 * seq.size(); - VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, useQuirk, waiter)); - - VERIFY_ARE_EQUAL(quirkExpectedAttribute, mainBuffer.GetAttributes()); - - seq = L"X"; - seqCb = 2 * seq.size(); - VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, useQuirk, waiter)); - - verifyLastAttribute(quirkExpectedAttribute); - } - - /* Write a 256-color white on a 256-color black, make sure the quirk does not suppress it */ - { - TextAttribute vtWhiteOnBlack256Attribute{}; - vtWhiteOnBlack256Attribute.SetForeground(TextColor{ TextColor::DARK_WHITE, true }); - vtWhiteOnBlack256Attribute.SetBackground(TextColor{ TextColor::DARK_BLACK, true }); - - // reset (disable intense from the last test) before setting both colors - seq = L"\x1b[m\x1b[38;5;7;48;5;0m"; // the quirk should *not* suppress this (!) - seqCb = 2 * seq.size(); - VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, useQuirk, waiter)); - - VERIFY_ARE_EQUAL(vtWhiteOnBlack256Attribute, mainBuffer.GetAttributes()); - - seq = L"X"; - seqCb = 2 * seq.size(); - VERIFY_SUCCEEDED(DoWriteConsole(&seq[0], &seqCb, mainBuffer, useQuirk, waiter)); - - verifyLastAttribute(vtWhiteOnBlack256Attribute); - } -} - void ScreenBufferTests::TestReflowEndOfLineColor() { BEGIN_TEST_METHOD_PROPERTIES() diff --git a/src/host/ut_host/TextBufferTests.cpp b/src/host/ut_host/TextBufferTests.cpp index 1f6a71312b..2d6c1d1628 100644 --- a/src/host/ut_host/TextBufferTests.cpp +++ b/src/host/ut_host/TextBufferTests.cpp @@ -1396,16 +1396,16 @@ void TextBufferTests::TestBackspaceStringsAPI() L"Using WriteCharsLegacy, write \\b \\b as a single string.")); size_t aCb = 2; size_t seqCb = 6; - VERIFY_SUCCEEDED(DoWriteConsole(L"a", &aCb, si, false, waiter)); - VERIFY_SUCCEEDED(DoWriteConsole(L"\b \b", &seqCb, si, false, waiter)); + VERIFY_SUCCEEDED(DoWriteConsole(L"a", &aCb, si, waiter)); + VERIFY_SUCCEEDED(DoWriteConsole(L"\b \b", &seqCb, si, waiter)); VERIFY_ARE_EQUAL(cursor.GetPosition().x, x0); VERIFY_ARE_EQUAL(cursor.GetPosition().y, y0); seqCb = 2; - VERIFY_SUCCEEDED(DoWriteConsole(L"a", &seqCb, si, false, waiter)); - VERIFY_SUCCEEDED(DoWriteConsole(L"\b", &seqCb, si, false, waiter)); - VERIFY_SUCCEEDED(DoWriteConsole(L" ", &seqCb, si, false, waiter)); - VERIFY_SUCCEEDED(DoWriteConsole(L"\b", &seqCb, si, false, waiter)); + VERIFY_SUCCEEDED(DoWriteConsole(L"a", &seqCb, si, waiter)); + VERIFY_SUCCEEDED(DoWriteConsole(L"\b", &seqCb, si, waiter)); + VERIFY_SUCCEEDED(DoWriteConsole(L" ", &seqCb, si, waiter)); + VERIFY_SUCCEEDED(DoWriteConsole(L"\b", &seqCb, si, waiter)); VERIFY_ARE_EQUAL(cursor.GetPosition().x, x0); VERIFY_ARE_EQUAL(cursor.GetPosition().y, y0); } diff --git a/src/host/ut_host/VtIoTests.cpp b/src/host/ut_host/VtIoTests.cpp index 1a6085b498..2f2ef1219b 100644 --- a/src/host/ut_host/VtIoTests.cpp +++ b/src/host/ut_host/VtIoTests.cpp @@ -241,19 +241,19 @@ class ::Microsoft::Console::VirtualTerminal::VtIoTests std::string_view expected; std::string_view actual; - THROW_IF_FAILED(routines.WriteConsoleWImpl(*screenInfo, L"", written, false, waiter)); + THROW_IF_FAILED(routines.WriteConsoleWImpl(*screenInfo, L"", written, waiter)); expected = ""; actual = readOutput(); VERIFY_ARE_EQUAL(expected, actual); // Force-wrap because we write up to the last column. - THROW_IF_FAILED(routines.WriteConsoleWImpl(*screenInfo, L"aaaaaaaa", written, false, waiter)); + THROW_IF_FAILED(routines.WriteConsoleWImpl(*screenInfo, L"aaaaaaaa", written, waiter)); expected = "aaaaaaaa\r\n"; actual = readOutput(); VERIFY_ARE_EQUAL(expected, actual); // Force-wrap because we write up to the last column, but this time with a tab. - THROW_IF_FAILED(routines.WriteConsoleWImpl(*screenInfo, L"a\t\r\nb", written, false, waiter)); + THROW_IF_FAILED(routines.WriteConsoleWImpl(*screenInfo, L"a\t\r\nb", written, waiter)); expected = "a\t\r\n\r\nb"; actual = readOutput(); VERIFY_ARE_EQUAL(expected, actual); diff --git a/src/host/writeData.cpp b/src/host/writeData.cpp index 21b1cbee56..dcf49c54c0 100644 --- a/src/host/writeData.cpp +++ b/src/host/writeData.cpp @@ -24,14 +24,12 @@ WriteData::WriteData(SCREEN_INFORMATION& siContext, _In_reads_bytes_(cbContext) PCWCHAR pwchContext, const size_t cbContext, - const UINT uiOutputCodepage, - const bool requiresVtQuirk) : + const UINT uiOutputCodepage) : IWaitRoutine(ReplyDataType::Write), _siContext(siContext), _pwchContext(THROW_IF_NULL_ALLOC(reinterpret_cast(new byte[cbContext]))), _cbContext(cbContext), _uiOutputCodepage(uiOutputCodepage), - _requiresVtQuirk(requiresVtQuirk), _fLeadByteCaptured(false), _fLeadByteConsumed(false), _cchUtf8Consumed(0) @@ -126,7 +124,6 @@ bool WriteData::Notify(const WaitTerminationReason TerminationReason, auto Status = DoWriteConsole(_pwchContext, &cbContext, _siContext, - _requiresVtQuirk, waiter); if (Status == CONSOLE_STATUS_WAIT) diff --git a/src/host/writeData.hpp b/src/host/writeData.hpp index 120689d52a..4609b98d37 100644 --- a/src/host/writeData.hpp +++ b/src/host/writeData.hpp @@ -27,8 +27,7 @@ public: WriteData(SCREEN_INFORMATION& siContext, _In_reads_bytes_(cbContext) PCWCHAR pwchContext, const size_t cbContext, - const UINT uiOutputCodepage, - const bool requiresVtQuirk); + const UINT uiOutputCodepage); ~WriteData(); void SetLeadByteAdjustmentStatus(const bool fLeadByteCaptured, @@ -49,7 +48,6 @@ private: wchar_t* const _pwchContext; const size_t _cbContext; UINT const _uiOutputCodepage; - bool _requiresVtQuirk; bool _fLeadByteCaptured; bool _fLeadByteConsumed; size_t _cchUtf8Consumed; diff --git a/src/server/ApiDispatchers.cpp b/src/server/ApiDispatchers.cpp index 3ae2b735e9..96ddb0b674 100644 --- a/src/server/ApiDispatchers.cpp +++ b/src/server/ApiDispatchers.cpp @@ -374,8 +374,6 @@ constexpr T saturate(auto val) std::unique_ptr waiter; size_t cbRead; - const auto requiresVtQuirk{ m->GetProcessHandle()->GetShimPolicy().IsVtColorQuirkRequired() }; - // We have to hold onto the HR from the call and return it. // We can't return some other error after the actual API call. // This is because the write console function is allowed to write part of the string and then return an error. @@ -391,7 +389,7 @@ constexpr T saturate(auto val) TraceLoggingUInt32(a->NumBytes, "NumBytes"), TraceLoggingCountedWideString(buffer.data(), static_cast(buffer.size()), "Buffer")); - hr = m->_pApiRoutines->WriteConsoleWImpl(*pScreenInfo, buffer, cchInputRead, requiresVtQuirk, waiter); + hr = m->_pApiRoutines->WriteConsoleWImpl(*pScreenInfo, buffer, cchInputRead, waiter); // We must set the reply length in bytes. Convert back from characters. LOG_IF_FAILED(SizeTMult(cchInputRead, sizeof(wchar_t), &cbRead)); @@ -406,7 +404,7 @@ constexpr T saturate(auto val) TraceLoggingUInt32(a->NumBytes, "NumBytes"), TraceLoggingCountedString(buffer.data(), static_cast(buffer.size()), "Buffer")); - hr = m->_pApiRoutines->WriteConsoleAImpl(*pScreenInfo, buffer, cchInputRead, requiresVtQuirk, waiter); + hr = m->_pApiRoutines->WriteConsoleAImpl(*pScreenInfo, buffer, cchInputRead, waiter); // Reply length is already in bytes (chars), don't need to convert. cbRead = cchInputRead; diff --git a/src/server/ConsoleShimPolicy.cpp b/src/server/ConsoleShimPolicy.cpp index 7f6cc56d69..5ca506bd9a 100644 --- a/src/server/ConsoleShimPolicy.cpp +++ b/src/server/ConsoleShimPolicy.cpp @@ -27,24 +27,6 @@ ConsoleShimPolicy::ConsoleShimPolicy(const HANDLE hProcess) const auto isInboxPowershell = til::equals_insensitive_ascii(clientName, L"powershell.exe"); const auto isPwsh = til::equals_insensitive_ascii(clientName, L"pwsh.exe"); _isPowershell = isInboxPowershell || isPwsh; - - // Inside Windows, we are guaranteed that we're building alongside a new (good) inbox Powershell. - // Therefore, we can default _requiresVtColorQuirk to false. -#ifndef __INSIDE_WINDOWS - // Outside of Windows, we need to check the OS version: Powershell was fixed in early Iron builds. - static auto doesInboxPowershellVersionRequireQuirk = [] { - OSVERSIONINFOEXW osver{}; - osver.dwOSVersionInfoSize = sizeof(osver); - osver.dwBuildNumber = 20348; // Windows Server 2022 RTM - - DWORDLONG dwlConditionMask = 0; - VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_LESS); - - return VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE; - }(); - _requiresVtColorQuirk = isInboxPowershell && doesInboxPowershellVersionRequireQuirk; - // All modern versions of pwsh.exe have been fixed, and we can direct users to update. -#endif } CATCH_LOG(); } @@ -73,15 +55,3 @@ bool ConsoleShimPolicy::IsPowershellExe() const noexcept { return _isPowershell; } - -// Method Description: -// - Returns true if the connected client application is known to -// attempt VT color promotion of legacy colors. See GH#6807 for more. -// Arguments: -// - -// Return Value: -// - True as laid out above. -bool ConsoleShimPolicy::IsVtColorQuirkRequired() const noexcept -{ - return _requiresVtColorQuirk; -} diff --git a/src/server/ConsoleShimPolicy.h b/src/server/ConsoleShimPolicy.h index 38c4221710..120ed3f8a7 100644 --- a/src/server/ConsoleShimPolicy.h +++ b/src/server/ConsoleShimPolicy.h @@ -24,10 +24,8 @@ public: ConsoleShimPolicy(const HANDLE hProcess); bool IsCmdExe() const noexcept; bool IsPowershellExe() const noexcept; - bool IsVtColorQuirkRequired() const noexcept; private: bool _isCmd{ false }; bool _isPowershell{ false }; - bool _requiresVtColorQuirk{ false }; }; diff --git a/src/server/IApiRoutines.h b/src/server/IApiRoutines.h index 72386c4981..579cbddb8f 100644 --- a/src/server/IApiRoutines.h +++ b/src/server/IApiRoutines.h @@ -80,13 +80,11 @@ public: [[nodiscard]] virtual HRESULT WriteConsoleAImpl(IConsoleOutputObject& context, const std::string_view buffer, size_t& read, - bool requiresVtQuirk, std::unique_ptr& waiter) noexcept = 0; [[nodiscard]] virtual HRESULT WriteConsoleWImpl(IConsoleOutputObject& context, const std::wstring_view buffer, size_t& read, - bool requiresVtQuirk, std::unique_ptr& waiter) noexcept = 0; #pragma region Thread Creation Info