text: // 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
  
  #define DEFAULT_NUMBER_OF_COMMANDS 25
  #define 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_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),
      _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.
      // 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);
  
      ZeroMemory((void*)&_LaunchFaceName, sizeof(_LaunchFaceName));
  
      _CursorColor = Cursor::s_InvertCursorColor;
      _CursorType = CursorType::Legacy;
  
      gsl::span<COLORREF> tableView = { _ColorTable, gsl::narrow<ptrdiff_t>(COLOR_TABLE_SIZE) };
      gsl::span<COLORREF> xtermTableView = { _XtermColorTable, gsl::narrow<ptrdiff_t>(XTERM_COLOR_TABLE_SIZE) };
      ::Microsoft::Console::Utils::Initialize256ColorTable(xtermTableView);
      ::Microsoft::Console::Utils::InitializeCampbellColorTable(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;
  
      gsl::span<COLORREF> tableView = { _ColorTable, gsl::narrow<ptrdiff_t>(COLOR_TABLE_SIZE) };
      ::Microsoft::Console::Utils::InitializeCampbellColorTable(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;
      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<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;
      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<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));
  
      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::GetFilterOnPaste() const
  {
      return _fFilterOnPaste;
  }
  void Settings::SetFilterOnPaste(const bool fFilterOnPaste)
  {
      _fFilterOnPaste = fFilterOnPaste;
  }
  
  const WCHAR* const Settings::GetLaunchFaceName() const
  {
      return _LaunchFaceName;
  }
  void Settings::SetLaunchFaceName(_In_ PCWSTR const LaunchFaceName, const size_t cchLength)
  {
      StringCchCopyW(_LaunchFaceName, cchLength, 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 defualt.
      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(_In_ PCWSTR const pcszFaceName, const size_t cchLength)
  {
      StringCchCopyW(_FaceName, cchLength, pcszFaceName);
  }
  
  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<size_t>(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<BYTE>((_wFillAttribute & FG_ATTRS));
      BYTE bgIndex = static_cast<BYTE>((_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<BYTE>(FindNearestTableIndex(rgbForeground));
  
          const COLORREF rgbBackground = LookupBackgroundColor(attributes);
          bgIndex = attributes.BackgroundIsDefault() ?
                        bgIndex :
                        static_cast<BYTE>(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:
  // - <none>
  // 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:
  // - <none>
  // 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 foregroud 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<COLORREF>(&GetColorTable()[0], GetColorTableSize());
      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<COLORREF>(&GetColorTable()[0], GetColorTableSize());
      return attr.CalculateRgbBackground(tableView, CalculateDefaultForeground(), CalculateDefaultBackground());
  }
  
  bool Settings::GetCopyColor() const noexcept
  {
      return _fCopyColor;
  }
  