Conhost window is not refreshed after software scroll #20447

Closed
opened 2026-01-31 07:14:05 +00:00 by claunia · 3 comments
Owner

Originally created by @alabuzhev on GitHub (Sep 5, 2023).

Originally assigned to: @lhecker on GitHub.

Windows Terminal version

1.18.1462.0

Windows build number

10.0.19045.3324

Other Software

No response

Steps to reproduce

  1. Compile the code:
#include <iostream>
#include <stdexcept>
#include <string>

#include <windows.h>

void scroll(bool page, bool up)
{
	const auto out = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_SCREEN_BUFFER_INFO csbi;
	if (!GetConsoleScreenBufferInfo(out, &csbi))
		throw std::runtime_error("GetConsoleScreenBufferInfo");

	if (up && !csbi.srWindow.Top)
		return;

	if (!up && csbi.srWindow.Bottom == csbi.dwSize.Y - 1)
		return;

	auto lines = page?
		csbi.srWindow.Bottom - csbi.srWindow.Top + 1:
		1;

	if (up)
		lines = -lines;

	csbi.srWindow.Top += lines;
	csbi.srWindow.Bottom += lines;

	if (csbi.srWindow.Top < 0)
	{
		csbi.srWindow.Bottom -= csbi.srWindow.Top;
		csbi.srWindow.Top = 0;
	}

	if (csbi.srWindow.Bottom >= csbi.dwSize.Y)
	{
		csbi.srWindow.Top -= (csbi.srWindow.Bottom - (csbi.dwSize.Y - 1));
		csbi.srWindow.Bottom = csbi.dwSize.Y - 1;
	}

	if (!SetConsoleWindowInfo(out, true, &csbi.srWindow))
		throw std::runtime_error("SetConsoleWindowInfo");
}

void run()
{
	const auto width = 80, height = 25;
	const auto screens = 5;
	const auto out = GetStdHandle(STD_OUTPUT_HANDLE);
	const SMALL_RECT Window{ 0, 0, width - 1, height - 1 };
	SetConsoleWindowInfo(out, true, &Window);
	SetConsoleScreenBufferSize(out, { width, height * screens });

	for (size_t i = 0; i != height * screens - 1; ++i)
	{
		const auto data = L"Line " + std::to_wstring(i) + L"\n";
		DWORD n;
		WriteConsole(out, data.data(), static_cast<DWORD>(data.size()), &n, {});
	}

	const auto in = GetStdHandle(STD_INPUT_HANDLE);
	for (;;)
	{
		INPUT_RECORD r;
		DWORD n;
		if (!ReadConsoleInput(in, &r, 1, &n))
			break;

		if (r.EventType != KEY_EVENT || !r.Event.KeyEvent.bKeyDown)
			continue;

		switch (const auto key = r.Event.KeyEvent.wVirtualKeyCode)
		{
		case VK_UP:
		case VK_DOWN:
		case VK_NEXT:
		case VK_PRIOR:
			scroll(key == VK_NEXT || key == VK_PRIOR, key == VK_UP || key == VK_PRIOR);
		}
	}
}

int main()
{
	try
	{
		run();
	}
	catch(const std::exception& e)
	{
		std::cerr << e.what();
	}
}

  1. Run it with the latest published OpenConsole, e.g. from WT 1.18.1462.
  2. Press Up and Down a few times.
  3. Press PgUp and PgDn a few times.

Expected Behavior

The viewport moves up or down, line by line or page by page.

Actual Behavior

Pressing Up or Down works as expected.
Pressing PgUp or PgDown doesn't.

When PgUp/PgDown are pressed, the scrollbar on the right moves appropriately, indicating that the viewport has moved, but the window is not refreshed and shows the very same content.

The issue occurs only if the number of lines to scroll is >= window height.

The original issue is described here:
https://github.com/FarGroup/FarManager/issues/727
According to the comments, the default conhost in Windows 11 is also affected to some extent.

Originally created by @alabuzhev on GitHub (Sep 5, 2023). Originally assigned to: @lhecker on GitHub. ### Windows Terminal version 1.18.1462.0 ### Windows build number 10.0.19045.3324 ### Other Software _No response_ ### Steps to reproduce 1. Compile the code: <details> ```C++ #include <iostream> #include <stdexcept> #include <string> #include <windows.h> void scroll(bool page, bool up) { const auto out = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO csbi; if (!GetConsoleScreenBufferInfo(out, &csbi)) throw std::runtime_error("GetConsoleScreenBufferInfo"); if (up && !csbi.srWindow.Top) return; if (!up && csbi.srWindow.Bottom == csbi.dwSize.Y - 1) return; auto lines = page? csbi.srWindow.Bottom - csbi.srWindow.Top + 1: 1; if (up) lines = -lines; csbi.srWindow.Top += lines; csbi.srWindow.Bottom += lines; if (csbi.srWindow.Top < 0) { csbi.srWindow.Bottom -= csbi.srWindow.Top; csbi.srWindow.Top = 0; } if (csbi.srWindow.Bottom >= csbi.dwSize.Y) { csbi.srWindow.Top -= (csbi.srWindow.Bottom - (csbi.dwSize.Y - 1)); csbi.srWindow.Bottom = csbi.dwSize.Y - 1; } if (!SetConsoleWindowInfo(out, true, &csbi.srWindow)) throw std::runtime_error("SetConsoleWindowInfo"); } void run() { const auto width = 80, height = 25; const auto screens = 5; const auto out = GetStdHandle(STD_OUTPUT_HANDLE); const SMALL_RECT Window{ 0, 0, width - 1, height - 1 }; SetConsoleWindowInfo(out, true, &Window); SetConsoleScreenBufferSize(out, { width, height * screens }); for (size_t i = 0; i != height * screens - 1; ++i) { const auto data = L"Line " + std::to_wstring(i) + L"\n"; DWORD n; WriteConsole(out, data.data(), static_cast<DWORD>(data.size()), &n, {}); } const auto in = GetStdHandle(STD_INPUT_HANDLE); for (;;) { INPUT_RECORD r; DWORD n; if (!ReadConsoleInput(in, &r, 1, &n)) break; if (r.EventType != KEY_EVENT || !r.Event.KeyEvent.bKeyDown) continue; switch (const auto key = r.Event.KeyEvent.wVirtualKeyCode) { case VK_UP: case VK_DOWN: case VK_NEXT: case VK_PRIOR: scroll(key == VK_NEXT || key == VK_PRIOR, key == VK_UP || key == VK_PRIOR); } } } int main() { try { run(); } catch(const std::exception& e) { std::cerr << e.what(); } } ``` </details> 2. Run it with the latest published OpenConsole, e.g. from WT 1.18.1462. 3. Press Up and Down a few times. 4. Press PgUp and PgDn a few times. ### Expected Behavior The viewport moves up or down, line by line or page by page. ### Actual Behavior Pressing Up or Down works as expected. Pressing PgUp or PgDown doesn't. When PgUp/PgDown are pressed, the scrollbar on the right moves appropriately, indicating that the viewport has moved, but the window is not refreshed and shows the very same content. The issue occurs only if the number of lines to scroll is >= window height. The original issue is described here: https://github.com/FarGroup/FarManager/issues/727 According to the comments, the default conhost in Windows 11 is also affected to some extent.
claunia added the Product-ConhostArea-OutputIssue-BugIn-PRNeeds-Tag-Fix labels 2026-01-31 07:14:06 +00:00
Author
Owner

@zadjii-msft commented on GitHub (Sep 6, 2023):

  • This isn't #10191, because that's conpty specific.
  • Kinda the inverse of #6659. In that one the contents update but the scrollbar doesn't. This is the opposite
  • It's not #13741 - that's alt-buffer specific
  • @lhecker believes this is probably the same root cause as #15769 - he'll bisect it
@zadjii-msft commented on GitHub (Sep 6, 2023): * This isn't #10191, because that's conpty specific. * Kinda the inverse of #6659. In that one the contents update but the scrollbar doesn't. This is the opposite * It's not #13741 - that's alt-buffer specific * @lhecker believes this is probably the same root cause as #15769 - he'll bisect it
Author
Owner

@lhecker commented on GitHub (Sep 6, 2023):

FYI #15769 will be closed by #15935, but that's just because I'm effectively working around this bug. The timing of you filing this issue is great, because it just made me realize that the cause for #15769 is not SSH's handling of SIGWINCH directly, but rather SetConsoleWindowInfo itself.

@lhecker commented on GitHub (Sep 6, 2023): FYI #15769 will be closed by #15935, but that's just because I'm effectively working around this bug. The timing of you filing this issue is great, because it just made me realize that the cause for #15769 is not SSH's handling of SIGWINCH directly, but rather `SetConsoleWindowInfo` itself.
Author
Owner

@lhecker commented on GitHub (Nov 17, 2023):

This regression was caused by 81b7e54659. Reverting it has no or negligible impact on performance at this point, likely due to the overall vastly better performance of conhost nowadays.

@lhecker commented on GitHub (Nov 17, 2023): This regression was caused by 81b7e546592a5743dac65b01c0cb280a75751624. Reverting it has no or negligible impact on performance at this point, likely due to the overall vastly better performance of conhost nowadays.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#20447