-
Notifications
You must be signed in to change notification settings - Fork 8.4k
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
Inverse cursor color logic is (sometimes) broken #3647
Comments
I've experimented a bit and managed to get exactly the same cursor colors as in the Classic Console: GDI: diff --git a/src/renderer/gdi/paint.cpp b/src/renderer/gdi/paint.cpp
index 2f067fc5a..a9f9c77d1 100644
--- a/src/renderer/gdi/paint.cpp
+++ b/src/renderer/gdi/paint.cpp
@@ -733,7 +733,11 @@ bool GdiEngine::FontHasWesternScript(HDC hdc)
for (auto r : cursorInvertRects)
{
- RETURN_HR_IF(E_FAIL, !(InvertRect(_hdcMemoryContext, &r)));
+ // Make the inverted cursor slightly darker to keep it distinct in all cases (see gh-3647).
+ const auto PrevObject = SelectObject(_hdcMemoryContext, GetStockObject(LTGRAY_BRUSH));
+ const auto Result = PatBlt(_hdcMemoryContext, r.left, r.top, r.right - r.left, r.bottom - r.top, PATINVERT);
+ SelectObject(_hdcMemoryContext, PrevObject);
+ RETURN_HR_IF(E_FAIL, !Result);
}
}
DX: diff --git a/src/renderer/dx/CustomTextRenderer.cpp b/src/renderer/dx/CustomTextRenderer.cpp
index f3a894a43..7ad00c923 100644
--- a/src/renderer/dx/CustomTextRenderer.cpp
+++ b/src/renderer/dx/CustomTextRenderer.cpp
@@ -395,8 +395,9 @@ try
if (firstPass)
{
// Draw a backplate behind the cursor in the *background* color so that we can invert it later.
- // We're going to draw the exact same color as the background behind the cursor
- const til::color color{ drawingContext.backgroundBrush->GetColor() };
+ // We're going to draw a slightly lighter color than the background behind the cursor,
+ // so that after the inversion it will be slightly darker and distinct in all cases (see gh-3647).
+ const til::color color{ til::color{ drawingContext.backgroundBrush->GetColor() } ^ RGB(63, 63, 63) };
RETURN_IF_FAILED(d2dContext->CreateSolidColorBrush(color.with_alpha(255),
&brush));
}
Atlas: diff --git a/src/renderer/atlas/shader_ps.hlsl b/src/renderer/atlas/shader_ps.hlsl
index 789cd98b0..fce0b9517 100644
--- a/src/renderer/atlas/shader_ps.hlsl
+++ b/src/renderer/atlas/shader_ps.hlsl
@@ -168,6 +168,8 @@ float4 main(float4 pos: SV_Position): SV_Target
[flatten] if (cursorColor == INVALID_COLOR && glyphs[cellPos].a != 0)
{
color = float4(1 - color.rgb, 1);
+ // Make the inverted cursor slightly darker to keep it distinct in all cases (see gh-3647).
+ color = abs(color - 0.25);
}
} Before:After:The logic is pretty simple and equivalent to making the inverted color 25% darker: uint32_t Color = current_cell_color();
uint32_t InvertedColor = ~Color & 0x00FFFFFF;
uint32_t CursorColor = InvertedColor ^ 0x003F3F3F; |
I've added DX and Atlas renderer changes to the previous comment. |
Lemme /cc @lhecker cause I think he's got some thoughts on the matter. |
@lhecker thanks, the XOR plot is correct, or, alternatively:
Mea culpa 🤦 diff --git a/src/renderer/atlas/shader_ps.hlsl b/src/renderer/atlas/shader_ps.hlsl
index 789cd98b0..320f2895e 100644
--- a/src/renderer/atlas/shader_ps.hlsl
+++ b/src/renderer/atlas/shader_ps.hlsl
@@ -168,6 +168,8 @@ float4 main(float4 pos: SV_Position): SV_Target
[flatten] if (cursorColor == INVALID_COLOR && glyphs[cellPos].a != 0)
{
color = float4(1 - color.rgb, 1);
+ float3 shifted = ((uint3(color.rgb * 255) ^ 0x3f) & 0xff) / 255.0;
+ color = float4(shifted.rgb, 1);
}
}
I'm all for creativity and fancy visuals, but it would be nice to at least have a uniform, always readable and already tested solution everywhere first, even if not the most creative one. |
If you'd like to submit a PR for this - go for it! |
Currently "Inverse Cursor" is actually simply bitwise inversed. It works fine, except when it does not, namely in the middle of the spectrum: Anything close enough to dark grey (index 8, RGB(128, 128, 128) in the classic palette) will for obvious reasons become almost the same dark grey again after the inversion. The issue is addressed by additionally `XOR`ing the inverted color with RGB(63, 63, 63). This distorts the result enough to avoid collisions in the middle. Ultimately this restores the behavior that was in Windows Console since the Middle Ages (and still exists in ConhostV1.dll). ## PR Checklist * [x] Closes #3647 * [x] CLA signed * [x] Tests added/passed * [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #3647 ## Validation Steps Performed 1. Open OpenConsole. 2. Properties, Terminal, Cursor Colors, choose Inverse Color. 3. Optionally set the RGB value of the 8th color in the standard palette to RGB(128, 128, 128) on the Colors tab, but the default one will do too. 4. Type `color 80` to see black text on dark grey background. 5. Make sure the inverted cursor is visible. 6. Repeat in WT with both default and experimental renderers.
🎉This issue was addressed in #13748, which has now been successfully released as Handy links: |
Isn't it ±16 in the picture? |
Ah woops. Yes it's ±16. It results in a -32 darkening, because when you invert a +16 color you get a -16 and so the delta is 32. I've considered using ±32 with a -64 darkening as well, but wasn't sure what to best pick. I was thinking that a smaller ±N could potentially result in a better visual "consistency". Edit: I found that |
Isn't that just a plain inversion on your screenshot? ~(127, 127, 111) = (128, 128, 144) |
Ah, "If all components of the background color are within...", and this one doesn't match. |
Yeah it's a plain inversion, because one of the components isn’t within the "±16" range anymore - at least according to the way I built it (which uses 0x80/128 as the gray value to make some bit twiddling simpler). If it was 112 instead of 111 the darkening effect would apply and the cursor would be visible. Sorry, I should’ve been more specific in my edit. |
I just realized that I can also just draw the background XOR'd with 63 ( Here's the current AtlasEngine for reference: The benefit of the current approach is that colors that are close together, stay close together. However I'm not 100% certain whether that's a good thing or not... |
Environment
Steps to reproduce
128 128 128
.Expected behavior
Cursor is visible no matter what background color is.
Actual behavior
Now you see it, now you don't.
Current "inverse" logic is too straightforward - it literally takes the inverse of the background, and for
128 128 128
the inverse is...127 127 127
, which is basically the same thing. Oops.Note: Legacy console handles this corner case properly, as well as all Windows versions prior to 10.
Also, legacy console inversion algorithm is not exactly "inverse" - the colors are slightly different (and subjectively more pleasant). Is it possible to get this classic inversion in the modern console please?
This issue affects a text editor app that uses console color
8
(128 128 128
in classic color scheme) to highlight various parts of text (e.g. current line). Sudden cursor disappearing is confusing and annoying.Example:
The text was updated successfully, but these errors were encountered: