diff --git a/src/host/ut_host/ScreenBufferTests.cpp b/src/host/ut_host/ScreenBufferTests.cpp index bd54b1b462..fa3fbe5412 100644 --- a/src/host/ut_host/ScreenBufferTests.cpp +++ b/src/host/ut_host/ScreenBufferTests.cpp @@ -123,6 +123,7 @@ class ScreenBufferTests TEST_METHOD(VtResizePreservingAttributes); TEST_METHOD(VtSoftResetCursorPosition); + TEST_METHOD(VtSoftResetAltBufferCursorState); TEST_METHOD(VtScrollMarginsNewlineColor); @@ -1510,6 +1511,30 @@ void ScreenBufferTests::VtSoftResetCursorPosition() VERIFY_ARE_EQUAL(til::point(1, 1), cursor.GetPosition()); } +void ScreenBufferTests::VtSoftResetAltBufferCursorState() +{ + auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); + gci.LockConsole(); // Lock must be taken to manipulate buffer. + auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); }); + + auto& si = gci.GetActiveOutputBuffer(); + auto& stateMachine = si.GetStateMachine(); + + Log::Comment(L"Move cursor on the main buffer."); + stateMachine.ProcessString(L"\x1b[4;7H"); + VERIFY_ARE_EQUAL(til::point(6, 3), si.GetTextBuffer().GetCursor().GetPosition()); + + Log::Comment(L"Enter alt buffer, soft reset, and return to main buffer."); + stateMachine.ProcessString(L"\x1b[?1049h"); + VERIFY_IS_TRUE(gci.GetActiveOutputBuffer()._IsAltBuffer()); + stateMachine.ProcessString(L"\x1b[!p"); + stateMachine.ProcessString(L"\x1b[?1049l"); + VERIFY_IS_FALSE(gci.GetActiveOutputBuffer()._IsAltBuffer()); + + Log::Comment(L"Returning from alt buffer should restore the main cursor position."); + VERIFY_ARE_EQUAL(til::point(6, 3), gci.GetActiveOutputBuffer().GetTextBuffer().GetCursor().GetPosition()); +} + void ScreenBufferTests::VtScrollMarginsNewlineColor() { auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp index e1fdb6a69c..633156c51d 100644 --- a/src/terminal/adapter/adaptDispatch.cpp +++ b/src/terminal/adapter/adaptDispatch.cpp @@ -3002,17 +3002,15 @@ void AdaptDispatch::SoftReset() SetGraphicsRendition({}); // Normal rendition. SetCharacterProtectionAttribute({}); // Default (unprotected) - // Reset the saved cursor state. - // Note that XTerm only resets the main buffer state, but that - // seems likely to be a bug. Most other terminals reset both. - _savedCursorState.at(0) = {}; // Main buffer - _savedCursorState.at(1) = {}; // Alt buffer + // Reset only the active saved cursor state. + // This matches xterm behavior when DECSTR is processed while using + // the alternate screen buffer (GH#19918). + _savedCursorState.at(_usingAltBuffer ? 1 : 0) = {}; - // The TerminalOutput state in these buffers must be reset to + // The TerminalOutput state in this buffer must be reset to // the same state as the _termOutput instance, which is not // necessarily equivalent to a full reset. - _savedCursorState.at(0).TermOutput = _termOutput; - _savedCursorState.at(1).TermOutput = _termOutput; + _savedCursorState.at(_usingAltBuffer ? 1 : 0).TermOutput = _termOutput; // Soft reset the Sixel parser if in use. if (_sixelParser)