Skip to content

Custom default colors are problematic for legacy apps #5952

Closed

Description

Environment

Windows build number: Version 10.0.18362.719
Windows Terminal version (if applicable): commit b46d393

Steps to reproduce

  1. Build a recent version of the OpenConsole solution.
  2. From the tools directory run opencon, to get a cmd shell.
  3. Open the Properties dialog and set the Screen Background to color index 3 (cyan).
  4. And on the Terminal tab, check Use Separate Background, and set some shade of red, e.g. 100/0/0.
  5. Execute cls.

Expected behavior

I'd expect the screen to be cleared with the same colors used to render the prompt. This is what it looks like in my existing Windows cmd shell.

image

Actual behavior

The screen is cleared with a cyan background, while the prompt is rendered with a red background.

image

The problem here is the active background color has ColorType::IsDefault, but the console APIs only deal in legacy attributes, which can't represent a "default" color. So when cls looks up the active background color, the legacy API returns the Screen Background index, which is cyan. And that's the color that cls then uses to fill the screen. The prompt in the meantime is just using the active background color, which is a genuine default color that maps to red.

The reason why this used to work, is the FillConsoleOutputAttribute API had a hack (since removed in PR #3100) that magically converted a legacy color that matched the legacy version of the active color into that equivalent TextColor value. However, that only applied when VT mode was enabled, so it wouldn't work for most legacy apps, and also relied on the active color just happening to match the color you wanted to fill with, which is by no means guaranteed.

So one option is we could add that hack back (or something similar), but I don't think that's the right solution. Other than the limitations mentioned already, it's only solving part of the problem. I know from working on issue #2661 that this is likely to effect us in other ways once conpty is passing through the full attributes correctly (the fact that conpty maps black to default is actually shielding us from these issues).

I have an idea for how we might address this, but I wanted to think it through some more before writing up the details. In the meantime, though, I thought it best to get this issue filed so you're at least aware of the problem.

Activity

  1. ghost added
    Needs-TriageIt's a new issue that the core contributor team needs to triage at the next triage meeting
    on May 17, 2020
  2. ghost added
    Needs-Tag-FixDoesn't match tag requirements
    on May 17, 2020
  3. DHowett commented on May 18, 2020

    @DHowett
    Member

    Man, I hate this issue. We wrote about it in the blog post that announced the "experimental terminal features" tab (which was intended to let users make conhost more like a terminal emulator), and... actually surprisingly, nobody complained about it. I wonder if that's because nobody used it?

    This is ugly, and we did have those heuristics to determine whether the application was simply setting what it thought were the defaults.

    Incidentally, the treatment of "matches default colors" as "wants default" is the root cause of #293.

  4. added
    Area-ServerDown in the muck of API call servicing, interprocess communication, eventing, etc.
    Area-UserInterfaceIssues pertaining to the user interface of the Console or Terminal
    Issue-BugIt either shouldn't be doing this or needs an investigation.
    Product-ConhostFor issues in the Console codebase
    and removed
    Needs-TriageIt's a new issue that the core contributor team needs to triage at the next triage meeting
    on May 18, 2020
  5. ghost removed
    Needs-Tag-FixDoesn't match tag requirements
    on May 18, 2020
  6. DHowett commented on May 19, 2020

    @DHowett
    Member

    I did, at one point, try to make life horrible for applications.

    d342182

    (hax branch - no warranty - no disclaimers)

    There was one unused legacy attribute flag on the API surface. I got to wondering, "What if?"

  7. zadjii-msft commented on May 19, 2020

    @zadjii-msft
    Member

    On a scale of 1-horrible, how bad was that?

    I was considering something similar where we use that bit as "the fg and/or bg is default colored, not indexed", and then if you queried the current attributes and the FG (or BG) byte matched the FG (or BG) byte of _wFillAttribute, then the app could infer "oh, it's not index 0x7, it's default colored.". Then, at least apps could roundtrip the default attributes. They'd ask "what are the current attrs" and we'd give them (HAX | wFillAttrs) as "use the default attrs", and then setting the attributes to HAX | wFillAtrs _wouldn't change anything.

    Though, if an app just wants to set 0x07 (not HAX | 0x07), then we'd still clear the default-ness of the current attributes. It's impossible to know who's roundtripping attributes vs just blindly setting them like this. So it's not a magic bullet 😕

  8. DHowett commented on May 19, 2020

    @DHowett
    Member

    It was a little horrible. PowerShell doesn't exactly round-trip them, for example: it recomposes them out of what it thinks they meant. :|

  9. 2 remaining items

  10. DHowett commented on Jun 15, 2020

    @DHowett
    Member

    I'm comfortable with us piloting the workaround that 0/7 are "default" when they come through the legacy API, yeah. It seems like we could safely(?) extend that to "active buffer defaults = default", but I'm not sure the risk there.

    Unfortunately, PS6 and PS7 are not significantly better in this regard and we may need to gate #6506 on a fix for this. :/

  11. j4james commented on Jun 15, 2020

    @j4james
    CollaboratorAuthor

    I'm comfortable with us piloting the workaround that 0/7 are "default" when they come through the legacy API, yeah. It seems like we could safely(?) extend that to "active buffer defaults = default", but I'm not sure the risk there.

    I'd love to be able to ignore the active buffer default (assuming we're talking about _wFillAttribute), because that's a pain to access in certain parts of the code. But that will be a breaking change in conhost for anyone that sets the Screen Text and Screen Background properties the way Powershell used to do (I'm not sure if that's still the case).

    Unfortunately, PS6 and PS7 are not significantly better in this regard and we may need to gate #6506 on a fix for this. :/

    I figured that might be necessary.

  12. DHowett commented on Jun 15, 2020

    @DHowett
    Member

    That old powershell shortcut is, unfortunately, checked into the Windows source tree and isn't going anywhere. ☹️

    Now, if people enable the weird woo-woo experimental settings on that LNK file and stuff goes wrong, I legit don't care. Terminal and other PTY hosts are unimpacted.

    I'm more concerned about applications that set the default attributes programmatically and then try to print in those attributes. This could be an as-yet-unexploded minefield

  13. j4james commented on Jun 16, 2020

    @j4james
    CollaboratorAuthor

    I'm more concerned about applications that set the default attributes programmatically and then try to print in those attributes. This could be an as-yet-unexploded minefield

    I don't think that's possible, at least as far I could tell. Those attributes are initialized at startup from the CONSOLE_API_CONNECTINFO, the link settings, and the registry. And at runtime they can be manually changed via the Properties menu. But I couldn't see any console API that would enable an app to set them programatically. I might have missed something though.

  14. DHowett commented on Jun 16, 2020

    @DHowett
    Member

    So, hmm. I was going to remark on the split between SCREEN_INFORMATION::SetAttributes and SCREEN_INFORMATION::SetDefaultAttributes, but it looks like SetDefaultAttributes just calls SetAttributes and then triggers a redraw. It does look like the API SetConsoleScreenBufferInfoEx lets you change the "default attributes", but as far as I can tell those are actually just the active attributes?

    I stand corrected! There's no API that sets the "default" attributes -- we just have really well and truly mixed up what the word "default" means in SCREEN_INFORMATION. 😄

  15. j4james commented on Jun 16, 2020

    @j4james
    CollaboratorAuthor

    It does look like the API SetConsoleScreenBufferInfoEx lets you change the "default attributes", but as far as I can tell those are actually just the active attributes?

    That's correct. The naming is extremely confusing. I've had to make copious notes tracking what these different attributes mean and where they're used. That's the only way I can make sense of the code.

  16. j4james commented on Jun 18, 2020

    @j4james
    CollaboratorAuthor

    I had what I thought was an inspirational idea. What if we allow profiles to override the default legacy attributes, so PowerShell could set its default legacy background index to 1 (i.e. blue). That's essentially what make the original PowerShell work the way it does. That turned out to be more complicated than I thought, but I eventually got it working in my POC, and this was the result:

    image

    On the plus side, Write-Host with a black background actually displays as black now. On the down side, other parts of the command line that used to render with a black background are now a garish blue. The black wasn't correct either, but the blue seems somehow worse.

    However, if you tweak the Campbell PowerShell color scheme so the dark blue color is the same shade as the background color, you get what I think is the perfect rendering:

    image

    But that's a whole lot of special case tweaks that all need to be in alignment for this to look right. Anyone trying to use a different color scheme is going to find things looking a mess again. Only now you're going to get bug reports about DarkBlue being rendered as black (or whatever the default background is).

    In short, I'd say this isn't worth the effort, but I thought I should at least present my results here in case anything thinks this approach is worth pursuing.

  17. j4james commented on Jun 20, 2020

    @j4james
    CollaboratorAuthor

    One other thing I should add regarding the above test. I was a little concerned about the fact that the dir error was displayed with the default background color, since I was actually expecting that to be black. But it turns that is just a difference between powershell.exe and pwsh.exe - the former displays the error with a black background while the latter uses the default background color (technically the "startup" color).

    Not that it makes much of a difference - it's just good to know that PR #6506 is actually doing the right thing here, and it is possible to get it exactly matching the conhost behaviour, assuming you're willing to jump through enough hoops.

  18. ghost added
    In-PRThis issue has a related PR
    on Jun 27, 2020
  19. ghost added
    Needs-Tag-FixDoesn't match tag requirements
    on Jul 1, 2020
  20. ghost removed
    In-PRThis issue has a related PR
    on Jul 1, 2020
  21. ghost added
    Resolution-Fix-CommittedFix is checked in, but it might be 3-4 weeks until a release.
    on Jul 1, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area-ServerDown in the muck of API call servicing, interprocess communication, eventing, etc.Area-UserInterfaceIssues pertaining to the user interface of the Console or TerminalImpact-CorrectnessIt be wrong.Issue-BugIt either shouldn't be doing this or needs an investigation.Needs-Tag-FixDoesn't match tag requirementsPriority-3A description (P3)Product-ConhostFor issues in the Console codebaseResolution-Fix-CommittedFix is checked in, but it might be 3-4 weeks until a release.

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions