2019-05-03 00:29:04 +02:00
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
# include "pch.h"
# include "TerminalDispatch.hpp"
using namespace : : Microsoft : : Terminal : : Core ;
using namespace : : Microsoft : : Console : : VirtualTerminal ;
2019-06-11 22:27:09 +02:00
// clang-format off
2019-05-03 00:29:04 +02:00
const BYTE RED_ATTR = 0x01 ;
const BYTE GREEN_ATTR = 0x02 ;
const BYTE BLUE_ATTR = 0x04 ;
const BYTE BRIGHT_ATTR = 0x08 ;
const BYTE DARK_BLACK = 0 ;
const BYTE DARK_RED = RED_ATTR ;
const BYTE DARK_GREEN = GREEN_ATTR ;
const BYTE DARK_YELLOW = RED_ATTR | GREEN_ATTR ;
const BYTE DARK_BLUE = BLUE_ATTR ;
const BYTE DARK_MAGENTA = RED_ATTR | BLUE_ATTR ;
const BYTE DARK_CYAN = GREEN_ATTR | BLUE_ATTR ;
const BYTE DARK_WHITE = RED_ATTR | GREEN_ATTR | BLUE_ATTR ;
const BYTE BRIGHT_BLACK = BRIGHT_ATTR ;
const BYTE BRIGHT_RED = BRIGHT_ATTR | RED_ATTR ;
const BYTE BRIGHT_GREEN = BRIGHT_ATTR | GREEN_ATTR ;
const BYTE BRIGHT_YELLOW = BRIGHT_ATTR | RED_ATTR | GREEN_ATTR ;
const BYTE BRIGHT_BLUE = BRIGHT_ATTR | BLUE_ATTR ;
const BYTE BRIGHT_MAGENTA = BRIGHT_ATTR | RED_ATTR | BLUE_ATTR ;
const BYTE BRIGHT_CYAN = BRIGHT_ATTR | GREEN_ATTR | BLUE_ATTR ;
const BYTE BRIGHT_WHITE = BRIGHT_ATTR | RED_ATTR | GREEN_ATTR | BLUE_ATTR ;
2019-06-11 22:27:09 +02:00
// clang-format on
2019-05-03 00:29:04 +02:00
// Routine Description:
// Returns true if the GraphicsOption represents an extended color option.
// These are followed by up to 4 more values which compose the entire option.
// Return Value:
// - true if the opt is the indicator for an extended color sequence, false otherwise.
bool TerminalDispatch : : s_IsRgbColorOption ( const DispatchTypes : : GraphicsOptions opt ) noexcept
{
return opt = = DispatchTypes : : GraphicsOptions : : ForegroundExtended | |
opt = = DispatchTypes : : GraphicsOptions : : BackgroundExtended ;
}
// Routine Description:
// Returns true if the GraphicsOption represents an extended color option.
// These are followed by up to 4 more values which compose the entire option.
// Return Value:
// - true if the opt is the indicator for an extended color sequence, false otherwise.
bool TerminalDispatch : : s_IsBoldColorOption ( const DispatchTypes : : GraphicsOptions opt ) noexcept
{
return opt = = DispatchTypes : : GraphicsOptions : : BoldBright | |
opt = = DispatchTypes : : GraphicsOptions : : UnBold ;
}
// Function Description:
// - checks if this graphics option should set either the console's FG or BG to
//the default attributes.
// Return Value:
// - true if the opt sets either/or attribute to the defaults, false otherwise.
bool TerminalDispatch : : s_IsDefaultColorOption ( const DispatchTypes : : GraphicsOptions opt ) noexcept
{
return opt = = DispatchTypes : : GraphicsOptions : : Off | |
opt = = DispatchTypes : : GraphicsOptions : : ForegroundDefault | |
opt = = DispatchTypes : : GraphicsOptions : : BackgroundDefault ;
}
// Routine Description:
// - Helper to parse extended graphics options, which start with 38 (FG) or 48 (BG)
// These options are followed by either a 2 (RGB) or 5 (xterm index)
// RGB sequences then take 3 MORE params to designate the R, G, B parts of the color
// Xterm index will use the param that follows to use a color from the preset 256 color xterm color table.
// Arguments:
// - rgOptions - An array of options that will be used to generate the RGB color
// - cOptions - The count of options
// - pcOptionsConsumed - a pointer to place the number of options we consumed parsing this option.
// Return Value:
// Returns true if we successfully parsed an extended color option from the options array.
// - This corresponds to the following number of options consumed (pcOptionsConsumed):
// 1 - false, not enough options to parse.
// 2 - false, not enough options to parse.
// 3 - true, parsed an xterm index to a color
// 5 - true, parsed an RGB color.
bool TerminalDispatch : : _SetRgbColorsHelper ( _In_reads_ ( cOptions ) const DispatchTypes : : GraphicsOptions * const rgOptions ,
2019-06-11 22:27:09 +02:00
const size_t cOptions ,
_Out_ size_t * const pcOptionsConsumed )
2019-05-03 00:29:04 +02:00
{
COLORREF color = 0 ;
bool isForeground = false ;
bool fSuccess = false ;
* pcOptionsConsumed = 1 ;
if ( cOptions > = 2 & & s_IsRgbColorOption ( rgOptions [ 0 ] ) )
{
* pcOptionsConsumed = 2 ;
DispatchTypes : : GraphicsOptions extendedOpt = rgOptions [ 0 ] ;
DispatchTypes : : GraphicsOptions typeOpt = rgOptions [ 1 ] ;
if ( extendedOpt = = DispatchTypes : : GraphicsOptions : : ForegroundExtended )
{
isForeground = true ;
}
else if ( extendedOpt = = DispatchTypes : : GraphicsOptions : : BackgroundExtended )
{
isForeground = false ;
}
if ( typeOpt = = DispatchTypes : : GraphicsOptions : : RGBColor & & cOptions > = 5 )
{
* pcOptionsConsumed = 5 ;
// ensure that each value fits in a byte
2019-06-11 22:27:09 +02:00
unsigned int red = rgOptions [ 2 ] > 255 ? 255 : rgOptions [ 2 ] ;
unsigned int green = rgOptions [ 3 ] > 255 ? 255 : rgOptions [ 3 ] ;
unsigned int blue = rgOptions [ 4 ] > 255 ? 255 : rgOptions [ 4 ] ;
2019-05-03 00:29:04 +02:00
color = RGB ( red , green , blue ) ;
fSuccess = _terminalApi . SetTextRgbColor ( color , isForeground ) ;
}
else if ( typeOpt = = DispatchTypes : : GraphicsOptions : : Xterm256Index & & cOptions > = 3 )
{
* pcOptionsConsumed = 3 ;
if ( rgOptions [ 2 ] < = 255 ) // ensure that the provided index is on the table
{
unsigned int tableIndex = rgOptions [ 2 ] ;
fSuccess = isForeground ?
2019-06-11 22:27:09 +02:00
_terminalApi . SetTextForegroundIndex ( ( BYTE ) tableIndex ) :
_terminalApi . SetTextBackgroundIndex ( ( BYTE ) tableIndex ) ;
2019-05-03 00:29:04 +02:00
}
}
}
return fSuccess ;
}
bool TerminalDispatch : : _SetBoldColorHelper ( const DispatchTypes : : GraphicsOptions option )
{
const bool bold = ( option = = DispatchTypes : : GraphicsOptions : : BoldBright ) ;
return _terminalApi . BoldText ( bold ) ;
}
bool TerminalDispatch : : _SetDefaultColorHelper ( const DispatchTypes : : GraphicsOptions option )
{
const bool fg = option = = DispatchTypes : : GraphicsOptions : : Off | | option = = DispatchTypes : : GraphicsOptions : : ForegroundDefault ;
const bool bg = option = = DispatchTypes : : GraphicsOptions : : Off | | option = = DispatchTypes : : GraphicsOptions : : BackgroundDefault ;
bool success = _terminalApi . SetTextToDefaults ( fg , bg ) ;
if ( success & & fg & & bg )
{
// If we're resetting both the FG & BG, also reset the meta attributes (underline)
// as well as the boldness
success = _terminalApi . UnderlineText ( false ) & &
_terminalApi . ReverseText ( false ) & &
_terminalApi . BoldText ( false ) ;
}
return success ;
}
// Routine Description:
// - Helper to apply the actual flags to each text attributes field.
// - Placed as a helper so it can be recursive/re-entrant for some of the convenience flag methods that perform similar/multiple operations in one command.
// Arguments:
// - opt - Graphics option sent to us by the parser/requestor.
// - pAttr - Pointer to the font attribute field to adjust
// Return Value:
// - <none>
void TerminalDispatch : : _SetGraphicsOptionHelper ( const DispatchTypes : : GraphicsOptions opt )
{
switch ( opt )
{
case DispatchTypes : : GraphicsOptions : : Off :
FAIL_FAST_MSG ( " GraphicsOptions::Off should be handled by _SetDefaultColorHelper " ) ;
break ;
// MSFT:16398982 - These two are now handled by _SetBoldColorHelper
// case DispatchTypes::GraphicsOptions::BoldBright:
// case DispatchTypes::GraphicsOptions::UnBold:
case DispatchTypes : : GraphicsOptions : : Negative :
_terminalApi . ReverseText ( true ) ;
break ;
case DispatchTypes : : GraphicsOptions : : Underline :
_terminalApi . UnderlineText ( true ) ;
break ;
case DispatchTypes : : GraphicsOptions : : Positive :
_terminalApi . ReverseText ( false ) ;
break ;
case DispatchTypes : : GraphicsOptions : : NoUnderline :
_terminalApi . UnderlineText ( false ) ;
break ;
case DispatchTypes : : GraphicsOptions : : ForegroundBlack :
_terminalApi . SetTextForegroundIndex ( DARK_BLACK ) ;
break ;
case DispatchTypes : : GraphicsOptions : : ForegroundBlue :
_terminalApi . SetTextForegroundIndex ( DARK_BLUE ) ;
break ;
case DispatchTypes : : GraphicsOptions : : ForegroundGreen :
_terminalApi . SetTextForegroundIndex ( DARK_GREEN ) ;
break ;
case DispatchTypes : : GraphicsOptions : : ForegroundCyan :
_terminalApi . SetTextForegroundIndex ( DARK_CYAN ) ;
break ;
case DispatchTypes : : GraphicsOptions : : ForegroundRed :
_terminalApi . SetTextForegroundIndex ( DARK_RED ) ;
break ;
case DispatchTypes : : GraphicsOptions : : ForegroundMagenta :
_terminalApi . SetTextForegroundIndex ( DARK_MAGENTA ) ;
break ;
case DispatchTypes : : GraphicsOptions : : ForegroundYellow :
_terminalApi . SetTextForegroundIndex ( DARK_YELLOW ) ;
break ;
case DispatchTypes : : GraphicsOptions : : ForegroundWhite :
_terminalApi . SetTextForegroundIndex ( DARK_WHITE ) ;
break ;
case DispatchTypes : : GraphicsOptions : : ForegroundDefault :
FAIL_FAST_MSG ( " GraphicsOptions::ForegroundDefault should be handled by _SetDefaultColorHelper " ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BackgroundBlack :
_terminalApi . SetTextBackgroundIndex ( DARK_BLACK ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BackgroundBlue :
_terminalApi . SetTextBackgroundIndex ( DARK_BLUE ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BackgroundGreen :
_terminalApi . SetTextBackgroundIndex ( DARK_GREEN ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BackgroundCyan :
_terminalApi . SetTextBackgroundIndex ( DARK_CYAN ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BackgroundRed :
_terminalApi . SetTextBackgroundIndex ( DARK_RED ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BackgroundMagenta :
_terminalApi . SetTextBackgroundIndex ( DARK_MAGENTA ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BackgroundYellow :
_terminalApi . SetTextBackgroundIndex ( DARK_YELLOW ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BackgroundWhite :
_terminalApi . SetTextBackgroundIndex ( DARK_WHITE ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BackgroundDefault :
FAIL_FAST_MSG ( " GraphicsOptions::BackgroundDefault should be handled by _SetDefaultColorHelper " ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BrightForegroundBlack :
_terminalApi . SetTextForegroundIndex ( BRIGHT_BLACK ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BrightForegroundBlue :
_terminalApi . SetTextForegroundIndex ( BRIGHT_BLUE ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BrightForegroundGreen :
_terminalApi . SetTextForegroundIndex ( BRIGHT_GREEN ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BrightForegroundCyan :
_terminalApi . SetTextForegroundIndex ( BRIGHT_CYAN ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BrightForegroundRed :
_terminalApi . SetTextForegroundIndex ( BRIGHT_RED ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BrightForegroundMagenta :
_terminalApi . SetTextForegroundIndex ( BRIGHT_MAGENTA ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BrightForegroundYellow :
_terminalApi . SetTextForegroundIndex ( BRIGHT_YELLOW ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BrightForegroundWhite :
_terminalApi . SetTextForegroundIndex ( BRIGHT_WHITE ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BrightBackgroundBlack :
_terminalApi . SetTextBackgroundIndex ( BRIGHT_BLACK ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BrightBackgroundBlue :
_terminalApi . SetTextBackgroundIndex ( BRIGHT_BLUE ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BrightBackgroundGreen :
_terminalApi . SetTextBackgroundIndex ( BRIGHT_GREEN ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BrightBackgroundCyan :
_terminalApi . SetTextBackgroundIndex ( BRIGHT_CYAN ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BrightBackgroundRed :
_terminalApi . SetTextBackgroundIndex ( BRIGHT_RED ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BrightBackgroundMagenta :
_terminalApi . SetTextBackgroundIndex ( BRIGHT_MAGENTA ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BrightBackgroundYellow :
_terminalApi . SetTextBackgroundIndex ( BRIGHT_YELLOW ) ;
break ;
case DispatchTypes : : GraphicsOptions : : BrightBackgroundWhite :
_terminalApi . SetTextBackgroundIndex ( BRIGHT_WHITE ) ;
break ;
}
}
bool TerminalDispatch : : SetGraphicsRendition ( const DispatchTypes : : GraphicsOptions * const rgOptions ,
const size_t cOptions )
{
bool fSuccess = false ;
// Run through the graphics options and apply them
for ( size_t i = 0 ; i < cOptions ; i + + )
{
DispatchTypes : : GraphicsOptions opt = rgOptions [ i ] ;
if ( s_IsDefaultColorOption ( opt ) )
{
fSuccess = _SetDefaultColorHelper ( opt ) ;
}
else if ( s_IsBoldColorOption ( opt ) )
{
fSuccess = _SetBoldColorHelper ( rgOptions [ i ] ) ;
}
else if ( s_IsRgbColorOption ( opt ) )
{
size_t cOptionsConsumed = 0 ;
// _SetRgbColorsHelper will call the appropriate ConApi function
2019-06-11 22:27:09 +02:00
fSuccess = _SetRgbColorsHelper ( & ( rgOptions [ i ] ) , cOptions - i , & cOptionsConsumed ) ;
2019-05-03 00:29:04 +02:00
i + = ( cOptionsConsumed - 1 ) ; // cOptionsConsumed includes the opt we're currently on.
}
else
{
_SetGraphicsOptionHelper ( opt ) ;
// Make sure we un-bold
if ( fSuccess & & opt = = DispatchTypes : : GraphicsOptions : : Off )
{
fSuccess = _SetBoldColorHelper ( opt ) ;
}
}
}
return fSuccess ;
}