@@ -179,6 +179,8 @@ class ScreenBufferTests
179179
180180TEST_METHOD (RestoreDownAltBufferWithTerminalScrolling);
181181
182+ TEST_METHOD (SnapCursorWithTerminalScrolling);
183+
182184TEST_METHOD (ClearAlternateBuffer);
183185
184186TEST_METHOD (InitializeTabStopsInVTMode);
@@ -4288,6 +4290,81 @@ void ScreenBufferTests::RestoreDownAltBufferWithTerminalScrolling()
42884290 }
42894291}
42904292
4293+ void ScreenBufferTests::SnapCursorWithTerminalScrolling ()
4294+ {
4295+ // This is a test for microsoft/terminal#1222. Refer to that issue for more
4296+ // context
4297+
4298+ auto & g =ServiceLocator::LocateGlobals ();
4299+ CONSOLE_INFORMATION& gci = g.getConsoleInformation ();
4300+ gci.SetTerminalScrolling (true );
4301+ gci.LockConsole ();// Lock must be taken to manipulate buffer.
4302+ auto unlock =wil::scope_exit ([&] { gci.UnlockConsole (); });
4303+
4304+ auto & si = gci.GetActiveOutputBuffer ();
4305+ auto & cursor = si.GetTextBuffer ().GetCursor ();
4306+ const auto originalView = si._viewport ;
4307+ si._virtualBottom = originalView.BottomInclusive ();
4308+
4309+ Log::Comment (NoThrowString ().Format (
4310+ L" cursor=%s" , VerifyOutputTraits<COORD>::ToString (cursor.GetPosition ()).GetBuffer ()));
4311+ Log::Comment (NoThrowString ().Format (
4312+ L" originalView=%s" , VerifyOutputTraits<SMALL_RECT>::ToString (originalView.ToInclusive ()).GetBuffer ()));
4313+
4314+ Log::Comment (NoThrowString ().Format (
4315+ L" First set the viewport somewhere lower in the buffer, as if the text"
4316+ L" was output there. Manually move the cursor there as well, so the"
4317+ L" cursor is within that viewport." ));
4318+ const COORD secondWindowOrigin{0 ,10 };
4319+ VERIFY_SUCCEEDED (si.SetViewportOrigin (true , secondWindowOrigin,true ));
4320+ si.GetTextBuffer ().GetCursor ().SetPosition (secondWindowOrigin);
4321+
4322+ const auto secondView = si._viewport ;
4323+ const auto secondVirtualBottom = si._virtualBottom ;
4324+ Log::Comment (NoThrowString ().Format (
4325+ L" cursor=%s" , VerifyOutputTraits<COORD>::ToString (cursor.GetPosition ()).GetBuffer ()));
4326+ Log::Comment (NoThrowString ().Format (
4327+ L" secondView=%s" , VerifyOutputTraits<SMALL_RECT>::ToString (secondView.ToInclusive ()).GetBuffer ()));
4328+
4329+ VERIFY_ARE_EQUAL (10 , secondView.Top ());
4330+ VERIFY_ARE_EQUAL (originalView.Height () +10 , secondView.BottomExclusive ());
4331+ VERIFY_ARE_EQUAL (originalView.Height () +10 -1 , secondVirtualBottom);
4332+
4333+ Log::Comment (NoThrowString ().Format (
4334+ L" Emulate scrolling upwards with the mouse (not moving the virtual view)" ));
4335+
4336+ const COORD thirdWindowOrigin{0 ,2 };
4337+ VERIFY_SUCCEEDED (si.SetViewportOrigin (true , thirdWindowOrigin,false ));
4338+
4339+ const auto thirdView = si._viewport ;
4340+ const auto thirdVirtualBottom = si._virtualBottom ;
4341+
4342+ Log::Comment (NoThrowString ().Format (
4343+ L" cursor=%s" , VerifyOutputTraits<COORD>::ToString (cursor.GetPosition ()).GetBuffer ()));
4344+ Log::Comment (NoThrowString ().Format (
4345+ L" thirdView=%s" , VerifyOutputTraits<SMALL_RECT>::ToString (thirdView.ToInclusive ()).GetBuffer ()));
4346+
4347+ VERIFY_ARE_EQUAL (2 , thirdView.Top ());
4348+ VERIFY_ARE_EQUAL (originalView.Height () +2 , thirdView.BottomExclusive ());
4349+ VERIFY_ARE_EQUAL (secondVirtualBottom, thirdVirtualBottom);
4350+
4351+ Log::Comment (NoThrowString ().Format (
4352+ L" Call SetConsoleCursorPosition to snap to the cursor" ));
4353+ VERIFY_SUCCEEDED (g.api .SetConsoleCursorPositionImpl (si, secondWindowOrigin));
4354+
4355+ const auto fourthView = si._viewport ;
4356+ const auto fourthVirtualBottom = si._virtualBottom ;
4357+
4358+ Log::Comment (NoThrowString ().Format (
4359+ L" cursor=%s" , VerifyOutputTraits<COORD>::ToString (cursor.GetPosition ()).GetBuffer ()));
4360+ Log::Comment (NoThrowString ().Format (
4361+ L" thirdView=%s" , VerifyOutputTraits<SMALL_RECT>::ToString (fourthView.ToInclusive ()).GetBuffer ()));
4362+
4363+ VERIFY_ARE_EQUAL (10 , fourthView.Top ());
4364+ VERIFY_ARE_EQUAL (originalView.Height () +10 , fourthView.BottomExclusive ());
4365+ VERIFY_ARE_EQUAL (secondVirtualBottom, fourthVirtualBottom);
4366+ }
4367+
42914368void ScreenBufferTests::ClearAlternateBuffer ()
42924369{
42934370// This is a test for microsoft/terminal#1189. Refer to that issue for more