Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SetConsoleScreenBufferInfoEx color palette behavior broken #399

Closed
PhMajerus opened this issue Mar 27, 2019 · 13 comments · Fixed by #12659
Closed

SetConsoleScreenBufferInfoEx color palette behavior broken #399

PhMajerus opened this issue Mar 27, 2019 · 13 comments · Fixed by #12659
Labels
Area-Rendering Text rendering, emoji, complex glyph & font-fallback issues good first issue This is a fix that might be easier for someone to do as a first contribution Help Wanted We encourage anyone to jump in on these. Issue-Bug It either shouldn't be doing this or needs an investigation. Priority-2 A description (P2) Product-Conhost For issues in the Console codebase Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release.

Comments

@PhMajerus
Copy link

PhMajerus commented Mar 27, 2019

19H1 has many improvements concerning console colors, but introduced a new bug. (@zadjii-msft is gonna hate me, sorry)
Testing on 19H1 build 18362.1 and comparing with 1809 build 17763.402.

The console was designed to work like a CGA text screen, with modifiable palette like on VGA.
Whenever the palette is changed, the characters already on screen are displayed using the updated palette on its next refresh cycle,
This was how it used to work until Win10 1809...
The new console code doesn't refresh all displayed cells when SetConsoleScreenBufferInfoEx is called.
This is a breaking compatibility change in 19H1, and an undesirable one as some apps might take advantage of the ability to change the palette without having to redraw the whole text screen to change displayed colors. (like how VGA games used colors cycling).

See the following sample code, it outputs text in color # 7 over a background of color # 0.
Since both lines it outputs are using the same colors indexes, they should be shown in the same color, changing the palette applies to the whole screen, including any existing output.

On 19H1, the console screen isn't updated with the new colors until the user either goes into console settings and clicks OK, or tries to resize the window even just a bit, or even just minimizes and restores the window, forcing a repaint.
This is clearly a bug, as minimizing and restoring the window would not change the colors if it was a new intended behavior.

int main()
{
	HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

	CONSOLE_SCREEN_BUFFER_INFOEX csbiex;
	ZeroMemory(&csbiex, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX));
	csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
	GetConsoleScreenBufferInfoEx(hStdOut, &csbiex);
	// Make sure we're using color#0 as background and #7 as foreground
	csbiex.wAttributes = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;

	// Set blue colors scheme.
	csbiex.ColorTable[0] = RGB(128, 0, 0);
	csbiex.ColorTable[7] = RGB(255, 0, 0);
	SetConsoleScreenBufferInfoEx(hStdOut, &csbiex);
	LPCTSTR pszRedString = TEXT("Bright red on dark red\r\n");
	WriteConsole(hStdOut, pszRedString, _tcslen(pszRedString), NULL, NULL);

	// Set red colors scheme.
	csbiex.ColorTable[0] = RGB(0, 0, 128);
	csbiex.ColorTable[7] = RGB(0, 0, 255);
	SetConsoleScreenBufferInfoEx(hStdOut, &csbiex);
	// At this point, the "Bright red on dark red", as well as all background,
	// for the whole screen should have been turned to blue.
	LPCTSTR pszBlueString = TEXT("Bright blue on dark blue\r\n");
	WriteConsole(hStdOut, pszBlueString, _tcslen(pszBlueString), NULL, NULL);

	getchar();
	return 0;
}

Screen on 1809 and below :
1809 and below

Same on 19H1 (18362.1) :
19H1 bug

@miniksa miniksa added Work-Item It's being tracked by an actual work item internally. (to be removed soon) Product-Conhost For issues in the Console codebase Area-Rendering Text rendering, emoji, complex glyph & font-fallback issues labels Mar 27, 2019
@miniksa
Copy link
Member

miniksa commented Mar 27, 2019

Yeah this looks like it's messed up. I've filed MSFT: 20990369 onto @zadjii-msft internally. He's out this week, so hopefully we can get him to look next week when he gets back.

@zadjii-msft zadjii-msft self-assigned this Apr 1, 2019
@zadjii-msft
Copy link
Member

i cri evrytiem

Eventually, I'm going to stop trying to add color features, and everything will just work as it should, for all scenarios. But 19H1 is not that release.

I'll take a look at this later in <insert next release codename>. Thanks for the detailed writeup, as always!

@PhMajerus
Copy link
Author

"Eventually, I'm going to stop trying to add color features, and everything will just work as it should, for all scenarios."
Don't lose hope, I've been testing the VT colors extensively and the issues really got reduced with the new implementation, you're almost there.
I'm patiently waiting for that time all the colors stuff works as well, so you can start working on sixel graphics and run into all kind of new problems with the characters cells assumptions in the codebase 😄

About this palette issue, since it seems you properly use the new palette when the screen requires a refresh, how about an InvalidateRect (hWnd, NULL, FALSE) at the end of SetConsoleScreenBufferInfoEx if the palette has changed to trigger a WM_PAINT ?

@miniksa
Copy link
Member

miniksa commented Apr 2, 2019

@PhMajerus, there is actually an Invalidate All being triggered when the colors are changing. The fact that it is not working quite right is what's making @zadjii-msft cry. It's a tangled web. 😋

@oising
Copy link
Collaborator

oising commented Apr 2, 2019

I'm patiently waiting for that time all the colors stuff works as well, so you can start working on sixel graphics and run into all kind of new problems with the characters cells assumptions in the codebase 😄

SIXEL YASSSSSS

Seriously though, I think that's not going to land with conhost v2. v3 perhaps? :D

@ghost ghost added the Needs-Tag-Fix Doesn't match tag requirements label May 17, 2019
@miniksa miniksa added Issue-Bug It either shouldn't be doing this or needs an investigation. and removed Mass-Chaos labels May 17, 2019
@ghost ghost removed the Needs-Tag-Fix Doesn't match tag requirements label May 18, 2019
@j4james
Copy link
Collaborator

j4james commented Dec 7, 2019

As far I can see, this is just missing a call to IRenderTarget::TriggerRedrawAll. There is a redraw trigger in the SCREEN_INFORMATION::SetDefaultAttributes method, but that only happens if the default attributes are changed, which isn't the case here.

So to make sure the redraw is always triggered, we'd need another explicit TriggerRedrawAll call in SetConsoleScreenBufferInfoExImpl, some point after the color table is set. That seems to fix the issue for me.

That said, if the redraw is expensive, you may want to be a bit smarter about it, and only refresh if the color table has actually changed.

@PhMajerus
Copy link
Author

@miniksa and @zadjii-msft, do you have any news on this? It's been almost a year and the bug is still present in the latest 20H1 insider build from last week.

Since it seems the conhost side is only updated with feature updates, missing the 20H1 release would make us have to keep this bug for another 6 months.

@zadjii-msft
Copy link
Member

Oh yea we stopped work on 20H1 months ago. Unfortunately this was missed since we didn't have it attached to that milestone 😞. This bug looks like it unfortunately was filed just before the Terminal was announced, so it awkwardly missed the transition to our new bug tracking here in the public.

@PhMajerus
Copy link
Author

@zadjii-msft and @miniksa, did you have a fix for this or is it still on the backlog?
The issue is still present in the current Windows 10 Insider Preview Dev Channel, build 20175.1000

Just bumping this since it's probably something that can only get fixed in an OS release and we'll be moving to a yearly release soon...

@zadjii-msft
Copy link
Member

We don't have any updates on this one. It might have just coincidentally gotten fixed in recent weeks, there was a lot of churn in this area recently. I don't think "September" is necessarily right for the 21H1 milestone, so don't worry about that.

@zadjii-msft zadjii-msft modified the milestones: Windows vNext, 22H1 Jan 4, 2022
@zadjii-msft zadjii-msft modified the milestones: 22H1, Terminal v1.14 Feb 2, 2022
@zadjii-msft zadjii-msft removed the Work-Item It's being tracked by an actual work item internally. (to be removed soon) label Mar 10, 2022
@zadjii-msft zadjii-msft added good first issue This is a fix that might be easier for someone to do as a first contribution Help Wanted We encourage anyone to jump in on these. labels Mar 10, 2022
@zadjii-msft
Copy link
Member

I just went to go and try and fix this, and this looks fine on main, and at least whatever version of conhost is on my 10.0.22563.1001 build. We must have fixed this one along the way! Sorry I don't have a more specific fix to point at 😕

@ghost ghost added the Needs-Tag-Fix Doesn't match tag requirements label Mar 10, 2022
@zadjii-msft zadjii-msft added Resolution-Fix-Available It's available in an Insiders build or a release and removed Needs-Tag-Fix Doesn't match tag requirements labels Mar 10, 2022
@j4james
Copy link
Collaborator

j4james commented Mar 10, 2022

@zadjii-msft I don't think the underlying issue is actually fixed. There is just a bug in the test case which is now hiding the problem.

One of the weird "features" of the Get/SetConsoleScreenBufferInfoEx APIs, is that the one uses exclusive coordinates while the other is inclusive. If you call GetConsoleScreenBufferInfoEx, and then pass the resulting info back to SetConsoleScreenBufferInfoEx, it's actually going to resize the viewport (which in this case is enough to trigger a full screen paint and force the updated palette to render).

Try adding the following lines after the GetConsoleScreenBufferInfoEx call:

csbiex.srWindow.Right += 1;
csbiex.srWindow.Bottom += 1;

That should prevent the resize, and you'll then see that the screen is still not being repainted correctly. It's not the same as it was before, but it's still not correct.

@zadjii-msft
Copy link
Member

WOW okay that is wild. I added some sleeps in there to see what was going on. If you start making a selection after the red color was set, you can see how wild this is.

int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/)
{
    HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

    CONSOLE_SCREEN_BUFFER_INFOEX csbiex;
    ZeroMemory(&csbiex, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX));
    csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
    GetConsoleScreenBufferInfoEx(hStdOut, &csbiex);
    // Make sure we're using color#0 as background and #7 as foreground
    csbiex.wAttributes = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;

    csbiex.srWindow.Right += 1;
    csbiex.srWindow.Bottom += 1;

    // Set blue colors scheme.
    csbiex.ColorTable[0] = RGB(128, 0, 0);
    csbiex.ColorTable[7] = RGB(255, 0, 0);
    SetConsoleScreenBufferInfoEx(hStdOut, &csbiex);

    Sleep(1000);

    LPCWSTR pszRedString = TEXT("Bright red on dark red\r\n");
    WriteConsole(hStdOut, pszRedString, lstrlenW(pszRedString), NULL, NULL);

    Sleep(1000);

    // Set red colors scheme.
    csbiex.ColorTable[0] = RGB(0, 0, 128);
    csbiex.ColorTable[7] = RGB(0, 0, 255);
    SetConsoleScreenBufferInfoEx(hStdOut, &csbiex);

    Sleep(1000);

    // At this point, the "Bright red on dark red", as well as all background,
    // for the whole screen should have been turned to blue.
    LPCWSTR pszBlueString = TEXT("Bright blue on dark blue\r\n");
    WriteConsole(hStdOut, pszBlueString, lstrlenW(pszBlueString), NULL, NULL);

    Sleep(2000);
    return 0;
}

Yea this is still happening. Should be an easy fix. Sorry for being too quick on the trigger 😅

@zadjii-msft zadjii-msft reopened this Mar 10, 2022
@zadjii-msft zadjii-msft removed the Resolution-Fix-Available It's available in an Insiders build or a release label Mar 10, 2022
zadjii-msft added a commit that referenced this issue Mar 10, 2022
Does what it says on the tin. Not super complicated of a fix.

* [x] Fixes #399
* [x] I work here.
* [x] Tested manually (not sure there's a great test for this particular path)
@ghost ghost added the In-PR This issue has a related PR label Mar 10, 2022
@ghost ghost closed this as completed in #12659 May 9, 2022
@ghost ghost added Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release. and removed In-PR This issue has a related PR labels May 9, 2022
ghost pushed a commit that referenced this issue May 9, 2022
Does what it says on the tin. Not super complicated of a fix.

* [x] Fixes #399
* [x] I work here.
* [x] Tested manually (not sure there's a great test for this particular path)
![gh-399-fixed](https://user-images.githubusercontent.com/18356694/157707993-9d59fce6-ae3b-4a6e-8b83-3ec5f3d73c96.gif)
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Rendering Text rendering, emoji, complex glyph & font-fallback issues good first issue This is a fix that might be easier for someone to do as a first contribution Help Wanted We encourage anyone to jump in on these. Issue-Bug It either shouldn't be doing this or needs an investigation. Priority-2 A description (P2) Product-Conhost For issues in the Console codebase Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants