Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit6f4b98a

Browse files
authored
Fix snapping to the cursor in "Terminal Scrolling" mode (#2705)
fixes#1222 PSReadline calls SetConsoleCursorPosition on each character they emit (go figure). When that function is called, and we set the cursor position, we'll try and "snap" the viewport to the location of the cursor, so that the cursor remains visible. However, we'd only ever do this with the visible viewport, the viewport defined by `SCREEN_INFORMATION::_viewport`. When there's a virtual viewport in Terminal Scrolling mode, we actually need to snap the virtual viewport, so that this behavior looks more regular.
1 parenteafa884 commit6f4b98a

File tree

2 files changed

+97
-9
lines changed

2 files changed

+97
-9
lines changed

‎src/host/getset.cpp‎

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -649,31 +649,42 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
649649

650650
LOG_IF_FAILED(ConsoleImeResizeCompStrView());
651651

652-
COORD WindowOrigin;
653-
WindowOrigin.X =0;
654-
WindowOrigin.Y =0;
652+
// Attempt to "snap" the viewport to the cursor position. If the cursor
653+
// is not in the current viewport, we'll try and move the viewport so
654+
// that the cursor is visible.
655+
// microsoft/terminal#1222 - Use the "virtual" viewport here, so that
656+
// when the console is in terminal-scrolling mode, the viewport snaps
657+
// back to the virtual viewport's location.
658+
const SMALL_RECT currentViewport = gci.IsTerminalScrolling() ?
659+
buffer.GetVirtualViewport().ToInclusive() :
660+
buffer.GetViewport().ToInclusive();
661+
COORD delta{0 };
655662
{
656-
const SMALL_RECT currentViewport = buffer.GetViewport().ToInclusive();
657663
if (currentViewport.Left > position.X)
658664
{
659-
WindowOrigin.X = position.X - currentViewport.Left;
665+
delta.X = position.X - currentViewport.Left;
660666
}
661667
elseif (currentViewport.Right < position.X)
662668
{
663-
WindowOrigin.X = position.X - currentViewport.Right;
669+
delta.X = position.X - currentViewport.Right;
664670
}
665671

666672
if (currentViewport.Top > position.Y)
667673
{
668-
WindowOrigin.Y = position.Y - currentViewport.Top;
674+
delta.Y = position.Y - currentViewport.Top;
669675
}
670676
elseif (currentViewport.Bottom < position.Y)
671677
{
672-
WindowOrigin.Y = position.Y - currentViewport.Bottom;
678+
delta.Y = position.Y - currentViewport.Bottom;
673679
}
674680
}
675681

676-
RETURN_IF_NTSTATUS_FAILED(buffer.SetViewportOrigin(false, WindowOrigin,true));
682+
COORD newWindowOrigin{0 };
683+
newWindowOrigin.X = currentViewport.Left + delta.X;
684+
newWindowOrigin.Y = currentViewport.Top + delta.Y;
685+
// SetViewportOrigin will worry about clamping these values to the
686+
// buffer for us.
687+
RETURN_IF_NTSTATUS_FAILED(buffer.SetViewportOrigin(true, newWindowOrigin,true));
677688

678689
return S_OK;
679690
}

‎src/host/ut_host/ScreenBufferTests.cpp‎

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ class ScreenBufferTests
179179

180180
TEST_METHOD(RestoreDownAltBufferWithTerminalScrolling);
181181

182+
TEST_METHOD(SnapCursorWithTerminalScrolling);
183+
182184
TEST_METHOD(ClearAlternateBuffer);
183185

184186
TEST_METHOD(InitializeTabStopsInVTMode);
@@ -4288,6 +4290,81 @@ void ScreenBufferTests::RestoreDownAltBufferWithTerminalScrolling()
42884290
}
42894291
}
42904292

4293+
voidScreenBufferTests::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+
constauto 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+
constauto secondView = si._viewport;
4323+
constauto 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+
constauto thirdView = si._viewport;
4340+
constauto 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+
constauto fourthView = si._viewport;
4356+
constauto 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+
42914368
voidScreenBufferTests::ClearAlternateBuffer()
42924369
{
42934370
// This is a test for microsoft/terminal#1189. Refer to that issue for more

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp