// Copyright (c) Microsoft Corporation. // Licensed under the MIT license. #include "precomp.h" #include "settings.hpp" #include "..\interactivity\inc\ServiceLocator.hpp" #include "../types/inc/utils.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. _fScreenReversed(false), // window size pixels initialized below _fInterceptCopyPaste(0), _DefaultForeground(INVALID_COLOR), _DefaultBackground(INVALID_COLOR), _fUseDx(false), _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 tableView = { _ColorTable, gsl::narrow(COLOR_TABLE_SIZE) }; gsl::span xtermTableView = { _XtermColorTable, gsl::narrow(XTERM_COLOR_TABLE_SIZE) }; ::Microsoft::Console::Utils::Initialize256ColorTable(xtermTableView); ::Microsoft::Console::Utils::InitializeCampbellColorTableForConhost(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: // - // Return Value: // - - 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; gsl::span tableView = { _ColorTable, gsl::narrow(COLOR_TABLE_SIZE) }; ::Microsoft::Console::Utils::InitializeCampbellColorTableForConhost(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: // - 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; memmove(_ColorTable, pStateInfo->ColorTable, sizeof(_ColorTable)); _uCodePage = pStateInfo->CodePage; _bWrapText = !!pStateInfo->fWrapText; _fFilterOnPaste = pStateInfo->fFilterOnPaste; _fCtrlKeyShortcutsDisabled = pStateInfo->fCtrlKeyShortcutsDisabled; _bLineSelection = pStateInfo->fLineSelection; _bWindowAlpha = pStateInfo->bWindowTransparency; _CursorColor = pStateInfo->CursorColor; _CursorType = static_cast(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: // - // 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; memmove(csi.ColorTable, _ColorTable, sizeof(_ColorTable)); 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(_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; } } 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(); } } } 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(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; } const COLORREF* const Settings::GetColorTable() const { return _ColorTable; } void Settings::SetColorTable(_In_reads_(cSize) const COLORREF* const pColorTable, const size_t cSize) { size_t cSizeWritten = std::min(cSize, static_cast(COLOR_TABLE_SIZE)); memmove(_ColorTable, pColorTable, cSizeWritten * sizeof(COLORREF)); } void Settings::SetColorTableEntry(const size_t index, const COLORREF ColorValue) { if (index < ARRAYSIZE(_ColorTable)) { _ColorTable[index] = ColorValue; } else { _XtermColorTable[index] = ColorValue; } } 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; } const size_t Settings::GetColorTableSize() const { return ARRAYSIZE(_ColorTable); } COLORREF Settings::GetColorTableEntry(const size_t index) const { if (index < ARRAYSIZE(_ColorTable)) { return _ColorTable[index]; } else { return _XtermColorTable[index]; } } // Routine Description: // - Generates a legacy attribute from the given TextAttributes. // This needs to be a method on the Settings because the generated index // is dependent upon the particular values of the color table at the time of reading. // Parameters: // - attributes - The TextAttributes to generate a legacy attribute for. // Return value: // - A WORD representing the entry in the color table that most closely represents the given fullcolor attributes. WORD Settings::GenerateLegacyAttributes(const TextAttribute attributes) const { const WORD wLegacyOriginal = attributes.GetLegacyAttributes(); if (attributes.IsLegacy()) { return wLegacyOriginal; } // We need to construct the legacy attributes manually // First start with whatever our default legacy attributes are BYTE fgIndex = static_cast((_wFillAttribute & FG_ATTRS)); BYTE bgIndex = static_cast((_wFillAttribute & BG_ATTRS) >> 4); // If the attributes have any RGB components, we need to match that RGB // color to a color table value. if (attributes.IsRgb()) { // If the attribute doesn't have a "default" colored *ground, look up // the nearest color table value for its *ground. const COLORREF rgbForeground = LookupForegroundColor(attributes); fgIndex = attributes.ForegroundIsDefault() ? fgIndex : static_cast(FindNearestTableIndex(rgbForeground)); const COLORREF rgbBackground = LookupBackgroundColor(attributes); bgIndex = attributes.BackgroundIsDefault() ? bgIndex : static_cast(FindNearestTableIndex(rgbBackground)); } // TextAttribute::GetLegacyAttributes(BYTE, BYTE) will use the legacy value // it has if the component is a legacy index, otherwise it will use the // provided byte for each index. In this way, we can provide a value to // use should it not already have one. const WORD wCompleteAttr = attributes.GetLegacyAttributes(fgIndex, bgIndex); return wCompleteAttr; } //Routine Description: // For a given RGB color Color, finds the nearest color from the array ColorTable, and returns the index of that match. //Arguments: // - Color - The RGB color to fine the nearest color to. // - ColorTable - The array of colors to find a nearest color from. // - cColorTable - The number of elements in ColorTable // Return value: // The index in ColorTable of the nearest match to Color. WORD Settings::FindNearestTableIndex(const COLORREF Color) const { return ::FindNearestTableIndex(Color, _ColorTable, ARRAYSIZE(_ColorTable)); } 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; } TextAttribute Settings::GetDefaultAttributes() const noexcept { auto attrs = TextAttribute{ _wFillAttribute }; if (_DefaultForeground != INVALID_COLOR) { attrs.SetDefaultForeground(); } if (_DefaultBackground != INVALID_COLOR) { attrs.SetDefaultBackground(); } return attrs; } bool Settings::IsTerminalScrolling() const noexcept { return _TerminalScrolling; } void Settings::SetTerminalScrolling(const bool terminalScrollingEnabled) noexcept { _TerminalScrolling = terminalScrollingEnabled; } // Routine Description: // - Determines whether our primary renderer should be DirectX or GDI. // - This is based on user preference and velocity hold back state. // Return Value: // - True means use DirectX renderer. False means use GDI renderer. bool Settings::GetUseDx() const noexcept { return _fUseDx; } // Method Description: // - Return the default foreground color of the console. If the settings are // configured to have a default foreground color (separate from the color // table), this will return that value. Otherwise it will return the value // from the colortable corresponding to our default legacy attributes. // Arguments: // - // Return Value: // - the default foreground color of the console. COLORREF Settings::CalculateDefaultForeground() const noexcept { const auto fg = GetDefaultForegroundColor(); return fg != INVALID_COLOR ? fg : ForegroundColor(GetFillAttribute(), GetColorTable(), GetColorTableSize()); } // Method Description: // - Return the default background color of the console. If the settings are // configured to have a default background color (separate from the color // table), this will return that value. Otherwise it will return the value // from the colortable corresponding to our default legacy attributes. // Arguments: // - // Return Value: // - the default background color of the console. COLORREF Settings::CalculateDefaultBackground() const noexcept { const auto bg = GetDefaultBackgroundColor(); return bg != INVALID_COLOR ? bg : BackgroundColor(GetFillAttribute(), GetColorTable(), GetColorTableSize()); } // Method Description: // - Get the foreground color of a particular text attribute, using our color // table, and our configured default attributes. // Arguments: // - attr: the TextAttribute to retrieve the foreground color of. // Return Value: // - The color value of the attribute's foreground TextColor. COLORREF Settings::LookupForegroundColor(const TextAttribute& attr) const noexcept { const auto tableView = std::basic_string_view(&GetColorTable()[0], GetColorTableSize()); if (_fScreenReversed) { return attr.CalculateRgbBackground(tableView, CalculateDefaultForeground(), CalculateDefaultBackground()); } else { return attr.CalculateRgbForeground(tableView, CalculateDefaultForeground(), CalculateDefaultBackground()); } } // Method Description: // - Get the background color of a particular text attribute, using our color // table, and our configured default attributes. // Arguments: // - attr: the TextAttribute to retrieve the background color of. // Return Value: // - The color value of the attribute's background TextColor. COLORREF Settings::LookupBackgroundColor(const TextAttribute& attr) const noexcept { const auto tableView = std::basic_string_view(&GetColorTable()[0], GetColorTableSize()); if (_fScreenReversed) { return attr.CalculateRgbForeground(tableView, CalculateDefaultForeground(), CalculateDefaultBackground()); } else { return attr.CalculateRgbBackground(tableView, CalculateDefaultForeground(), CalculateDefaultBackground()); } } bool Settings::GetCopyColor() const noexcept { return _fCopyColor; }