terminal/src/host/settings.cpp

834 lines
24 KiB
C++
Raw Normal View History

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "settings.hpp"
#include "../interactivity/inc/ServiceLocator.hpp"
#include "../types/inc/colorTable.hpp"
#pragma hdrstop
constexpr unsigned int DEFAULT_NUMBER_OF_COMMANDS = 25;
constexpr unsigned int DEFAULT_NUMBER_OF_BUFFERS = 4;
using Microsoft::Console::Interactivity::ServiceLocator;
Settings::Settings() :
_dwHotKey(0),
_dwStartupFlags(0),
_wFillAttribute(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE), // White (not bright) on black by default
_wPopupFillAttribute(FOREGROUND_RED | FOREGROUND_BLUE | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY), // Purple on white (bright) by default
_wShowWindow(SW_SHOWNORMAL),
_wReserved(0),
// dwScreenBufferSize initialized below
// dwWindowSize initialized below
// dwWindowOrigin initialized below
_nFont(0),
// dwFontSize initialized below
_uFontFamily(0),
_uFontWeight(0),
// FaceName initialized below
_uCursorSize(Cursor::CURSOR_SMALL_SIZE),
_bFullScreen(false),
_bQuickEdit(true),
_bInsertMode(true),
_bAutoPosition(true),
_uHistoryBufferSize(DEFAULT_NUMBER_OF_COMMANDS),
_uNumberOfHistoryBuffers(DEFAULT_NUMBER_OF_BUFFERS),
_bHistoryNoDup(false),
// ColorTable initialized below
_uCodePage(ServiceLocator::LocateGlobals().uiOEMCP),
_uScrollScale(1),
_bLineSelection(true),
_bWrapText(true),
_fCtrlKeyShortcutsDisabled(false),
_bWindowAlpha(BYTE_MAX), // 255 alpha = opaque. 0 = transparent.
_fFilterOnPaste(false),
_LaunchFaceName{},
_fTrimLeadingZeros(FALSE),
_fEnableColorSelection(FALSE),
_fAllowAltF4Close(true),
_dwVirtTermLevel(0),
_fUseWindowSizePixels(false),
_fAutoReturnOnNewline(true), // the historic Windows behavior defaults this to on.
_fRenderGridWorldwide(false), // historically grid lines were only rendered in DBCS codepages, so this is false by default unless otherwise specified.
Add support for the DECSCNM screen mode (#3817) ## Summary of the Pull Request This adds support for the [`DECSCNM`](https://vt100.net/docs/vt510-rm/DECSCNM.html) private mode escape sequence, which toggles the display between normal and reverse screen modes. When reversed, the background and foreground colors are switched. Tested manually, with [Vttest](https://invisible-island.net/vttest/), and with some new unit tests. ## References This also fixes issue #72 for the most part, although if you toggle the mode too fast, there is no discernible flash. ## PR Checklist * [x] Closes #3773 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed * [ ] Requires documentation to be updated * [ ] 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: #xxx ## Detailed Description of the Pull Request / Additional comments I've implemented this as a new flag in the `Settings` class, along with updates to the `LookupForegroundColor` and `LookupBackgroundColor` methods, to switch the returned foreground and background colors when that flag is set. It also required a new private API in the `ConGetSet` interface to toggle the setting. And that API is then called from the `AdaptDispatch` class when the screen mode escape sequence is received. The last thing needed was to add a step to the `HardReset` method, to reset the mode back to normal, which is one of the `RIS` requirements. Note that this does currently work in the Windows Terminal, but once #2661 is implemented that may no longer be the case. It might become necessary to let the mode change sequences pass through conpty, and handle the color reversing on the client side. ## Validation Steps Performed I've added a state machine test to make sure the escape sequence is dispatched correctly, and a screen buffer test to confirm that the mode change does alter the interpretation of colors as expected. I've also confirmed that the various "light background" tests in Vttest now display correctly, and that the `tput flash` command (in a bash shell) does actually cause the screen to flash.
2020-01-22 23:29:50 +01:00
_fScreenReversed(false),
// window size pixels initialized below
_fInterceptCopyPaste(0),
_DefaultForeground(INVALID_COLOR),
_DefaultBackground(INVALID_COLOR),
Introduce AtlasEngine - A new text rendering prototype (#11623) This commit introduces "AtlasEngine", a new text renderer based on DxEngine. But unlike it, DirectWrite and Direct2D are only used to rasterize glyphs. Blending and placing these glyphs into the target view is being done using Direct3D and a simple HLSL shader. Since this new renderer more aggressively assumes that the text is monospace, it simplifies the implementation: The viewport is divided into cells, and its data is stored as a simple matrix. Modifications to this matrix involve only simple pointer arithmetic and is easy to understand. But just like with DxEngine however, DirectWrite related code remains extremely complex and hard to understand. Supported features: * Basic text rendering with grayscale AA * Foreground and background colors * Emojis, including zero width joiners * Underline, dotted underline, strikethrough * Custom font axes and features * Selections * All cursor styles * Full alpha support for all colors * _Should_ work with Windows 7 Unsupported features: * A more conservative GPU memory usage The backing texture atlas for glyphs is grow-only and will not shrink. After 256MB of memory is used up (~20k glyphs) text output will be broken until the renderer is restarted. * ClearType * Remaining gridlines (left, right, top, bottom, double underline) * Hyperlinks don't get full underlines if hovered in WT * Softfonts * Non-default line renditions Performance: * Runs at up to native display refresh rate Unfortunately the frame rate often drops below refresh rate, due us fighting over the buffer lock with other parts of the application. * CPU consumption is up to halved compared to DxEngine AtlasEngine is still highly unoptimized. Glyph hashing consumes up to a third of the current CPU time. * No regressions in WT performance VT parsing and related buffer management takes up most of the CPU time (~85%), due to which the AtlasEngine can't show any further improvements. * ~2x improvement in raw text throughput in OpenConsole compared to DxEngine running at 144 FPS * ≥10x improvement in colored VT output in WT/OpenConsole compared to DxEngine running at 144 FPS
2021-11-13 01:10:06 +01:00
_fUseDx(UseDx::Disabled),
_fCopyColor(false)
{
_dwScreenBufferSize.X = 80;
_dwScreenBufferSize.Y = 25;
_dwWindowSize.X = _dwScreenBufferSize.X;
_dwWindowSize.Y = _dwScreenBufferSize.Y;
_dwWindowSizePixels = { 0 };
_dwWindowOrigin.X = 0;
_dwWindowOrigin.Y = 0;
_dwFontSize.X = 0;
_dwFontSize.Y = 16;
ZeroMemory((void*)&_FaceName, sizeof(_FaceName));
wcscpy_s(_FaceName, DEFAULT_TT_FONT_FACENAME);
_CursorColor = Cursor::s_InvertCursorColor;
_CursorType = CursorType::Legacy;
gsl::span<COLORREF> tableView = { _colorTable.data(), _colorTable.size() };
Standardize the color table order (#11602) ## Summary of the Pull Request In the original implementation, we used two different orderings for the color tables. The WT color table used ANSI order, while the conhost color table used a Windows-specific order. This PR standardizes on the ANSI color order everywhere, so the usage of indexed colors is consistent across both parts of the code base, which will hopefully allow more of the code to be shared one day. ## References This is another small step towards de-duplicating `AdaptDispatch` and `TerminalDispatch` for issue #3849, and is essentially a followup to the SGR dispatch refactoring in PR #6728. ## PR Checklist * [x] Closes #11461 * [x] CLA signed. * [x] Tests added/passed * [ ] Documentation updated. * [ ] Schema updated. * [x] I've discussed this with core contributors already. Issue number where discussion took place: #11461 ## Detailed Description of the Pull Request / Additional comments Conhost still needs to deal with legacy attributes using Windows color order, so those values now need to be transposed to ANSI colors order when creating a `TextAttribute` object. This is done with a simple mapping table, which also handles the translation of the default color entries, so it's actually slightly faster than the original code. And when converting `TextAttribute` values back to legacy console attributes, we were already using a mapping table to handle the narrowing of 256-color values down to 16 colors, so we just needed to adjust that table to account for the translation from ANSI to Windows, and then could make use of the same table for both 256-color and 16-color values. There are also a few places in conhost that read from or write to the color tables, and those now need to transpose the index values. I've addressed this by creating separate `SetLegacyColorTableEntry` and `GetLegacyColorTableEntry` methods in the `Settings` class which take care of the mapping, so it's now clearer in which cases the code is dealing with legacy values, and which are ANSI values. These methods are used in the `SetConsoleScreenBufferInfoEx` and `GetConsoleScreenBufferInfoEx` APIs, as well as a few place where color preferences are handled (the registry, shortcut links, and the properties dialog), none of which are particularly sensitive to performance. However, we also use the legacy table when looking up the default colors for rendering (which happens a lot), so I've refactored that code so the default color calculations now only occur once per frame. The plus side of all of this is that the VT code doesn't need to do the index translation anymore, so we can finally get rid of all the calls to `XTermToWindowsIndex`, and we no longer need a separate color table initialization method for conhost, so I was able to merge a number of color initialization methods into one. We also no longer need to translate from legacy values to ANSI when generating VT sequences for conpty. The one exception to that is the 16-color VT renderer, which uses the `TextColor::GetLegacyIndex` method to approximate 16-color equivalents for RGB and 256-color values. Since that method returns a legacy index, it still needs to be translated to ANSI before it can be used in a VT sequence. But this should be no worse than it was before. One more special case is conhost's secret _Color Selection_ feature. That uses `Ctrl`+Number and `Alt`+Number key sequences to highlight parts of the buffer, and the mapping from number to color is based on the Windows color order. So that mapping now needs to be transposed, but that's also not performance sensitive. The only thing that I haven't bothered to update is the trace logging code in the `Telemetry` class, which logs the first 16 entries in the color table. Those entries are now going to be in a different order, but I didn't think that would be of great concern to anyone. ## Validation Steps Performed A lot of unit tests needed to be updated to use ANSI color constants when setting indexed colors, where before they might have been expecting values in Windows order. But this replaced a wild mix of different constants, sometimes having to use bit shifting, as well as values mapped with `XTermToWindowsIndex`, so I think the tests are a whole lot clearer now. Only a few cases have been left with literal numbers where that seemed more appropriate. In addition to getting the unit tests working, I've also manually tested the behaviour of all the console APIs which I thought could be affected by these changes, and confirmed that they produced the same results in the new code as they did in the original implementation. This includes: - `WriteConsoleOutput` - `ReadConsoleOutput` - `SetConsoleTextAttribute` with `WriteConsoleOutputCharacter` - `FillConsoleOutputAttribute` and `FillConsoleOutputCharacter` - `ScrollConsoleScreenBuffer` - `GetConsoleScreenBufferInfo` - `GetConsoleScreenBufferInfoEx` - `SetConsoleScreenBufferInfoEx` I've also manually tested changing colors via the console properties menu, the registry, and shortcut links, including setting default colors and popup colors. And I've tested that the "Quirks Mode" is still working as expected in PowerShell. In terms of performance, I wrote a little test app that filled a 80x9999 buffer with random color combinations using `WriteConsoleOutput`, which I figured was likely to be the most performance sensitive call, and I think it now actually performs slightly better than the original implementation. I've also tested similar code - just filling the visible window - with SGR VT sequences of various types, and the performance seems about the same as it was before.
2021-11-04 23:13:22 +01:00
::Microsoft::Console::Utils::InitializeColorTable(tableView);
}
// Routine Description:
// - Applies hardcoded default settings that are in line with what is defined
// in our Windows edition manifest (living in win32k-settings.man).
// - NOTE: This exists in case we cannot access the registry on desktop platforms.
// We will use this to provide better defaults than the constructor values which
// are optimized for OneCore.
// Arguments:
// - <none>
// Return Value:
// - <none> - Adjusts internal state only.
void Settings::ApplyDesktopSpecificDefaults()
{
_dwFontSize.X = 0;
_dwFontSize.Y = 16;
_uFontFamily = 0;
_dwScreenBufferSize.X = 120;
_dwScreenBufferSize.Y = 9001;
_uCursorSize = 25;
_dwWindowSize.X = 120;
_dwWindowSize.Y = 30;
_wFillAttribute = 0x7;
_wPopupFillAttribute = 0xf5;
wcscpy_s(_FaceName, L"__DefaultTTFont__");
_uFontWeight = 0;
_bInsertMode = TRUE;
_bFullScreen = FALSE;
_fCtrlKeyShortcutsDisabled = false;
_bWrapText = true;
_bLineSelection = TRUE;
_bWindowAlpha = 255;
_fFilterOnPaste = TRUE;
_bQuickEdit = TRUE;
_uHistoryBufferSize = 50;
_uNumberOfHistoryBuffers = 4;
_bHistoryNoDup = FALSE;
Standardize the color table order (#11602) ## Summary of the Pull Request In the original implementation, we used two different orderings for the color tables. The WT color table used ANSI order, while the conhost color table used a Windows-specific order. This PR standardizes on the ANSI color order everywhere, so the usage of indexed colors is consistent across both parts of the code base, which will hopefully allow more of the code to be shared one day. ## References This is another small step towards de-duplicating `AdaptDispatch` and `TerminalDispatch` for issue #3849, and is essentially a followup to the SGR dispatch refactoring in PR #6728. ## PR Checklist * [x] Closes #11461 * [x] CLA signed. * [x] Tests added/passed * [ ] Documentation updated. * [ ] Schema updated. * [x] I've discussed this with core contributors already. Issue number where discussion took place: #11461 ## Detailed Description of the Pull Request / Additional comments Conhost still needs to deal with legacy attributes using Windows color order, so those values now need to be transposed to ANSI colors order when creating a `TextAttribute` object. This is done with a simple mapping table, which also handles the translation of the default color entries, so it's actually slightly faster than the original code. And when converting `TextAttribute` values back to legacy console attributes, we were already using a mapping table to handle the narrowing of 256-color values down to 16 colors, so we just needed to adjust that table to account for the translation from ANSI to Windows, and then could make use of the same table for both 256-color and 16-color values. There are also a few places in conhost that read from or write to the color tables, and those now need to transpose the index values. I've addressed this by creating separate `SetLegacyColorTableEntry` and `GetLegacyColorTableEntry` methods in the `Settings` class which take care of the mapping, so it's now clearer in which cases the code is dealing with legacy values, and which are ANSI values. These methods are used in the `SetConsoleScreenBufferInfoEx` and `GetConsoleScreenBufferInfoEx` APIs, as well as a few place where color preferences are handled (the registry, shortcut links, and the properties dialog), none of which are particularly sensitive to performance. However, we also use the legacy table when looking up the default colors for rendering (which happens a lot), so I've refactored that code so the default color calculations now only occur once per frame. The plus side of all of this is that the VT code doesn't need to do the index translation anymore, so we can finally get rid of all the calls to `XTermToWindowsIndex`, and we no longer need a separate color table initialization method for conhost, so I was able to merge a number of color initialization methods into one. We also no longer need to translate from legacy values to ANSI when generating VT sequences for conpty. The one exception to that is the 16-color VT renderer, which uses the `TextColor::GetLegacyIndex` method to approximate 16-color equivalents for RGB and 256-color values. Since that method returns a legacy index, it still needs to be translated to ANSI before it can be used in a VT sequence. But this should be no worse than it was before. One more special case is conhost's secret _Color Selection_ feature. That uses `Ctrl`+Number and `Alt`+Number key sequences to highlight parts of the buffer, and the mapping from number to color is based on the Windows color order. So that mapping now needs to be transposed, but that's also not performance sensitive. The only thing that I haven't bothered to update is the trace logging code in the `Telemetry` class, which logs the first 16 entries in the color table. Those entries are now going to be in a different order, but I didn't think that would be of great concern to anyone. ## Validation Steps Performed A lot of unit tests needed to be updated to use ANSI color constants when setting indexed colors, where before they might have been expecting values in Windows order. But this replaced a wild mix of different constants, sometimes having to use bit shifting, as well as values mapped with `XTermToWindowsIndex`, so I think the tests are a whole lot clearer now. Only a few cases have been left with literal numbers where that seemed more appropriate. In addition to getting the unit tests working, I've also manually tested the behaviour of all the console APIs which I thought could be affected by these changes, and confirmed that they produced the same results in the new code as they did in the original implementation. This includes: - `WriteConsoleOutput` - `ReadConsoleOutput` - `SetConsoleTextAttribute` with `WriteConsoleOutputCharacter` - `FillConsoleOutputAttribute` and `FillConsoleOutputCharacter` - `ScrollConsoleScreenBuffer` - `GetConsoleScreenBufferInfo` - `GetConsoleScreenBufferInfoEx` - `SetConsoleScreenBufferInfoEx` I've also manually tested changing colors via the console properties menu, the registry, and shortcut links, including setting default colors and popup colors. And I've tested that the "Quirks Mode" is still working as expected in PowerShell. In terms of performance, I wrote a little test app that filled a 80x9999 buffer with random color combinations using `WriteConsoleOutput`, which I figured was likely to be the most performance sensitive call, and I think it now actually performs slightly better than the original implementation. I've also tested similar code - just filling the visible window - with SGR VT sequences of various types, and the performance seems about the same as it was before.
2021-11-04 23:13:22 +01:00
gsl::span<COLORREF> tableView = { _colorTable.data(), 16 };
::Microsoft::Console::Utils::InitializeColorTable(tableView);
_fTrimLeadingZeros = false;
_fEnableColorSelection = false;
_uScrollScale = 1;
}
void Settings::ApplyStartupInfo(const Settings* const pStartupSettings)
{
const DWORD dwFlags = pStartupSettings->_dwStartupFlags;
// See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686331(v=vs.85).aspx
// Note: These attributes do not get sent to us if we started conhost
// directly. See minkernel/console/client/dllinit for the
// initialization of these values for cmdline applications.
if (WI_IsFlagSet(dwFlags, STARTF_USECOUNTCHARS))
{
_dwScreenBufferSize = pStartupSettings->_dwScreenBufferSize;
}
if (WI_IsFlagSet(dwFlags, STARTF_USESIZE))
{
// WARNING: This size is in pixels when passed in the create process call.
// It will need to be divided by the font size before use.
// All other Window Size values (from registry/shortcuts) are stored in characters.
_dwWindowSizePixels = pStartupSettings->_dwWindowSize;
_fUseWindowSizePixels = true;
}
if (WI_IsFlagSet(dwFlags, STARTF_USEPOSITION))
{
_dwWindowOrigin = pStartupSettings->_dwWindowOrigin;
_bAutoPosition = FALSE;
}
if (WI_IsFlagSet(dwFlags, STARTF_USEFILLATTRIBUTE))
{
_wFillAttribute = pStartupSettings->_wFillAttribute;
}
if (WI_IsFlagSet(dwFlags, STARTF_USESHOWWINDOW))
{
_wShowWindow = pStartupSettings->_wShowWindow;
}
}
// Method Description:
// - Applies settings passed on the commandline to this settings structure.
// Currently, the only settings that can be passed on the commandline are
// the initial width and height of the screenbuffer/viewport.
// Arguments:
// - consoleArgs: A reference to a parsed command-line args object.
// Return Value:
// - <none>
void Settings::ApplyCommandlineArguments(const ConsoleArguments& consoleArgs)
{
const short width = consoleArgs.GetWidth();
const short height = consoleArgs.GetHeight();
if (width > 0 && height > 0)
{
_dwScreenBufferSize.X = width;
_dwWindowSize.X = width;
_dwScreenBufferSize.Y = height;
_dwWindowSize.Y = height;
}
else if (ServiceLocator::LocateGlobals().getConsoleInformation().IsInVtIoMode())
{
// If we're a PTY but we weren't explicitly told a size, use the window size as the buffer size.
_dwScreenBufferSize = _dwWindowSize;
}
}
// WARNING: this function doesn't perform any validation or conversion
void Settings::InitFromStateInfo(_In_ PCONSOLE_STATE_INFO pStateInfo)
{
_wFillAttribute = pStateInfo->ScreenAttributes;
_wPopupFillAttribute = pStateInfo->PopupAttributes;
_dwScreenBufferSize = pStateInfo->ScreenBufferSize;
_dwWindowSize = pStateInfo->WindowSize;
_dwWindowOrigin.X = (SHORT)pStateInfo->WindowPosX;
_dwWindowOrigin.Y = (SHORT)pStateInfo->WindowPosY;
_dwFontSize = pStateInfo->FontSize;
_uFontFamily = pStateInfo->FontFamily;
_uFontWeight = pStateInfo->FontWeight;
StringCchCopyW(_FaceName, ARRAYSIZE(_FaceName), pStateInfo->FaceName);
_uCursorSize = pStateInfo->CursorSize;
_bFullScreen = pStateInfo->FullScreen;
_bQuickEdit = pStateInfo->QuickEdit;
_bAutoPosition = pStateInfo->AutoPosition;
_bInsertMode = pStateInfo->InsertMode;
_bHistoryNoDup = pStateInfo->HistoryNoDup;
_uHistoryBufferSize = pStateInfo->HistoryBufferSize;
_uNumberOfHistoryBuffers = pStateInfo->NumberOfHistoryBuffers;
Fix SGR indexed colors to distinguish Indexed256 color (and more) (#5834) This PR introduces a new `ColorType` to allow us to distinguish between `SGR` indexed colors from the 16 color table, the lower half of which can be brightened, and the ISO/ITU indexed colors from the 256 color table, which have a fixed brightness. Retaining the distinction between these two types will enable us to forward the correct `SGR` sequences to conpty when addressing issue #2661. The other benefit of retaining the color index (which we didn't previously do for ISO/ITU colors) is that it ensures that the colors are updated correctly when the color scheme is changed. ## References * This is another step towards fixing the conpty narrowing bugs in issue #2661. * This is technically a fix for issue #5384, but that won't be apparent until #2661 is complete. ## PR Checklist * [x] Closes #1223 * [x] CLA signed. * [x] Tests added/passed * [ ] Requires documentation to be updated * [x] I've discussed this with core contributors already. ## Detailed Description of the Pull Request / Additional comments The first part of this PR was the introduction of a new `ColorType` in the `TextColor` class. Instead of just the one `IsIndex` type, there is now an `IsIndex16` and an `IsIndex256`. `IsIndex16` covers the eight original ANSI colors set with `SGR 3x` and `SGR 4x`, as well as the brighter aixterm variants set with `SGR 9x` and `SGR 10x`. `IsIndex256` covers the 256 ISO/ITU indexed colors set with `SGR 38;5` and `SGR 48;5`. There are two reasons for this distinction. The first is that the ANSI colors have the potential to be brightened by the `SGR 1` bold attribute, while the ISO/ITO color do not. The second reason is that when forwarding an attributes through conpty, we want to try and preserve the original SGR sequence that generated each color (to the extent that that is possible). By having the two separate types, we can map the `IsIndex16` colors back to ANSI/aixterm values, and `IsIndex256` to the ISO/ITU sequences. In addition to the VT colors, we also have to deal with the legacy colors set by the Windows console APIs, but we don't really need a separate type for those. It seemed most appropriate to me to store them as `IsIndex256` colors, since it doesn't make sense to have them brightened by the `SGR 1` attribute (which is what would happen if they were stored as `IsIndex16`). If a console app wanted a bright color it would have selected one, so we shouldn't be messing with that choice. The second part of the PR was the unification of the two color tables. Originally we had a 16 color table for the legacy colors, and a separate table for the 256 ISO/ITU colors. These have now been merged into one, so color table lookups no longer need to decide which of the two tables they should be referencing. I've also updated all the methods that took a color table as a parameter to use a `basic_string_view` instead of separate pointer and length variables, which I think makes them a lot easier and safer to work with. With this new architecture in place, I could now update the `AdaptDispatch` SGR implementation to store the ISO/ITU indexed colors as `IsIndex256` values, where before they were mapped to RGB values (which prevented them reflecting any color scheme changes). I could also update the `TerminalDispatch` implementation to differentiate between the two index types, so that the `SGR 1` brightening would only be applied to the ANSI colors. I've also done a bit of code refactoring to try and minimise any direct access to the color tables, getting rid of a lot of places that were copying tables with `memmove` operations. I'm hoping this will make it easier for us to update the code in the future if we want to reorder the table entries (which is likely a requirement for unifying the `AdaptDispatch` and `TerminalDispatch` implementations). ## Validation Steps Performed For testing, I've just updated the existing unit tests to account for the API changes. The `TextColorTests` required an extra parameter specifying the index type when setting an index. And the `AdapterTest` and `ScreenBufferTests` required the use of the new `SetIndexedXXX` methods in order to be explicit about the index type, instead of relying on the `TextAttribute` constructor and the old `SetForeground` and `SetBackground` methods which didn't have a way to differentiate index types. I've manually tested the various console APIs (`SetConsoleTextAttribute`, `ReadConsoleOutputAttribute`, and `ReadConsoleOutput`), to make sure they are still setting and reading the attributes as well as they used to. And I've tested the `SetConsoleScreenBufferInfoEx` and `GetConsoleScreenBufferInfoEx` APIs to make sure they can read and write the color table correctly. I've also tested the color table in the properties dialog, made sure it was saved and restored from the registry correctly, and similarly saved and restored from a shortcut link. Note that there are still a bunch of issues with the color table APIs, but no new problems have been introduced by the changes in this PR, as far as I could tell. I've also done a bunch of manual tests of `OSC 4` to make sure it's updating all the colors correctly (at least in conhost), and confirmed that the test case in issue #1223 now works as expected.
2020-05-28 00:34:45 +02:00
for (size_t i = 0; i < std::size(pStateInfo->ColorTable); i++)
{
Standardize the color table order (#11602) ## Summary of the Pull Request In the original implementation, we used two different orderings for the color tables. The WT color table used ANSI order, while the conhost color table used a Windows-specific order. This PR standardizes on the ANSI color order everywhere, so the usage of indexed colors is consistent across both parts of the code base, which will hopefully allow more of the code to be shared one day. ## References This is another small step towards de-duplicating `AdaptDispatch` and `TerminalDispatch` for issue #3849, and is essentially a followup to the SGR dispatch refactoring in PR #6728. ## PR Checklist * [x] Closes #11461 * [x] CLA signed. * [x] Tests added/passed * [ ] Documentation updated. * [ ] Schema updated. * [x] I've discussed this with core contributors already. Issue number where discussion took place: #11461 ## Detailed Description of the Pull Request / Additional comments Conhost still needs to deal with legacy attributes using Windows color order, so those values now need to be transposed to ANSI colors order when creating a `TextAttribute` object. This is done with a simple mapping table, which also handles the translation of the default color entries, so it's actually slightly faster than the original code. And when converting `TextAttribute` values back to legacy console attributes, we were already using a mapping table to handle the narrowing of 256-color values down to 16 colors, so we just needed to adjust that table to account for the translation from ANSI to Windows, and then could make use of the same table for both 256-color and 16-color values. There are also a few places in conhost that read from or write to the color tables, and those now need to transpose the index values. I've addressed this by creating separate `SetLegacyColorTableEntry` and `GetLegacyColorTableEntry` methods in the `Settings` class which take care of the mapping, so it's now clearer in which cases the code is dealing with legacy values, and which are ANSI values. These methods are used in the `SetConsoleScreenBufferInfoEx` and `GetConsoleScreenBufferInfoEx` APIs, as well as a few place where color preferences are handled (the registry, shortcut links, and the properties dialog), none of which are particularly sensitive to performance. However, we also use the legacy table when looking up the default colors for rendering (which happens a lot), so I've refactored that code so the default color calculations now only occur once per frame. The plus side of all of this is that the VT code doesn't need to do the index translation anymore, so we can finally get rid of all the calls to `XTermToWindowsIndex`, and we no longer need a separate color table initialization method for conhost, so I was able to merge a number of color initialization methods into one. We also no longer need to translate from legacy values to ANSI when generating VT sequences for conpty. The one exception to that is the 16-color VT renderer, which uses the `TextColor::GetLegacyIndex` method to approximate 16-color equivalents for RGB and 256-color values. Since that method returns a legacy index, it still needs to be translated to ANSI before it can be used in a VT sequence. But this should be no worse than it was before. One more special case is conhost's secret _Color Selection_ feature. That uses `Ctrl`+Number and `Alt`+Number key sequences to highlight parts of the buffer, and the mapping from number to color is based on the Windows color order. So that mapping now needs to be transposed, but that's also not performance sensitive. The only thing that I haven't bothered to update is the trace logging code in the `Telemetry` class, which logs the first 16 entries in the color table. Those entries are now going to be in a different order, but I didn't think that would be of great concern to anyone. ## Validation Steps Performed A lot of unit tests needed to be updated to use ANSI color constants when setting indexed colors, where before they might have been expecting values in Windows order. But this replaced a wild mix of different constants, sometimes having to use bit shifting, as well as values mapped with `XTermToWindowsIndex`, so I think the tests are a whole lot clearer now. Only a few cases have been left with literal numbers where that seemed more appropriate. In addition to getting the unit tests working, I've also manually tested the behaviour of all the console APIs which I thought could be affected by these changes, and confirmed that they produced the same results in the new code as they did in the original implementation. This includes: - `WriteConsoleOutput` - `ReadConsoleOutput` - `SetConsoleTextAttribute` with `WriteConsoleOutputCharacter` - `FillConsoleOutputAttribute` and `FillConsoleOutputCharacter` - `ScrollConsoleScreenBuffer` - `GetConsoleScreenBufferInfo` - `GetConsoleScreenBufferInfoEx` - `SetConsoleScreenBufferInfoEx` I've also manually tested changing colors via the console properties menu, the registry, and shortcut links, including setting default colors and popup colors. And I've tested that the "Quirks Mode" is still working as expected in PowerShell. In terms of performance, I wrote a little test app that filled a 80x9999 buffer with random color combinations using `WriteConsoleOutput`, which I figured was likely to be the most performance sensitive call, and I think it now actually performs slightly better than the original implementation. I've also tested similar code - just filling the visible window - with SGR VT sequences of various types, and the performance seems about the same as it was before.
2021-11-04 23:13:22 +01:00
SetLegacyColorTableEntry(i, pStateInfo->ColorTable[i]);
Fix SGR indexed colors to distinguish Indexed256 color (and more) (#5834) This PR introduces a new `ColorType` to allow us to distinguish between `SGR` indexed colors from the 16 color table, the lower half of which can be brightened, and the ISO/ITU indexed colors from the 256 color table, which have a fixed brightness. Retaining the distinction between these two types will enable us to forward the correct `SGR` sequences to conpty when addressing issue #2661. The other benefit of retaining the color index (which we didn't previously do for ISO/ITU colors) is that it ensures that the colors are updated correctly when the color scheme is changed. ## References * This is another step towards fixing the conpty narrowing bugs in issue #2661. * This is technically a fix for issue #5384, but that won't be apparent until #2661 is complete. ## PR Checklist * [x] Closes #1223 * [x] CLA signed. * [x] Tests added/passed * [ ] Requires documentation to be updated * [x] I've discussed this with core contributors already. ## Detailed Description of the Pull Request / Additional comments The first part of this PR was the introduction of a new `ColorType` in the `TextColor` class. Instead of just the one `IsIndex` type, there is now an `IsIndex16` and an `IsIndex256`. `IsIndex16` covers the eight original ANSI colors set with `SGR 3x` and `SGR 4x`, as well as the brighter aixterm variants set with `SGR 9x` and `SGR 10x`. `IsIndex256` covers the 256 ISO/ITU indexed colors set with `SGR 38;5` and `SGR 48;5`. There are two reasons for this distinction. The first is that the ANSI colors have the potential to be brightened by the `SGR 1` bold attribute, while the ISO/ITO color do not. The second reason is that when forwarding an attributes through conpty, we want to try and preserve the original SGR sequence that generated each color (to the extent that that is possible). By having the two separate types, we can map the `IsIndex16` colors back to ANSI/aixterm values, and `IsIndex256` to the ISO/ITU sequences. In addition to the VT colors, we also have to deal with the legacy colors set by the Windows console APIs, but we don't really need a separate type for those. It seemed most appropriate to me to store them as `IsIndex256` colors, since it doesn't make sense to have them brightened by the `SGR 1` attribute (which is what would happen if they were stored as `IsIndex16`). If a console app wanted a bright color it would have selected one, so we shouldn't be messing with that choice. The second part of the PR was the unification of the two color tables. Originally we had a 16 color table for the legacy colors, and a separate table for the 256 ISO/ITU colors. These have now been merged into one, so color table lookups no longer need to decide which of the two tables they should be referencing. I've also updated all the methods that took a color table as a parameter to use a `basic_string_view` instead of separate pointer and length variables, which I think makes them a lot easier and safer to work with. With this new architecture in place, I could now update the `AdaptDispatch` SGR implementation to store the ISO/ITU indexed colors as `IsIndex256` values, where before they were mapped to RGB values (which prevented them reflecting any color scheme changes). I could also update the `TerminalDispatch` implementation to differentiate between the two index types, so that the `SGR 1` brightening would only be applied to the ANSI colors. I've also done a bit of code refactoring to try and minimise any direct access to the color tables, getting rid of a lot of places that were copying tables with `memmove` operations. I'm hoping this will make it easier for us to update the code in the future if we want to reorder the table entries (which is likely a requirement for unifying the `AdaptDispatch` and `TerminalDispatch` implementations). ## Validation Steps Performed For testing, I've just updated the existing unit tests to account for the API changes. The `TextColorTests` required an extra parameter specifying the index type when setting an index. And the `AdapterTest` and `ScreenBufferTests` required the use of the new `SetIndexedXXX` methods in order to be explicit about the index type, instead of relying on the `TextAttribute` constructor and the old `SetForeground` and `SetBackground` methods which didn't have a way to differentiate index types. I've manually tested the various console APIs (`SetConsoleTextAttribute`, `ReadConsoleOutputAttribute`, and `ReadConsoleOutput`), to make sure they are still setting and reading the attributes as well as they used to. And I've tested the `SetConsoleScreenBufferInfoEx` and `GetConsoleScreenBufferInfoEx` APIs to make sure they can read and write the color table correctly. I've also tested the color table in the properties dialog, made sure it was saved and restored from the registry correctly, and similarly saved and restored from a shortcut link. Note that there are still a bunch of issues with the color table APIs, but no new problems have been introduced by the changes in this PR, as far as I could tell. I've also done a bunch of manual tests of `OSC 4` to make sure it's updating all the colors correctly (at least in conhost), and confirmed that the test case in issue #1223 now works as expected.
2020-05-28 00:34:45 +02:00
}
_uCodePage = pStateInfo->CodePage;
_bWrapText = !!pStateInfo->fWrapText;
_fFilterOnPaste = pStateInfo->fFilterOnPaste;
_fCtrlKeyShortcutsDisabled = pStateInfo->fCtrlKeyShortcutsDisabled;
_bLineSelection = pStateInfo->fLineSelection;
_bWindowAlpha = pStateInfo->bWindowTransparency;
_CursorColor = pStateInfo->CursorColor;
_CursorType = static_cast<CursorType>(pStateInfo->CursorType);
_fInterceptCopyPaste = pStateInfo->InterceptCopyPaste;
_DefaultForeground = pStateInfo->DefaultForeground;
_DefaultBackground = pStateInfo->DefaultBackground;
_TerminalScrolling = pStateInfo->TerminalScrolling;
}
// Method Description:
// - Create a CONSOLE_STATE_INFO with the current state of this settings structure.
// Arguments:
// - <none>
// Return Value:
// - a CONSOLE_STATE_INFO with the current state of this settings structure.
CONSOLE_STATE_INFO Settings::CreateConsoleStateInfo() const
{
CONSOLE_STATE_INFO csi = { 0 };
csi.ScreenAttributes = _wFillAttribute;
csi.PopupAttributes = _wPopupFillAttribute;
csi.ScreenBufferSize = _dwScreenBufferSize;
csi.WindowSize = _dwWindowSize;
csi.WindowPosX = (SHORT)_dwWindowOrigin.X;
csi.WindowPosY = (SHORT)_dwWindowOrigin.Y;
csi.FontSize = _dwFontSize;
csi.FontFamily = _uFontFamily;
csi.FontWeight = _uFontWeight;
StringCchCopyW(csi.FaceName, ARRAYSIZE(_FaceName), _FaceName);
csi.CursorSize = _uCursorSize;
csi.FullScreen = _bFullScreen;
csi.QuickEdit = _bQuickEdit;
csi.AutoPosition = _bAutoPosition;
csi.InsertMode = _bInsertMode;
csi.HistoryNoDup = _bHistoryNoDup;
csi.HistoryBufferSize = _uHistoryBufferSize;
csi.NumberOfHistoryBuffers = _uNumberOfHistoryBuffers;
Fix SGR indexed colors to distinguish Indexed256 color (and more) (#5834) This PR introduces a new `ColorType` to allow us to distinguish between `SGR` indexed colors from the 16 color table, the lower half of which can be brightened, and the ISO/ITU indexed colors from the 256 color table, which have a fixed brightness. Retaining the distinction between these two types will enable us to forward the correct `SGR` sequences to conpty when addressing issue #2661. The other benefit of retaining the color index (which we didn't previously do for ISO/ITU colors) is that it ensures that the colors are updated correctly when the color scheme is changed. ## References * This is another step towards fixing the conpty narrowing bugs in issue #2661. * This is technically a fix for issue #5384, but that won't be apparent until #2661 is complete. ## PR Checklist * [x] Closes #1223 * [x] CLA signed. * [x] Tests added/passed * [ ] Requires documentation to be updated * [x] I've discussed this with core contributors already. ## Detailed Description of the Pull Request / Additional comments The first part of this PR was the introduction of a new `ColorType` in the `TextColor` class. Instead of just the one `IsIndex` type, there is now an `IsIndex16` and an `IsIndex256`. `IsIndex16` covers the eight original ANSI colors set with `SGR 3x` and `SGR 4x`, as well as the brighter aixterm variants set with `SGR 9x` and `SGR 10x`. `IsIndex256` covers the 256 ISO/ITU indexed colors set with `SGR 38;5` and `SGR 48;5`. There are two reasons for this distinction. The first is that the ANSI colors have the potential to be brightened by the `SGR 1` bold attribute, while the ISO/ITO color do not. The second reason is that when forwarding an attributes through conpty, we want to try and preserve the original SGR sequence that generated each color (to the extent that that is possible). By having the two separate types, we can map the `IsIndex16` colors back to ANSI/aixterm values, and `IsIndex256` to the ISO/ITU sequences. In addition to the VT colors, we also have to deal with the legacy colors set by the Windows console APIs, but we don't really need a separate type for those. It seemed most appropriate to me to store them as `IsIndex256` colors, since it doesn't make sense to have them brightened by the `SGR 1` attribute (which is what would happen if they were stored as `IsIndex16`). If a console app wanted a bright color it would have selected one, so we shouldn't be messing with that choice. The second part of the PR was the unification of the two color tables. Originally we had a 16 color table for the legacy colors, and a separate table for the 256 ISO/ITU colors. These have now been merged into one, so color table lookups no longer need to decide which of the two tables they should be referencing. I've also updated all the methods that took a color table as a parameter to use a `basic_string_view` instead of separate pointer and length variables, which I think makes them a lot easier and safer to work with. With this new architecture in place, I could now update the `AdaptDispatch` SGR implementation to store the ISO/ITU indexed colors as `IsIndex256` values, where before they were mapped to RGB values (which prevented them reflecting any color scheme changes). I could also update the `TerminalDispatch` implementation to differentiate between the two index types, so that the `SGR 1` brightening would only be applied to the ANSI colors. I've also done a bit of code refactoring to try and minimise any direct access to the color tables, getting rid of a lot of places that were copying tables with `memmove` operations. I'm hoping this will make it easier for us to update the code in the future if we want to reorder the table entries (which is likely a requirement for unifying the `AdaptDispatch` and `TerminalDispatch` implementations). ## Validation Steps Performed For testing, I've just updated the existing unit tests to account for the API changes. The `TextColorTests` required an extra parameter specifying the index type when setting an index. And the `AdapterTest` and `ScreenBufferTests` required the use of the new `SetIndexedXXX` methods in order to be explicit about the index type, instead of relying on the `TextAttribute` constructor and the old `SetForeground` and `SetBackground` methods which didn't have a way to differentiate index types. I've manually tested the various console APIs (`SetConsoleTextAttribute`, `ReadConsoleOutputAttribute`, and `ReadConsoleOutput`), to make sure they are still setting and reading the attributes as well as they used to. And I've tested the `SetConsoleScreenBufferInfoEx` and `GetConsoleScreenBufferInfoEx` APIs to make sure they can read and write the color table correctly. I've also tested the color table in the properties dialog, made sure it was saved and restored from the registry correctly, and similarly saved and restored from a shortcut link. Note that there are still a bunch of issues with the color table APIs, but no new problems have been introduced by the changes in this PR, as far as I could tell. I've also done a bunch of manual tests of `OSC 4` to make sure it's updating all the colors correctly (at least in conhost), and confirmed that the test case in issue #1223 now works as expected.
2020-05-28 00:34:45 +02:00
for (size_t i = 0; i < std::size(csi.ColorTable); i++)
{
Standardize the color table order (#11602) ## Summary of the Pull Request In the original implementation, we used two different orderings for the color tables. The WT color table used ANSI order, while the conhost color table used a Windows-specific order. This PR standardizes on the ANSI color order everywhere, so the usage of indexed colors is consistent across both parts of the code base, which will hopefully allow more of the code to be shared one day. ## References This is another small step towards de-duplicating `AdaptDispatch` and `TerminalDispatch` for issue #3849, and is essentially a followup to the SGR dispatch refactoring in PR #6728. ## PR Checklist * [x] Closes #11461 * [x] CLA signed. * [x] Tests added/passed * [ ] Documentation updated. * [ ] Schema updated. * [x] I've discussed this with core contributors already. Issue number where discussion took place: #11461 ## Detailed Description of the Pull Request / Additional comments Conhost still needs to deal with legacy attributes using Windows color order, so those values now need to be transposed to ANSI colors order when creating a `TextAttribute` object. This is done with a simple mapping table, which also handles the translation of the default color entries, so it's actually slightly faster than the original code. And when converting `TextAttribute` values back to legacy console attributes, we were already using a mapping table to handle the narrowing of 256-color values down to 16 colors, so we just needed to adjust that table to account for the translation from ANSI to Windows, and then could make use of the same table for both 256-color and 16-color values. There are also a few places in conhost that read from or write to the color tables, and those now need to transpose the index values. I've addressed this by creating separate `SetLegacyColorTableEntry` and `GetLegacyColorTableEntry` methods in the `Settings` class which take care of the mapping, so it's now clearer in which cases the code is dealing with legacy values, and which are ANSI values. These methods are used in the `SetConsoleScreenBufferInfoEx` and `GetConsoleScreenBufferInfoEx` APIs, as well as a few place where color preferences are handled (the registry, shortcut links, and the properties dialog), none of which are particularly sensitive to performance. However, we also use the legacy table when looking up the default colors for rendering (which happens a lot), so I've refactored that code so the default color calculations now only occur once per frame. The plus side of all of this is that the VT code doesn't need to do the index translation anymore, so we can finally get rid of all the calls to `XTermToWindowsIndex`, and we no longer need a separate color table initialization method for conhost, so I was able to merge a number of color initialization methods into one. We also no longer need to translate from legacy values to ANSI when generating VT sequences for conpty. The one exception to that is the 16-color VT renderer, which uses the `TextColor::GetLegacyIndex` method to approximate 16-color equivalents for RGB and 256-color values. Since that method returns a legacy index, it still needs to be translated to ANSI before it can be used in a VT sequence. But this should be no worse than it was before. One more special case is conhost's secret _Color Selection_ feature. That uses `Ctrl`+Number and `Alt`+Number key sequences to highlight parts of the buffer, and the mapping from number to color is based on the Windows color order. So that mapping now needs to be transposed, but that's also not performance sensitive. The only thing that I haven't bothered to update is the trace logging code in the `Telemetry` class, which logs the first 16 entries in the color table. Those entries are now going to be in a different order, but I didn't think that would be of great concern to anyone. ## Validation Steps Performed A lot of unit tests needed to be updated to use ANSI color constants when setting indexed colors, where before they might have been expecting values in Windows order. But this replaced a wild mix of different constants, sometimes having to use bit shifting, as well as values mapped with `XTermToWindowsIndex`, so I think the tests are a whole lot clearer now. Only a few cases have been left with literal numbers where that seemed more appropriate. In addition to getting the unit tests working, I've also manually tested the behaviour of all the console APIs which I thought could be affected by these changes, and confirmed that they produced the same results in the new code as they did in the original implementation. This includes: - `WriteConsoleOutput` - `ReadConsoleOutput` - `SetConsoleTextAttribute` with `WriteConsoleOutputCharacter` - `FillConsoleOutputAttribute` and `FillConsoleOutputCharacter` - `ScrollConsoleScreenBuffer` - `GetConsoleScreenBufferInfo` - `GetConsoleScreenBufferInfoEx` - `SetConsoleScreenBufferInfoEx` I've also manually tested changing colors via the console properties menu, the registry, and shortcut links, including setting default colors and popup colors. And I've tested that the "Quirks Mode" is still working as expected in PowerShell. In terms of performance, I wrote a little test app that filled a 80x9999 buffer with random color combinations using `WriteConsoleOutput`, which I figured was likely to be the most performance sensitive call, and I think it now actually performs slightly better than the original implementation. I've also tested similar code - just filling the visible window - with SGR VT sequences of various types, and the performance seems about the same as it was before.
2021-11-04 23:13:22 +01:00
csi.ColorTable[i] = GetLegacyColorTableEntry(i);
Fix SGR indexed colors to distinguish Indexed256 color (and more) (#5834) This PR introduces a new `ColorType` to allow us to distinguish between `SGR` indexed colors from the 16 color table, the lower half of which can be brightened, and the ISO/ITU indexed colors from the 256 color table, which have a fixed brightness. Retaining the distinction between these two types will enable us to forward the correct `SGR` sequences to conpty when addressing issue #2661. The other benefit of retaining the color index (which we didn't previously do for ISO/ITU colors) is that it ensures that the colors are updated correctly when the color scheme is changed. ## References * This is another step towards fixing the conpty narrowing bugs in issue #2661. * This is technically a fix for issue #5384, but that won't be apparent until #2661 is complete. ## PR Checklist * [x] Closes #1223 * [x] CLA signed. * [x] Tests added/passed * [ ] Requires documentation to be updated * [x] I've discussed this with core contributors already. ## Detailed Description of the Pull Request / Additional comments The first part of this PR was the introduction of a new `ColorType` in the `TextColor` class. Instead of just the one `IsIndex` type, there is now an `IsIndex16` and an `IsIndex256`. `IsIndex16` covers the eight original ANSI colors set with `SGR 3x` and `SGR 4x`, as well as the brighter aixterm variants set with `SGR 9x` and `SGR 10x`. `IsIndex256` covers the 256 ISO/ITU indexed colors set with `SGR 38;5` and `SGR 48;5`. There are two reasons for this distinction. The first is that the ANSI colors have the potential to be brightened by the `SGR 1` bold attribute, while the ISO/ITO color do not. The second reason is that when forwarding an attributes through conpty, we want to try and preserve the original SGR sequence that generated each color (to the extent that that is possible). By having the two separate types, we can map the `IsIndex16` colors back to ANSI/aixterm values, and `IsIndex256` to the ISO/ITU sequences. In addition to the VT colors, we also have to deal with the legacy colors set by the Windows console APIs, but we don't really need a separate type for those. It seemed most appropriate to me to store them as `IsIndex256` colors, since it doesn't make sense to have them brightened by the `SGR 1` attribute (which is what would happen if they were stored as `IsIndex16`). If a console app wanted a bright color it would have selected one, so we shouldn't be messing with that choice. The second part of the PR was the unification of the two color tables. Originally we had a 16 color table for the legacy colors, and a separate table for the 256 ISO/ITU colors. These have now been merged into one, so color table lookups no longer need to decide which of the two tables they should be referencing. I've also updated all the methods that took a color table as a parameter to use a `basic_string_view` instead of separate pointer and length variables, which I think makes them a lot easier and safer to work with. With this new architecture in place, I could now update the `AdaptDispatch` SGR implementation to store the ISO/ITU indexed colors as `IsIndex256` values, where before they were mapped to RGB values (which prevented them reflecting any color scheme changes). I could also update the `TerminalDispatch` implementation to differentiate between the two index types, so that the `SGR 1` brightening would only be applied to the ANSI colors. I've also done a bit of code refactoring to try and minimise any direct access to the color tables, getting rid of a lot of places that were copying tables with `memmove` operations. I'm hoping this will make it easier for us to update the code in the future if we want to reorder the table entries (which is likely a requirement for unifying the `AdaptDispatch` and `TerminalDispatch` implementations). ## Validation Steps Performed For testing, I've just updated the existing unit tests to account for the API changes. The `TextColorTests` required an extra parameter specifying the index type when setting an index. And the `AdapterTest` and `ScreenBufferTests` required the use of the new `SetIndexedXXX` methods in order to be explicit about the index type, instead of relying on the `TextAttribute` constructor and the old `SetForeground` and `SetBackground` methods which didn't have a way to differentiate index types. I've manually tested the various console APIs (`SetConsoleTextAttribute`, `ReadConsoleOutputAttribute`, and `ReadConsoleOutput`), to make sure they are still setting and reading the attributes as well as they used to. And I've tested the `SetConsoleScreenBufferInfoEx` and `GetConsoleScreenBufferInfoEx` APIs to make sure they can read and write the color table correctly. I've also tested the color table in the properties dialog, made sure it was saved and restored from the registry correctly, and similarly saved and restored from a shortcut link. Note that there are still a bunch of issues with the color table APIs, but no new problems have been introduced by the changes in this PR, as far as I could tell. I've also done a bunch of manual tests of `OSC 4` to make sure it's updating all the colors correctly (at least in conhost), and confirmed that the test case in issue #1223 now works as expected.
2020-05-28 00:34:45 +02:00
}
csi.CodePage = _uCodePage;
csi.fWrapText = !!_bWrapText;
csi.fFilterOnPaste = _fFilterOnPaste;
csi.fCtrlKeyShortcutsDisabled = _fCtrlKeyShortcutsDisabled;
csi.fLineSelection = _bLineSelection;
csi.bWindowTransparency = _bWindowAlpha;
csi.CursorColor = _CursorColor;
csi.CursorType = static_cast<unsigned int>(_CursorType);
csi.InterceptCopyPaste = _fInterceptCopyPaste;
csi.DefaultForeground = _DefaultForeground;
csi.DefaultBackground = _DefaultBackground;
csi.TerminalScrolling = _TerminalScrolling;
return csi;
}
void Settings::Validate()
{
// If we were explicitly given a size in pixels from the startup info, divide by the font to turn it into characters.
// See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331%28v=vs.85%29.aspx
if (WI_IsFlagSet(_dwStartupFlags, STARTF_USESIZE))
{
// TODO: FIX
//// Get the font that we're going to use to convert pixels to characters.
//DWORD const dwFontIndexWant = FindCreateFont(_uFontFamily,
// _FaceName,
// _dwFontSize,
// _uFontWeight,
// _uCodePage);
//_dwWindowSize.X /= g_pfiFontInfo[dwFontIndexWant].Size.X;
//_dwWindowSize.Y /= g_pfiFontInfo[dwFontIndexWant].Size.Y;
}
// minimum screen buffer size 1x1
_dwScreenBufferSize.X = std::max(_dwScreenBufferSize.X, 1i16);
_dwScreenBufferSize.Y = std::max(_dwScreenBufferSize.Y, 1i16);
// minimum window size size 1x1
_dwWindowSize.X = std::max(_dwWindowSize.X, 1i16);
_dwWindowSize.Y = std::max(_dwWindowSize.Y, 1i16);
// if buffer size is less than window size, increase buffer size to meet window size
_dwScreenBufferSize.X = std::max(_dwWindowSize.X, _dwScreenBufferSize.X);
_dwScreenBufferSize.Y = std::max(_dwWindowSize.Y, _dwScreenBufferSize.Y);
// ensure that the window alpha value is not below the minimum. (no invisible windows)
// if it's below minimum, just set it to the opaque value
if (_bWindowAlpha < MIN_WINDOW_OPACITY)
{
_bWindowAlpha = BYTE_MAX;
}
// If text wrapping is on, ensure that the window width is the same as the buffer width.
if (_bWrapText)
{
_dwWindowSize.X = _dwScreenBufferSize.X;
}
// Ensure that our fill attributes only contain colors and not any box drawing or invert attributes.
WI_ClearAllFlags(_wFillAttribute, ~(FG_ATTRS | BG_ATTRS));
WI_ClearAllFlags(_wPopupFillAttribute, ~(FG_ATTRS | BG_ATTRS));
// If the extended color options are set to invalid values (all the same color), reset them.
if (_CursorColor != Cursor::s_InvertCursorColor && _CursorColor == _DefaultBackground)
{
_CursorColor = Cursor::s_InvertCursorColor;
}
if (_DefaultForeground != INVALID_COLOR && _DefaultForeground == _DefaultBackground)
{
// INVALID_COLOR is used as an "unset" sentinel in future attribute functions.
_DefaultForeground = _DefaultBackground = INVALID_COLOR;
// If the damaged settings _further_ propagated to the default fill attribute, fix it.
if (_wFillAttribute == 0)
{
// These attributes were taken from the Settings ctor and equal "gray on black"
_wFillAttribute = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
}
}
Improve conpty rendering of default colors in legacy apps (#6698) Essentially what this does is map the default legacy foreground and background attributes (typically white on black) to the `IsDefault` color type in the `TextColor` class. As a result, we can now initialize the buffer for "legacy" shells (like PowerShell and cmd.exe) with default colors, instead of white on black. This fixes the startup rendering in conpty clients, which expect an initial default background color. It also makes these colors update appropriately when the default palette values change. One complication in getting this to work, is that the console permits users to change which color indices are designated as defaults, so we can't assume they'll always be white on black. This means that the legacy-to-`TextAttribute` conversion will need access to those default values. Unfortunately the defaults are stored in the conhost `Settings` class (the `_wFillAttribute` field), which isn't easily accessible to all the code that needs to construct a `TextAttribute` from a legacy value. The `OutputCellIterator` is particularly problematic, because some iterator types need to generate a new `TextAttribute` on every iteration. So after trying a couple of different approaches, I decided that the least worst option would be to add a pair of static properties for the legacy defaults in the `TextAttribute` class itself, then refresh those values from the `Settings` class whenever the defaults changed (this only happens on startup, or when the conhost _Properties_ dialog is edited). And once the `TextAttribute` class had access to those defaults, it was fairly easy to adapt the constructor to handle the conversion of default values to the `IsDefault` color type. I could also then simplify the `TextAttribute::GetLegacyAttributes` method which does the reverse mapping, and which previously required the default values to be passed in as a parameter VALIDATION I had to make one small change to the `TestRoundtripExhaustive` unit test which assumed that all legacy attributes would convert to legacy color types, which is no longer the case, but otherwise all the existing tests passed as is. I added a new unit test verifying that the default legacy attributes correctly mapped to default color types, and the default color types were mapped back to the correct legacy attributes. I've manually confirmed that this fixed the issue raised in #5952, namely that the conhost screen is cleared with the correct default colors, and also that it is correctly refreshed when changing the palette from the properties dialog. And I've combined this PR with #6506, and confirmed that the PowerShell and the cmd shell renderings in Windows Terminal are at least improved, if not always perfect. This is a prerequisite for PR #6506 Closes #5952
2020-07-01 20:08:30 +02:00
// At this point the default fill attributes are fully initialized
// so we can pass on the final colors to the TextAttribute class.
TextAttribute::SetLegacyDefaultAttributes(_wFillAttribute);
FAIL_FAST_IF(!(_dwWindowSize.X > 0));
FAIL_FAST_IF(!(_dwWindowSize.Y > 0));
FAIL_FAST_IF(!(_dwScreenBufferSize.X > 0));
FAIL_FAST_IF(!(_dwScreenBufferSize.Y > 0));
}
DWORD Settings::GetVirtTermLevel() const
{
return _dwVirtTermLevel;
}
void Settings::SetVirtTermLevel(const DWORD dwVirtTermLevel)
{
_dwVirtTermLevel = dwVirtTermLevel;
}
bool Settings::IsAltF4CloseAllowed() const
{
return _fAllowAltF4Close;
}
void Settings::SetAltF4CloseAllowed(const bool fAllowAltF4Close)
{
_fAllowAltF4Close = fAllowAltF4Close;
}
bool Settings::IsReturnOnNewlineAutomatic() const
{
return _fAutoReturnOnNewline;
}
void Settings::SetAutomaticReturnOnNewline(const bool fAutoReturnOnNewline)
{
_fAutoReturnOnNewline = fAutoReturnOnNewline;
}
bool Settings::IsGridRenderingAllowedWorldwide() const
{
return _fRenderGridWorldwide;
}
void Settings::SetGridRenderingAllowedWorldwide(const bool fGridRenderingAllowed)
{
// Only trigger a notification and update the status if something has changed.
if (_fRenderGridWorldwide != fGridRenderingAllowed)
{
_fRenderGridWorldwide = fGridRenderingAllowed;
if (ServiceLocator::LocateGlobals().pRender != nullptr)
{
ServiceLocator::LocateGlobals().pRender->TriggerRedrawAll();
}
}
}
Add support for the DECSCNM screen mode (#3817) ## Summary of the Pull Request This adds support for the [`DECSCNM`](https://vt100.net/docs/vt510-rm/DECSCNM.html) private mode escape sequence, which toggles the display between normal and reverse screen modes. When reversed, the background and foreground colors are switched. Tested manually, with [Vttest](https://invisible-island.net/vttest/), and with some new unit tests. ## References This also fixes issue #72 for the most part, although if you toggle the mode too fast, there is no discernible flash. ## PR Checklist * [x] Closes #3773 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed * [ ] Requires documentation to be updated * [ ] 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: #xxx ## Detailed Description of the Pull Request / Additional comments I've implemented this as a new flag in the `Settings` class, along with updates to the `LookupForegroundColor` and `LookupBackgroundColor` methods, to switch the returned foreground and background colors when that flag is set. It also required a new private API in the `ConGetSet` interface to toggle the setting. And that API is then called from the `AdaptDispatch` class when the screen mode escape sequence is received. The last thing needed was to add a step to the `HardReset` method, to reset the mode back to normal, which is one of the `RIS` requirements. Note that this does currently work in the Windows Terminal, but once #2661 is implemented that may no longer be the case. It might become necessary to let the mode change sequences pass through conpty, and handle the color reversing on the client side. ## Validation Steps Performed I've added a state machine test to make sure the escape sequence is dispatched correctly, and a screen buffer test to confirm that the mode change does alter the interpretation of colors as expected. I've also confirmed that the various "light background" tests in Vttest now display correctly, and that the `tput flash` command (in a bash shell) does actually cause the screen to flash.
2020-01-22 23:29:50 +01:00
bool Settings::IsScreenReversed() const
{
return _fScreenReversed;
}
void Settings::SetScreenReversed(const bool fScreenReversed)
{
_fScreenReversed = fScreenReversed;
}
bool Settings::GetFilterOnPaste() const
{
return _fFilterOnPaste;
}
void Settings::SetFilterOnPaste(const bool fFilterOnPaste)
{
_fFilterOnPaste = fFilterOnPaste;
}
const std::wstring_view Settings::GetLaunchFaceName() const
{
return _LaunchFaceName;
}
void Settings::SetLaunchFaceName(const std::wstring_view launchFaceName)
{
_LaunchFaceName = launchFaceName;
}
UINT Settings::GetCodePage() const
{
return _uCodePage;
}
void Settings::SetCodePage(const UINT uCodePage)
{
_uCodePage = uCodePage;
}
UINT Settings::GetScrollScale() const
{
return _uScrollScale;
}
void Settings::SetScrollScale(const UINT uScrollScale)
{
_uScrollScale = uScrollScale;
}
bool Settings::GetTrimLeadingZeros() const
{
return _fTrimLeadingZeros;
}
void Settings::SetTrimLeadingZeros(const bool fTrimLeadingZeros)
{
_fTrimLeadingZeros = fTrimLeadingZeros;
}
bool Settings::GetEnableColorSelection() const
{
return _fEnableColorSelection;
}
void Settings::SetEnableColorSelection(const bool fEnableColorSelection)
{
_fEnableColorSelection = fEnableColorSelection;
}
bool Settings::GetLineSelection() const
{
return _bLineSelection;
}
void Settings::SetLineSelection(const bool bLineSelection)
{
_bLineSelection = bLineSelection;
}
bool Settings::GetWrapText() const
{
return _bWrapText;
}
void Settings::SetWrapText(const bool bWrapText)
{
_bWrapText = bWrapText;
}
bool Settings::GetCtrlKeyShortcutsDisabled() const
{
return _fCtrlKeyShortcutsDisabled;
}
void Settings::SetCtrlKeyShortcutsDisabled(const bool fCtrlKeyShortcutsDisabled)
{
_fCtrlKeyShortcutsDisabled = fCtrlKeyShortcutsDisabled;
}
BYTE Settings::GetWindowAlpha() const
{
return _bWindowAlpha;
}
void Settings::SetWindowAlpha(const BYTE bWindowAlpha)
{
// if we're out of bounds, set it to 100% opacity so it appears as if nothing happened.
_bWindowAlpha = (bWindowAlpha < MIN_WINDOW_OPACITY) ? BYTE_MAX : bWindowAlpha;
}
DWORD Settings::GetHotKey() const
{
return _dwHotKey;
}
void Settings::SetHotKey(const DWORD dwHotKey)
{
_dwHotKey = dwHotKey;
}
DWORD Settings::GetStartupFlags() const
{
return _dwStartupFlags;
}
void Settings::SetStartupFlags(const DWORD dwStartupFlags)
{
_dwStartupFlags = dwStartupFlags;
}
WORD Settings::GetFillAttribute() const
{
return _wFillAttribute;
}
void Settings::SetFillAttribute(const WORD wFillAttribute)
{
_wFillAttribute = wFillAttribute;
// Do not allow the default fill attribute to use any attrs other than fg/bg colors.
// This prevents us from accidentally inverting everything or suddenly drawing lines
// everywhere by default.
WI_ClearAllFlags(_wFillAttribute, ~(FG_ATTRS | BG_ATTRS));
}
WORD Settings::GetPopupFillAttribute() const
{
return _wPopupFillAttribute;
}
void Settings::SetPopupFillAttribute(const WORD wPopupFillAttribute)
{
_wPopupFillAttribute = wPopupFillAttribute;
// Do not allow the default popup fill attribute to use any attrs other than fg/bg colors.
// This prevents us from accidentally inverting everything or suddenly drawing lines
// everywhere by default.
WI_ClearAllFlags(_wPopupFillAttribute, ~(FG_ATTRS | BG_ATTRS));
}
WORD Settings::GetShowWindow() const
{
return _wShowWindow;
}
void Settings::SetShowWindow(const WORD wShowWindow)
{
_wShowWindow = wShowWindow;
}
WORD Settings::GetReserved() const
{
return _wReserved;
}
void Settings::SetReserved(const WORD wReserved)
{
_wReserved = wReserved;
}
COORD Settings::GetScreenBufferSize() const
{
return _dwScreenBufferSize;
}
void Settings::SetScreenBufferSize(const COORD dwScreenBufferSize)
{
_dwScreenBufferSize = dwScreenBufferSize;
}
COORD Settings::GetWindowSize() const
{
return _dwWindowSize;
}
void Settings::SetWindowSize(const COORD dwWindowSize)
{
_dwWindowSize = dwWindowSize;
}
bool Settings::IsWindowSizePixelsValid() const
{
return _fUseWindowSizePixels;
}
COORD Settings::GetWindowSizePixels() const
{
return _dwWindowSizePixels;
}
void Settings::SetWindowSizePixels(const COORD dwWindowSizePixels)
{
_dwWindowSizePixels = dwWindowSizePixels;
}
COORD Settings::GetWindowOrigin() const
{
return _dwWindowOrigin;
}
void Settings::SetWindowOrigin(const COORD dwWindowOrigin)
{
_dwWindowOrigin = dwWindowOrigin;
}
DWORD Settings::GetFont() const
{
return _nFont;
}
void Settings::SetFont(const DWORD nFont)
{
_nFont = nFont;
}
COORD Settings::GetFontSize() const
{
return _dwFontSize;
}
void Settings::SetFontSize(const COORD dwFontSize)
{
_dwFontSize = dwFontSize;
}
UINT Settings::GetFontFamily() const
{
return _uFontFamily;
}
void Settings::SetFontFamily(const UINT uFontFamily)
{
_uFontFamily = uFontFamily;
}
UINT Settings::GetFontWeight() const
{
return _uFontWeight;
}
void Settings::SetFontWeight(const UINT uFontWeight)
{
_uFontWeight = uFontWeight;
}
const WCHAR* const Settings::GetFaceName() const
{
return _FaceName;
}
void Settings::SetFaceName(const std::wstring_view faceName)
{
auto extent = std::min<size_t>(faceName.size(), ARRAYSIZE(_FaceName));
StringCchCopyW(_FaceName, extent, faceName.data());
}
UINT Settings::GetCursorSize() const
{
return _uCursorSize;
}
void Settings::SetCursorSize(const UINT uCursorSize)
{
_uCursorSize = uCursorSize;
}
bool Settings::GetFullScreen() const
{
return _bFullScreen;
}
void Settings::SetFullScreen(const bool bFullScreen)
{
_bFullScreen = bFullScreen;
}
bool Settings::GetQuickEdit() const
{
return _bQuickEdit;
}
void Settings::SetQuickEdit(const bool bQuickEdit)
{
_bQuickEdit = bQuickEdit;
}
bool Settings::GetInsertMode() const
{
return _bInsertMode;
}
void Settings::SetInsertMode(const bool bInsertMode)
{
_bInsertMode = bInsertMode;
}
bool Settings::GetAutoPosition() const
{
return _bAutoPosition;
}
void Settings::SetAutoPosition(const bool bAutoPosition)
{
_bAutoPosition = bAutoPosition;
}
UINT Settings::GetHistoryBufferSize() const
{
return _uHistoryBufferSize;
}
void Settings::SetHistoryBufferSize(const UINT uHistoryBufferSize)
{
_uHistoryBufferSize = uHistoryBufferSize;
}
UINT Settings::GetNumberOfHistoryBuffers() const
{
return _uNumberOfHistoryBuffers;
}
void Settings::SetNumberOfHistoryBuffers(const UINT uNumberOfHistoryBuffers)
{
_uNumberOfHistoryBuffers = uNumberOfHistoryBuffers;
}
bool Settings::GetHistoryNoDup() const
{
return _bHistoryNoDup;
}
void Settings::SetHistoryNoDup(const bool bHistoryNoDup)
{
_bHistoryNoDup = bHistoryNoDup;
}
bool Settings::IsStartupTitleIsLinkNameSet() const
{
return WI_IsFlagSet(_dwStartupFlags, STARTF_TITLEISLINKNAME);
}
bool Settings::IsFaceNameSet() const
{
return GetFaceName()[0] != '\0';
}
void Settings::UnsetStartupFlag(const DWORD dwFlagToUnset)
{
_dwStartupFlags &= ~dwFlagToUnset;
}
Standardize the color table order (#11602) ## Summary of the Pull Request In the original implementation, we used two different orderings for the color tables. The WT color table used ANSI order, while the conhost color table used a Windows-specific order. This PR standardizes on the ANSI color order everywhere, so the usage of indexed colors is consistent across both parts of the code base, which will hopefully allow more of the code to be shared one day. ## References This is another small step towards de-duplicating `AdaptDispatch` and `TerminalDispatch` for issue #3849, and is essentially a followup to the SGR dispatch refactoring in PR #6728. ## PR Checklist * [x] Closes #11461 * [x] CLA signed. * [x] Tests added/passed * [ ] Documentation updated. * [ ] Schema updated. * [x] I've discussed this with core contributors already. Issue number where discussion took place: #11461 ## Detailed Description of the Pull Request / Additional comments Conhost still needs to deal with legacy attributes using Windows color order, so those values now need to be transposed to ANSI colors order when creating a `TextAttribute` object. This is done with a simple mapping table, which also handles the translation of the default color entries, so it's actually slightly faster than the original code. And when converting `TextAttribute` values back to legacy console attributes, we were already using a mapping table to handle the narrowing of 256-color values down to 16 colors, so we just needed to adjust that table to account for the translation from ANSI to Windows, and then could make use of the same table for both 256-color and 16-color values. There are also a few places in conhost that read from or write to the color tables, and those now need to transpose the index values. I've addressed this by creating separate `SetLegacyColorTableEntry` and `GetLegacyColorTableEntry` methods in the `Settings` class which take care of the mapping, so it's now clearer in which cases the code is dealing with legacy values, and which are ANSI values. These methods are used in the `SetConsoleScreenBufferInfoEx` and `GetConsoleScreenBufferInfoEx` APIs, as well as a few place where color preferences are handled (the registry, shortcut links, and the properties dialog), none of which are particularly sensitive to performance. However, we also use the legacy table when looking up the default colors for rendering (which happens a lot), so I've refactored that code so the default color calculations now only occur once per frame. The plus side of all of this is that the VT code doesn't need to do the index translation anymore, so we can finally get rid of all the calls to `XTermToWindowsIndex`, and we no longer need a separate color table initialization method for conhost, so I was able to merge a number of color initialization methods into one. We also no longer need to translate from legacy values to ANSI when generating VT sequences for conpty. The one exception to that is the 16-color VT renderer, which uses the `TextColor::GetLegacyIndex` method to approximate 16-color equivalents for RGB and 256-color values. Since that method returns a legacy index, it still needs to be translated to ANSI before it can be used in a VT sequence. But this should be no worse than it was before. One more special case is conhost's secret _Color Selection_ feature. That uses `Ctrl`+Number and `Alt`+Number key sequences to highlight parts of the buffer, and the mapping from number to color is based on the Windows color order. So that mapping now needs to be transposed, but that's also not performance sensitive. The only thing that I haven't bothered to update is the trace logging code in the `Telemetry` class, which logs the first 16 entries in the color table. Those entries are now going to be in a different order, but I didn't think that would be of great concern to anyone. ## Validation Steps Performed A lot of unit tests needed to be updated to use ANSI color constants when setting indexed colors, where before they might have been expecting values in Windows order. But this replaced a wild mix of different constants, sometimes having to use bit shifting, as well as values mapped with `XTermToWindowsIndex`, so I think the tests are a whole lot clearer now. Only a few cases have been left with literal numbers where that seemed more appropriate. In addition to getting the unit tests working, I've also manually tested the behaviour of all the console APIs which I thought could be affected by these changes, and confirmed that they produced the same results in the new code as they did in the original implementation. This includes: - `WriteConsoleOutput` - `ReadConsoleOutput` - `SetConsoleTextAttribute` with `WriteConsoleOutputCharacter` - `FillConsoleOutputAttribute` and `FillConsoleOutputCharacter` - `ScrollConsoleScreenBuffer` - `GetConsoleScreenBufferInfo` - `GetConsoleScreenBufferInfoEx` - `SetConsoleScreenBufferInfoEx` I've also manually tested changing colors via the console properties menu, the registry, and shortcut links, including setting default colors and popup colors. And I've tested that the "Quirks Mode" is still working as expected in PowerShell. In terms of performance, I wrote a little test app that filled a 80x9999 buffer with random color combinations using `WriteConsoleOutput`, which I figured was likely to be the most performance sensitive call, and I think it now actually performs slightly better than the original implementation. I've also tested similar code - just filling the visible window - with SGR VT sequences of various types, and the performance seems about the same as it was before.
2021-11-04 23:13:22 +01:00
void Settings::SetColorTableEntry(const size_t index, const COLORREF ColorValue)
{
_colorTable.at(index) = ColorValue;
}
COLORREF Settings::GetColorTableEntry(const size_t index) const
{
Fix SGR indexed colors to distinguish Indexed256 color (and more) (#5834) This PR introduces a new `ColorType` to allow us to distinguish between `SGR` indexed colors from the 16 color table, the lower half of which can be brightened, and the ISO/ITU indexed colors from the 256 color table, which have a fixed brightness. Retaining the distinction between these two types will enable us to forward the correct `SGR` sequences to conpty when addressing issue #2661. The other benefit of retaining the color index (which we didn't previously do for ISO/ITU colors) is that it ensures that the colors are updated correctly when the color scheme is changed. ## References * This is another step towards fixing the conpty narrowing bugs in issue #2661. * This is technically a fix for issue #5384, but that won't be apparent until #2661 is complete. ## PR Checklist * [x] Closes #1223 * [x] CLA signed. * [x] Tests added/passed * [ ] Requires documentation to be updated * [x] I've discussed this with core contributors already. ## Detailed Description of the Pull Request / Additional comments The first part of this PR was the introduction of a new `ColorType` in the `TextColor` class. Instead of just the one `IsIndex` type, there is now an `IsIndex16` and an `IsIndex256`. `IsIndex16` covers the eight original ANSI colors set with `SGR 3x` and `SGR 4x`, as well as the brighter aixterm variants set with `SGR 9x` and `SGR 10x`. `IsIndex256` covers the 256 ISO/ITU indexed colors set with `SGR 38;5` and `SGR 48;5`. There are two reasons for this distinction. The first is that the ANSI colors have the potential to be brightened by the `SGR 1` bold attribute, while the ISO/ITO color do not. The second reason is that when forwarding an attributes through conpty, we want to try and preserve the original SGR sequence that generated each color (to the extent that that is possible). By having the two separate types, we can map the `IsIndex16` colors back to ANSI/aixterm values, and `IsIndex256` to the ISO/ITU sequences. In addition to the VT colors, we also have to deal with the legacy colors set by the Windows console APIs, but we don't really need a separate type for those. It seemed most appropriate to me to store them as `IsIndex256` colors, since it doesn't make sense to have them brightened by the `SGR 1` attribute (which is what would happen if they were stored as `IsIndex16`). If a console app wanted a bright color it would have selected one, so we shouldn't be messing with that choice. The second part of the PR was the unification of the two color tables. Originally we had a 16 color table for the legacy colors, and a separate table for the 256 ISO/ITU colors. These have now been merged into one, so color table lookups no longer need to decide which of the two tables they should be referencing. I've also updated all the methods that took a color table as a parameter to use a `basic_string_view` instead of separate pointer and length variables, which I think makes them a lot easier and safer to work with. With this new architecture in place, I could now update the `AdaptDispatch` SGR implementation to store the ISO/ITU indexed colors as `IsIndex256` values, where before they were mapped to RGB values (which prevented them reflecting any color scheme changes). I could also update the `TerminalDispatch` implementation to differentiate between the two index types, so that the `SGR 1` brightening would only be applied to the ANSI colors. I've also done a bit of code refactoring to try and minimise any direct access to the color tables, getting rid of a lot of places that were copying tables with `memmove` operations. I'm hoping this will make it easier for us to update the code in the future if we want to reorder the table entries (which is likely a requirement for unifying the `AdaptDispatch` and `TerminalDispatch` implementations). ## Validation Steps Performed For testing, I've just updated the existing unit tests to account for the API changes. The `TextColorTests` required an extra parameter specifying the index type when setting an index. And the `AdapterTest` and `ScreenBufferTests` required the use of the new `SetIndexedXXX` methods in order to be explicit about the index type, instead of relying on the `TextAttribute` constructor and the old `SetForeground` and `SetBackground` methods which didn't have a way to differentiate index types. I've manually tested the various console APIs (`SetConsoleTextAttribute`, `ReadConsoleOutputAttribute`, and `ReadConsoleOutput`), to make sure they are still setting and reading the attributes as well as they used to. And I've tested the `SetConsoleScreenBufferInfoEx` and `GetConsoleScreenBufferInfoEx` APIs to make sure they can read and write the color table correctly. I've also tested the color table in the properties dialog, made sure it was saved and restored from the registry correctly, and similarly saved and restored from a shortcut link. Note that there are still a bunch of issues with the color table APIs, but no new problems have been introduced by the changes in this PR, as far as I could tell. I've also done a bunch of manual tests of `OSC 4` to make sure it's updating all the colors correctly (at least in conhost), and confirmed that the test case in issue #1223 now works as expected.
2020-05-28 00:34:45 +02:00
return _colorTable.at(index);
}
Standardize the color table order (#11602) ## Summary of the Pull Request In the original implementation, we used two different orderings for the color tables. The WT color table used ANSI order, while the conhost color table used a Windows-specific order. This PR standardizes on the ANSI color order everywhere, so the usage of indexed colors is consistent across both parts of the code base, which will hopefully allow more of the code to be shared one day. ## References This is another small step towards de-duplicating `AdaptDispatch` and `TerminalDispatch` for issue #3849, and is essentially a followup to the SGR dispatch refactoring in PR #6728. ## PR Checklist * [x] Closes #11461 * [x] CLA signed. * [x] Tests added/passed * [ ] Documentation updated. * [ ] Schema updated. * [x] I've discussed this with core contributors already. Issue number where discussion took place: #11461 ## Detailed Description of the Pull Request / Additional comments Conhost still needs to deal with legacy attributes using Windows color order, so those values now need to be transposed to ANSI colors order when creating a `TextAttribute` object. This is done with a simple mapping table, which also handles the translation of the default color entries, so it's actually slightly faster than the original code. And when converting `TextAttribute` values back to legacy console attributes, we were already using a mapping table to handle the narrowing of 256-color values down to 16 colors, so we just needed to adjust that table to account for the translation from ANSI to Windows, and then could make use of the same table for both 256-color and 16-color values. There are also a few places in conhost that read from or write to the color tables, and those now need to transpose the index values. I've addressed this by creating separate `SetLegacyColorTableEntry` and `GetLegacyColorTableEntry` methods in the `Settings` class which take care of the mapping, so it's now clearer in which cases the code is dealing with legacy values, and which are ANSI values. These methods are used in the `SetConsoleScreenBufferInfoEx` and `GetConsoleScreenBufferInfoEx` APIs, as well as a few place where color preferences are handled (the registry, shortcut links, and the properties dialog), none of which are particularly sensitive to performance. However, we also use the legacy table when looking up the default colors for rendering (which happens a lot), so I've refactored that code so the default color calculations now only occur once per frame. The plus side of all of this is that the VT code doesn't need to do the index translation anymore, so we can finally get rid of all the calls to `XTermToWindowsIndex`, and we no longer need a separate color table initialization method for conhost, so I was able to merge a number of color initialization methods into one. We also no longer need to translate from legacy values to ANSI when generating VT sequences for conpty. The one exception to that is the 16-color VT renderer, which uses the `TextColor::GetLegacyIndex` method to approximate 16-color equivalents for RGB and 256-color values. Since that method returns a legacy index, it still needs to be translated to ANSI before it can be used in a VT sequence. But this should be no worse than it was before. One more special case is conhost's secret _Color Selection_ feature. That uses `Ctrl`+Number and `Alt`+Number key sequences to highlight parts of the buffer, and the mapping from number to color is based on the Windows color order. So that mapping now needs to be transposed, but that's also not performance sensitive. The only thing that I haven't bothered to update is the trace logging code in the `Telemetry` class, which logs the first 16 entries in the color table. Those entries are now going to be in a different order, but I didn't think that would be of great concern to anyone. ## Validation Steps Performed A lot of unit tests needed to be updated to use ANSI color constants when setting indexed colors, where before they might have been expecting values in Windows order. But this replaced a wild mix of different constants, sometimes having to use bit shifting, as well as values mapped with `XTermToWindowsIndex`, so I think the tests are a whole lot clearer now. Only a few cases have been left with literal numbers where that seemed more appropriate. In addition to getting the unit tests working, I've also manually tested the behaviour of all the console APIs which I thought could be affected by these changes, and confirmed that they produced the same results in the new code as they did in the original implementation. This includes: - `WriteConsoleOutput` - `ReadConsoleOutput` - `SetConsoleTextAttribute` with `WriteConsoleOutputCharacter` - `FillConsoleOutputAttribute` and `FillConsoleOutputCharacter` - `ScrollConsoleScreenBuffer` - `GetConsoleScreenBufferInfo` - `GetConsoleScreenBufferInfoEx` - `SetConsoleScreenBufferInfoEx` I've also manually tested changing colors via the console properties menu, the registry, and shortcut links, including setting default colors and popup colors. And I've tested that the "Quirks Mode" is still working as expected in PowerShell. In terms of performance, I wrote a little test app that filled a 80x9999 buffer with random color combinations using `WriteConsoleOutput`, which I figured was likely to be the most performance sensitive call, and I think it now actually performs slightly better than the original implementation. I've also tested similar code - just filling the visible window - with SGR VT sequences of various types, and the performance seems about the same as it was before.
2021-11-04 23:13:22 +01:00
void Settings::SetLegacyColorTableEntry(const size_t index, const COLORREF ColorValue)
{
_colorTable.at(TextColor::TransposeLegacyIndex(index)) = ColorValue;
}
COLORREF Settings::GetLegacyColorTableEntry(const size_t index) const
{
return _colorTable.at(TextColor::TransposeLegacyIndex(index));
}
COLORREF Settings::GetCursorColor() const noexcept
{
return _CursorColor;
}
CursorType Settings::GetCursorType() const noexcept
{
return _CursorType;
}
void Settings::SetCursorColor(const COLORREF CursorColor) noexcept
{
_CursorColor = CursorColor;
}
void Settings::SetCursorType(const CursorType cursorType) noexcept
{
_CursorType = cursorType;
}
bool Settings::GetInterceptCopyPaste() const noexcept
{
return _fInterceptCopyPaste;
}
void Settings::SetInterceptCopyPaste(const bool interceptCopyPaste) noexcept
{
_fInterceptCopyPaste = interceptCopyPaste;
}
COLORREF Settings::GetDefaultForegroundColor() const noexcept
{
return _DefaultForeground;
}
void Settings::SetDefaultForegroundColor(const COLORREF defaultForeground) noexcept
{
_DefaultForeground = defaultForeground;
}
COLORREF Settings::GetDefaultBackgroundColor() const noexcept
{
return _DefaultBackground;
}
void Settings::SetDefaultBackgroundColor(const COLORREF defaultBackground) noexcept
{
_DefaultBackground = defaultBackground;
}
bool Settings::IsTerminalScrolling() const noexcept
{
return _TerminalScrolling;
}
void Settings::SetTerminalScrolling(const bool terminalScrollingEnabled) noexcept
{
_TerminalScrolling = terminalScrollingEnabled;
}
Introduce AtlasEngine - A new text rendering prototype (#11623) This commit introduces "AtlasEngine", a new text renderer based on DxEngine. But unlike it, DirectWrite and Direct2D are only used to rasterize glyphs. Blending and placing these glyphs into the target view is being done using Direct3D and a simple HLSL shader. Since this new renderer more aggressively assumes that the text is monospace, it simplifies the implementation: The viewport is divided into cells, and its data is stored as a simple matrix. Modifications to this matrix involve only simple pointer arithmetic and is easy to understand. But just like with DxEngine however, DirectWrite related code remains extremely complex and hard to understand. Supported features: * Basic text rendering with grayscale AA * Foreground and background colors * Emojis, including zero width joiners * Underline, dotted underline, strikethrough * Custom font axes and features * Selections * All cursor styles * Full alpha support for all colors * _Should_ work with Windows 7 Unsupported features: * A more conservative GPU memory usage The backing texture atlas for glyphs is grow-only and will not shrink. After 256MB of memory is used up (~20k glyphs) text output will be broken until the renderer is restarted. * ClearType * Remaining gridlines (left, right, top, bottom, double underline) * Hyperlinks don't get full underlines if hovered in WT * Softfonts * Non-default line renditions Performance: * Runs at up to native display refresh rate Unfortunately the frame rate often drops below refresh rate, due us fighting over the buffer lock with other parts of the application. * CPU consumption is up to halved compared to DxEngine AtlasEngine is still highly unoptimized. Glyph hashing consumes up to a third of the current CPU time. * No regressions in WT performance VT parsing and related buffer management takes up most of the CPU time (~85%), due to which the AtlasEngine can't show any further improvements. * ~2x improvement in raw text throughput in OpenConsole compared to DxEngine running at 144 FPS * ≥10x improvement in colored VT output in WT/OpenConsole compared to DxEngine running at 144 FPS
2021-11-13 01:10:06 +01:00
// Determines whether our primary renderer should be DirectX or GDI.
// This is based on user preference and velocity hold back state.
UseDx Settings::GetUseDx() const noexcept
{
return _fUseDx;
}
bool Settings::GetCopyColor() const noexcept
{
return _fCopyColor;
}