Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal. We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags. Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however. ## References See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1. ## PR Checklist * [x] Closes #2554 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated <hr> * store text with extended attributes too * Plumb attributes through all the renderers * parse extended attrs, though we're not renderering them right * Render these states correctly * Add a very extensive test * Cleanup for PR * a block of PR feedback * add 512 test cases * Fix the build * Fix @carlos-zamora's suggestions * @miniksa's PR feedback
This commit is contained in:
parent
53c81a08f8
commit
dec5c11e19
|
@ -44,7 +44,7 @@ COLORREF TextAttribute::CalculateRgbBackground(std::basic_string_view<COLORREF>
|
|||
COLORREF TextAttribute::_GetRgbForeground(std::basic_string_view<COLORREF> colorTable,
|
||||
COLORREF defaultColor) const noexcept
|
||||
{
|
||||
return _foreground.GetColor(colorTable, defaultColor, _isBold);
|
||||
return _foreground.GetColor(colorTable, defaultColor, IsBold());
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -155,11 +155,6 @@ void TextAttribute::SetColor(const COLORREF rgbColor, const bool fIsForeground)
|
|||
}
|
||||
}
|
||||
|
||||
bool TextAttribute::IsBold() const noexcept
|
||||
{
|
||||
return _isBold;
|
||||
}
|
||||
|
||||
bool TextAttribute::_IsReverseVideo() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_wAttrLegacy, COMMON_LVB_REVERSE_VIDEO);
|
||||
|
@ -215,6 +210,11 @@ void TextAttribute::Debolden() noexcept
|
|||
_SetBoldness(false);
|
||||
}
|
||||
|
||||
void TextAttribute::SetExtendedAttributes(const ExtendedAttributes attrs) noexcept
|
||||
{
|
||||
_extendedAttrs = attrs;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - swaps foreground and background color
|
||||
void TextAttribute::Invert() noexcept
|
||||
|
@ -224,7 +224,7 @@ void TextAttribute::Invert() noexcept
|
|||
|
||||
void TextAttribute::_SetBoldness(const bool isBold) noexcept
|
||||
{
|
||||
_isBold = isBold;
|
||||
WI_UpdateFlag(_extendedAttrs, ExtendedAttributes::Bold, isBold);
|
||||
}
|
||||
|
||||
void TextAttribute::SetDefaultForeground() noexcept
|
||||
|
|
|
@ -27,6 +27,8 @@ Revision History:
|
|||
#include "WexTestClass.h"
|
||||
#endif
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
class TextAttribute final
|
||||
{
|
||||
public:
|
||||
|
@ -34,7 +36,7 @@ public:
|
|||
_wAttrLegacy{ 0 },
|
||||
_foreground{},
|
||||
_background{},
|
||||
_isBold{ false }
|
||||
_extendedAttrs{ ExtendedAttributes::Normal }
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -42,7 +44,7 @@ public:
|
|||
_wAttrLegacy{ gsl::narrow_cast<WORD>(wLegacyAttr & META_ATTRS) },
|
||||
_foreground{ gsl::narrow_cast<BYTE>(wLegacyAttr & FG_ATTRS) },
|
||||
_background{ gsl::narrow_cast<BYTE>((wLegacyAttr & BG_ATTRS) >> 4) },
|
||||
_isBold{ false }
|
||||
_extendedAttrs{ ExtendedAttributes::Normal }
|
||||
{
|
||||
// If we're given lead/trailing byte information with the legacy color, strip it.
|
||||
WI_ClearAllFlags(_wAttrLegacy, COMMON_LVB_SBCSDBCS);
|
||||
|
@ -53,7 +55,7 @@ public:
|
|||
_wAttrLegacy{ 0 },
|
||||
_foreground{ rgbForeground },
|
||||
_background{ rgbBackground },
|
||||
_isBold{ false }
|
||||
_extendedAttrs{ ExtendedAttributes::Normal }
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -62,7 +64,7 @@ public:
|
|||
const BYTE fg = (_foreground.GetIndex() & FG_ATTRS);
|
||||
const BYTE bg = (_background.GetIndex() << 4) & BG_ATTRS;
|
||||
const WORD meta = (_wAttrLegacy & META_ATTRS);
|
||||
return (fg | bg | meta) | (_isBold ? FOREGROUND_INTENSITY : 0);
|
||||
return (fg | bg | meta) | (IsBold() ? FOREGROUND_INTENSITY : 0);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -85,7 +87,7 @@ public:
|
|||
const BYTE fg = (fgIndex & FG_ATTRS);
|
||||
const BYTE bg = (bgIndex << 4) & BG_ATTRS;
|
||||
const WORD meta = (_wAttrLegacy & META_ATTRS);
|
||||
return (fg | bg | meta) | (_isBold ? FOREGROUND_INTENSITY : 0);
|
||||
return (fg | bg | meta) | (IsBold() ? FOREGROUND_INTENSITY : 0);
|
||||
}
|
||||
|
||||
COLORREF CalculateRgbForeground(std::basic_string_view<COLORREF> colorTable,
|
||||
|
@ -131,7 +133,18 @@ public:
|
|||
friend constexpr bool operator!=(const WORD& legacyAttr, const TextAttribute& attr) noexcept;
|
||||
|
||||
bool IsLegacy() const noexcept;
|
||||
bool IsBold() const noexcept;
|
||||
|
||||
constexpr bool IsBold() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_extendedAttrs, ExtendedAttributes::Bold);
|
||||
}
|
||||
|
||||
constexpr ExtendedAttributes GetExtendedAttributes() const noexcept
|
||||
{
|
||||
return _extendedAttrs;
|
||||
}
|
||||
|
||||
void SetExtendedAttributes(const ExtendedAttributes attrs) noexcept;
|
||||
|
||||
void SetForeground(const COLORREF rgbForeground) noexcept;
|
||||
void SetBackground(const COLORREF rgbBackground) noexcept;
|
||||
|
@ -159,7 +172,7 @@ private:
|
|||
WORD _wAttrLegacy;
|
||||
TextColor _foreground;
|
||||
TextColor _background;
|
||||
bool _isBold;
|
||||
ExtendedAttributes _extendedAttrs;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class TextBufferTests;
|
||||
|
@ -169,6 +182,13 @@ private:
|
|||
#endif
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
// 2 for _wAttrLegacy
|
||||
// 4 for _foreground
|
||||
// 4 for _background
|
||||
// 1 for _extendedAttrs
|
||||
static_assert(sizeof(TextAttribute) <= 11 * sizeof(BYTE), "We should only need 11B for an entire TextColor. Any more than that is just waste");
|
||||
|
||||
enum class TextAttributeBehavior
|
||||
{
|
||||
Stored, // use contained text attribute
|
||||
|
@ -181,7 +201,7 @@ constexpr bool operator==(const TextAttribute& a, const TextAttribute& b) noexce
|
|||
return a._wAttrLegacy == b._wAttrLegacy &&
|
||||
a._foreground == b._foreground &&
|
||||
a._background == b._background &&
|
||||
a._isBold == b._isBold;
|
||||
a._extendedAttrs == b._extendedAttrs;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const TextAttribute& a, const TextAttribute& b) noexcept
|
||||
|
|
|
@ -103,7 +103,7 @@ bool TerminalDispatch::_SetRgbColorsHelper(_In_reads_(cOptions) const DispatchTy
|
|||
isForeground = false;
|
||||
}
|
||||
|
||||
if (typeOpt == DispatchTypes::GraphicsOptions::RGBColor && cOptions >= 5)
|
||||
if (typeOpt == DispatchTypes::GraphicsOptions::RGBColorOrFaint && cOptions >= 5)
|
||||
{
|
||||
*pcOptionsConsumed = 5;
|
||||
// ensure that each value fits in a byte
|
||||
|
@ -115,7 +115,7 @@ bool TerminalDispatch::_SetRgbColorsHelper(_In_reads_(cOptions) const DispatchTy
|
|||
|
||||
fSuccess = _terminalApi.SetTextRgbColor(color, isForeground);
|
||||
}
|
||||
else if (typeOpt == DispatchTypes::GraphicsOptions::Xterm256Index && cOptions >= 3)
|
||||
else if (typeOpt == DispatchTypes::GraphicsOptions::BlinkOrXterm256Index && cOptions >= 3)
|
||||
{
|
||||
*pcOptionsConsumed = 3;
|
||||
if (rgOptions[2] <= 255) // ensure that the provided index is on the table
|
||||
|
|
|
@ -981,6 +981,39 @@ void DoSrvPrivateBoldText(SCREEN_INFORMATION& screenInfo, const bool bolded)
|
|||
buffer.SetAttributes(attrs);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Retrieves the active ExtendedAttributes (italic, underline, etc.) of the
|
||||
// given screen buffer. Text written to this buffer will be written with these
|
||||
// attributes.
|
||||
// Arguments:
|
||||
// - screenInfo: The buffer to get the extended attrs from.
|
||||
// Return Value:
|
||||
// - the currently active ExtendedAttributes.
|
||||
ExtendedAttributes DoSrvPrivateGetExtendedTextAttributes(SCREEN_INFORMATION& screenInfo)
|
||||
{
|
||||
auto& buffer = screenInfo.GetActiveBuffer();
|
||||
auto attrs = buffer.GetAttributes();
|
||||
return attrs.GetExtendedAttributes();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets the active ExtendedAttributes (italic, underline, etc.) of the given
|
||||
// screen buffer. Text written to this buffer will be written with these
|
||||
// attributes.
|
||||
// Arguments:
|
||||
// - screenInfo: The buffer to set the extended attrs for.
|
||||
// - extendedAttrs: The new ExtendedAttributes to use
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void DoSrvPrivateSetExtendedTextAttributes(SCREEN_INFORMATION& screenInfo,
|
||||
const ExtendedAttributes extendedAttrs)
|
||||
{
|
||||
auto& buffer = screenInfo.GetActiveBuffer();
|
||||
auto attrs = buffer.GetAttributes();
|
||||
attrs.SetExtendedAttributes(extendedAttrs);
|
||||
buffer.SetAttributes(attrs);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Sets the codepage used for translating text when calling A versions of functions affecting the output buffer.
|
||||
// Arguments:
|
||||
|
|
|
@ -60,6 +60,9 @@ void DoSrvPrivateSetConsoleRGBTextAttribute(SCREEN_INFORMATION& screenInfo,
|
|||
|
||||
void DoSrvPrivateBoldText(SCREEN_INFORMATION& screenInfo, const bool bolded);
|
||||
|
||||
ExtendedAttributes DoSrvPrivateGetExtendedTextAttributes(SCREEN_INFORMATION& screenInfo);
|
||||
void DoSrvPrivateSetExtendedTextAttributes(SCREEN_INFORMATION& screenInfo, const ExtendedAttributes attrs);
|
||||
|
||||
[[nodiscard]] NTSTATUS DoSrvPrivateEraseAll(SCREEN_INFORMATION& screenInfo);
|
||||
|
||||
void DoSrvSetCursorStyle(SCREEN_INFORMATION& screenInfo,
|
||||
|
|
|
@ -273,6 +273,32 @@ BOOL ConhostInternalGetSet::PrivateBoldText(const bool bolded)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Retrieves the currently active ExtendedAttributes. See also
|
||||
// DoSrvPrivateGetExtendedTextAttributes
|
||||
// Arguments:
|
||||
// - pAttrs: Recieves the ExtendedAttributes value.
|
||||
// Return Value:
|
||||
// - TRUE if successful (see DoSrvPrivateGetExtendedTextAttributes). FALSE otherwise.
|
||||
BOOL ConhostInternalGetSet::PrivateGetExtendedTextAttributes(ExtendedAttributes* const pAttrs)
|
||||
{
|
||||
*pAttrs = DoSrvPrivateGetExtendedTextAttributes(_io.GetActiveOutputBuffer());
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets the active ExtendedAttributes of the active screen buffer. Text
|
||||
// written to this buffer will be written with these attributes.
|
||||
// Arguments:
|
||||
// - extendedAttrs: The new ExtendedAttributes to use
|
||||
// Return Value:
|
||||
// - TRUE if successful (see DoSrvPrivateSetExtendedTextAttributes). FALSE otherwise.
|
||||
BOOL ConhostInternalGetSet::PrivateSetExtendedTextAttributes(const ExtendedAttributes attrs)
|
||||
{
|
||||
DoSrvPrivateSetExtendedTextAttributes(_io.GetActiveOutputBuffer(), attrs);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Connects the WriteConsoleInput API call directly into our Driver Message servicing call inside Conhost.exe
|
||||
// Arguments:
|
||||
|
|
|
@ -88,6 +88,8 @@ public:
|
|||
const bool fIsForeground) override;
|
||||
|
||||
BOOL PrivateBoldText(const bool bolded) override;
|
||||
BOOL PrivateGetExtendedTextAttributes(ExtendedAttributes* const pAttrs) override;
|
||||
BOOL PrivateSetExtendedTextAttributes(const ExtendedAttributes attrs) override;
|
||||
|
||||
BOOL PrivateWriteConsoleInputW(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& events,
|
||||
_Out_ size_t& eventsWritten) override;
|
||||
|
|
|
@ -187,6 +187,9 @@ class ScreenBufferTests
|
|||
|
||||
TEST_METHOD(InitializeTabStopsInVTMode);
|
||||
|
||||
TEST_METHOD(TestExtendedTextAttributes);
|
||||
TEST_METHOD(TestExtendedTextAttributesWithColors);
|
||||
|
||||
TEST_METHOD(CursorUpDownAcrossMargins);
|
||||
TEST_METHOD(CursorUpDownOutsideMargins);
|
||||
TEST_METHOD(CursorUpDownExactlyAtMargins);
|
||||
|
@ -4546,6 +4549,336 @@ void ScreenBufferTests::InitializeTabStopsInVTMode()
|
|||
VERIFY_IS_TRUE(gci.GetActiveOutputBuffer().AreTabsSet());
|
||||
}
|
||||
|
||||
void ScreenBufferTests::TestExtendedTextAttributes()
|
||||
{
|
||||
// This is a test for microsoft/terminal#2554. Refer to that issue for more
|
||||
// context.
|
||||
|
||||
// We're going to set every possible combination of extended attributes via
|
||||
// VT, then disable them, and make sure that they are all always represented
|
||||
// internally correctly.
|
||||
|
||||
// Run this test for each and every possible combination of states.
|
||||
BEGIN_TEST_METHOD_PROPERTIES()
|
||||
TEST_METHOD_PROPERTY(L"Data:bold", L"{false, true}")
|
||||
TEST_METHOD_PROPERTY(L"Data:italics", L"{false, true}")
|
||||
TEST_METHOD_PROPERTY(L"Data:blink", L"{false, true}")
|
||||
TEST_METHOD_PROPERTY(L"Data:invisible", L"{false, true}")
|
||||
TEST_METHOD_PROPERTY(L"Data:crossedOut", L"{false, true}")
|
||||
END_TEST_METHOD_PROPERTIES()
|
||||
|
||||
bool bold, italics, blink, invisible, crossedOut;
|
||||
VERIFY_SUCCEEDED(TestData::TryGetValue(L"bold", bold));
|
||||
VERIFY_SUCCEEDED(TestData::TryGetValue(L"italics", italics));
|
||||
VERIFY_SUCCEEDED(TestData::TryGetValue(L"blink", blink));
|
||||
VERIFY_SUCCEEDED(TestData::TryGetValue(L"invisible", invisible));
|
||||
VERIFY_SUCCEEDED(TestData::TryGetValue(L"crossedOut", crossedOut));
|
||||
|
||||
auto& g = ServiceLocator::LocateGlobals();
|
||||
auto& gci = g.getConsoleInformation();
|
||||
auto& si = gci.GetActiveOutputBuffer();
|
||||
auto& tbi = si.GetTextBuffer();
|
||||
auto& stateMachine = si.GetStateMachine();
|
||||
auto& cursor = tbi.GetCursor();
|
||||
|
||||
ExtendedAttributes expectedAttrs{ ExtendedAttributes::Normal };
|
||||
std::wstring vtSeq = L"";
|
||||
|
||||
// Collect up a VT sequence to set the state given the method properties
|
||||
if (bold)
|
||||
{
|
||||
WI_SetFlag(expectedAttrs, ExtendedAttributes::Bold);
|
||||
vtSeq += L"\x1b[1m";
|
||||
}
|
||||
if (italics)
|
||||
{
|
||||
WI_SetFlag(expectedAttrs, ExtendedAttributes::Italics);
|
||||
vtSeq += L"\x1b[3m";
|
||||
}
|
||||
if (blink)
|
||||
{
|
||||
WI_SetFlag(expectedAttrs, ExtendedAttributes::Blinking);
|
||||
vtSeq += L"\x1b[5m";
|
||||
}
|
||||
if (invisible)
|
||||
{
|
||||
WI_SetFlag(expectedAttrs, ExtendedAttributes::Invisible);
|
||||
vtSeq += L"\x1b[8m";
|
||||
}
|
||||
if (crossedOut)
|
||||
{
|
||||
WI_SetFlag(expectedAttrs, ExtendedAttributes::CrossedOut);
|
||||
vtSeq += L"\x1b[9m";
|
||||
}
|
||||
|
||||
// Helper lambda to write a VT sequence, then an "X", then check that the
|
||||
// attributes of the "X" match what we think they should be.
|
||||
auto validate = [&](const ExtendedAttributes expectedAttrs,
|
||||
const std::wstring& vtSequence) {
|
||||
auto cursorPos = cursor.GetPosition();
|
||||
|
||||
// Convert the vtSequence to something printable. Lets not set these
|
||||
// attrs on the test console
|
||||
std::wstring debugString = vtSequence;
|
||||
{
|
||||
size_t start_pos = 0;
|
||||
while ((start_pos = debugString.find(L"\x1b", start_pos)) != std::string::npos)
|
||||
{
|
||||
debugString.replace(start_pos, 1, L"\\x1b");
|
||||
start_pos += 4;
|
||||
}
|
||||
}
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Testing string:\"%s\"", debugString.c_str()));
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Expecting attrs:0x%02x", expectedAttrs));
|
||||
|
||||
stateMachine.ProcessString(vtSequence);
|
||||
stateMachine.ProcessString(L"X");
|
||||
|
||||
auto iter = tbi.GetCellDataAt(cursorPos);
|
||||
auto currentExtendedAttrs = iter->TextAttr().GetExtendedAttributes();
|
||||
VERIFY_ARE_EQUAL(expectedAttrs, currentExtendedAttrs);
|
||||
};
|
||||
|
||||
// Check setting all the states collected above
|
||||
validate(expectedAttrs, vtSeq);
|
||||
|
||||
// One-by-one, turn off each of these states with VT, then check that the
|
||||
// state matched.
|
||||
if (bold)
|
||||
{
|
||||
WI_ClearFlag(expectedAttrs, ExtendedAttributes::Bold);
|
||||
vtSeq = L"\x1b[22m";
|
||||
validate(expectedAttrs, vtSeq);
|
||||
}
|
||||
if (italics)
|
||||
{
|
||||
WI_ClearFlag(expectedAttrs, ExtendedAttributes::Italics);
|
||||
vtSeq = L"\x1b[23m";
|
||||
validate(expectedAttrs, vtSeq);
|
||||
}
|
||||
if (blink)
|
||||
{
|
||||
WI_ClearFlag(expectedAttrs, ExtendedAttributes::Blinking);
|
||||
vtSeq = L"\x1b[25m";
|
||||
validate(expectedAttrs, vtSeq);
|
||||
}
|
||||
if (invisible)
|
||||
{
|
||||
WI_ClearFlag(expectedAttrs, ExtendedAttributes::Invisible);
|
||||
vtSeq = L"\x1b[28m";
|
||||
validate(expectedAttrs, vtSeq);
|
||||
}
|
||||
if (crossedOut)
|
||||
{
|
||||
WI_ClearFlag(expectedAttrs, ExtendedAttributes::CrossedOut);
|
||||
vtSeq = L"\x1b[29m";
|
||||
validate(expectedAttrs, vtSeq);
|
||||
}
|
||||
|
||||
stateMachine.ProcessString(L"\x1b[0m");
|
||||
}
|
||||
|
||||
void ScreenBufferTests::TestExtendedTextAttributesWithColors()
|
||||
{
|
||||
// This is a test for microsoft/terminal#2554. Refer to that issue for more
|
||||
// context.
|
||||
|
||||
// We're going to set every possible combination of extended attributes via
|
||||
// VT, then set assorted colors, then disable extended attrs, then reset
|
||||
// colors, in various ways, and make sure that they are all always
|
||||
// represented internally correctly.
|
||||
|
||||
// Run this test for each and every possible combination of states.
|
||||
BEGIN_TEST_METHOD_PROPERTIES()
|
||||
TEST_METHOD_PROPERTY(L"Data:bold", L"{false, true}")
|
||||
TEST_METHOD_PROPERTY(L"Data:italics", L"{false, true}")
|
||||
TEST_METHOD_PROPERTY(L"Data:blink", L"{false, true}")
|
||||
TEST_METHOD_PROPERTY(L"Data:invisible", L"{false, true}")
|
||||
TEST_METHOD_PROPERTY(L"Data:crossedOut", L"{false, true}")
|
||||
TEST_METHOD_PROPERTY(L"Data:setForegroundType", L"{0, 1, 2, 3}")
|
||||
TEST_METHOD_PROPERTY(L"Data:setBackgroundType", L"{0, 1, 2, 3}")
|
||||
END_TEST_METHOD_PROPERTIES()
|
||||
|
||||
// colorStyle will be used to control whether we use a color from the 16
|
||||
// color table, a color from the 256 color table, or a pure RGB color.
|
||||
const int UseDefault = 0;
|
||||
const int Use16Color = 1;
|
||||
const int Use256Color = 2;
|
||||
const int UseRGBColor = 3;
|
||||
|
||||
bool bold, italics, blink, invisible, crossedOut;
|
||||
VERIFY_SUCCEEDED(TestData::TryGetValue(L"bold", bold));
|
||||
VERIFY_SUCCEEDED(TestData::TryGetValue(L"italics", italics));
|
||||
VERIFY_SUCCEEDED(TestData::TryGetValue(L"blink", blink));
|
||||
VERIFY_SUCCEEDED(TestData::TryGetValue(L"invisible", invisible));
|
||||
VERIFY_SUCCEEDED(TestData::TryGetValue(L"crossedOut", crossedOut));
|
||||
|
||||
int setForegroundType, setBackgroundType;
|
||||
VERIFY_SUCCEEDED(TestData::TryGetValue(L"setForegroundType", setForegroundType), L"controls whether to use the 16 color table, 256 table, or RGB colors");
|
||||
VERIFY_SUCCEEDED(TestData::TryGetValue(L"setBackgroundType", setBackgroundType), L"controls whether to use the 16 color table, 256 table, or RGB colors");
|
||||
|
||||
auto& g = ServiceLocator::LocateGlobals();
|
||||
auto& gci = g.getConsoleInformation();
|
||||
auto& si = gci.GetActiveOutputBuffer();
|
||||
auto& tbi = si.GetTextBuffer();
|
||||
auto& stateMachine = si.GetStateMachine();
|
||||
auto& cursor = tbi.GetCursor();
|
||||
|
||||
TextAttribute expectedAttr{ si.GetAttributes() };
|
||||
ExtendedAttributes expectedExtendedAttrs{ ExtendedAttributes::Normal };
|
||||
std::wstring vtSeq = L"";
|
||||
|
||||
// Collect up a VT sequence to set the state given the method properties
|
||||
if (bold)
|
||||
{
|
||||
WI_SetFlag(expectedExtendedAttrs, ExtendedAttributes::Bold);
|
||||
vtSeq += L"\x1b[1m";
|
||||
}
|
||||
if (italics)
|
||||
{
|
||||
WI_SetFlag(expectedExtendedAttrs, ExtendedAttributes::Italics);
|
||||
vtSeq += L"\x1b[3m";
|
||||
}
|
||||
if (blink)
|
||||
{
|
||||
WI_SetFlag(expectedExtendedAttrs, ExtendedAttributes::Blinking);
|
||||
vtSeq += L"\x1b[5m";
|
||||
}
|
||||
if (invisible)
|
||||
{
|
||||
WI_SetFlag(expectedExtendedAttrs, ExtendedAttributes::Invisible);
|
||||
vtSeq += L"\x1b[8m";
|
||||
}
|
||||
if (crossedOut)
|
||||
{
|
||||
WI_SetFlag(expectedExtendedAttrs, ExtendedAttributes::CrossedOut);
|
||||
vtSeq += L"\x1b[9m";
|
||||
}
|
||||
|
||||
// Prepare the foreground attributes
|
||||
if (setForegroundType == UseDefault)
|
||||
{
|
||||
expectedAttr.SetDefaultForeground();
|
||||
vtSeq += L"\x1b[39m";
|
||||
}
|
||||
else if (setForegroundType == Use16Color)
|
||||
{
|
||||
expectedAttr.SetIndexedAttributes({ static_cast<BYTE>(2) }, std::nullopt);
|
||||
vtSeq += L"\x1b[32m";
|
||||
}
|
||||
else if (setForegroundType == Use256Color)
|
||||
{
|
||||
expectedAttr.SetForeground(gci.GetColorTableEntry(20));
|
||||
vtSeq += L"\x1b[38;5;20m";
|
||||
}
|
||||
else if (setForegroundType == UseRGBColor)
|
||||
{
|
||||
expectedAttr.SetForeground(RGB(1, 2, 3));
|
||||
vtSeq += L"\x1b[38;2;1;2;3m";
|
||||
}
|
||||
|
||||
// Prepare the background attributes
|
||||
if (setBackgroundType == UseDefault)
|
||||
{
|
||||
expectedAttr.SetDefaultBackground();
|
||||
vtSeq += L"\x1b[49m";
|
||||
}
|
||||
else if (setBackgroundType == Use16Color)
|
||||
{
|
||||
expectedAttr.SetIndexedAttributes(std::nullopt, { static_cast<BYTE>(2) });
|
||||
vtSeq += L"\x1b[42m";
|
||||
}
|
||||
else if (setBackgroundType == Use256Color)
|
||||
{
|
||||
expectedAttr.SetBackground(gci.GetColorTableEntry(20));
|
||||
vtSeq += L"\x1b[48;5;20m";
|
||||
}
|
||||
else if (setBackgroundType == UseRGBColor)
|
||||
{
|
||||
expectedAttr.SetBackground(RGB(1, 2, 3));
|
||||
vtSeq += L"\x1b[48;2;1;2;3m";
|
||||
}
|
||||
|
||||
expectedAttr.SetExtendedAttributes(expectedExtendedAttrs);
|
||||
|
||||
// Helper lambda to write a VT sequence, then an "X", then check that the
|
||||
// attributes of the "X" match what we think they should be.
|
||||
auto validate = [&](const TextAttribute attr,
|
||||
const std::wstring& vtSequence) {
|
||||
auto cursorPos = cursor.GetPosition();
|
||||
|
||||
// Convert the vtSequence to something printable. Lets not set these
|
||||
// attrs on the test console
|
||||
std::wstring debugString = vtSequence;
|
||||
{
|
||||
size_t start_pos = 0;
|
||||
while ((start_pos = debugString.find(L"\x1b", start_pos)) != std::string::npos)
|
||||
{
|
||||
debugString.replace(start_pos, 1, L"\\x1b");
|
||||
start_pos += 4;
|
||||
}
|
||||
}
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Testing string:\"%s\"", debugString.c_str()));
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Expecting attrs:0x%02x", VerifyOutputTraits<TextAttribute>::ToString(attr).GetBuffer()));
|
||||
|
||||
stateMachine.ProcessString(vtSequence);
|
||||
stateMachine.ProcessString(L"X");
|
||||
|
||||
auto iter = tbi.GetCellDataAt(cursorPos);
|
||||
const TextAttribute currentAttrs = iter->TextAttr();
|
||||
VERIFY_ARE_EQUAL(attr, currentAttrs);
|
||||
};
|
||||
|
||||
// Check setting all the states collected above
|
||||
validate(expectedAttr, vtSeq);
|
||||
|
||||
// One-by-one, turn off each of these states with VT, then check that the
|
||||
// state matched.
|
||||
if (bold)
|
||||
{
|
||||
WI_ClearFlag(expectedExtendedAttrs, ExtendedAttributes::Bold);
|
||||
expectedAttr.SetExtendedAttributes(expectedExtendedAttrs);
|
||||
vtSeq = L"\x1b[22m";
|
||||
validate(expectedAttr, vtSeq);
|
||||
}
|
||||
if (italics)
|
||||
{
|
||||
WI_ClearFlag(expectedExtendedAttrs, ExtendedAttributes::Italics);
|
||||
expectedAttr.SetExtendedAttributes(expectedExtendedAttrs);
|
||||
vtSeq = L"\x1b[23m";
|
||||
validate(expectedAttr, vtSeq);
|
||||
}
|
||||
if (blink)
|
||||
{
|
||||
WI_ClearFlag(expectedExtendedAttrs, ExtendedAttributes::Blinking);
|
||||
expectedAttr.SetExtendedAttributes(expectedExtendedAttrs);
|
||||
vtSeq = L"\x1b[25m";
|
||||
validate(expectedAttr, vtSeq);
|
||||
}
|
||||
if (invisible)
|
||||
{
|
||||
WI_ClearFlag(expectedExtendedAttrs, ExtendedAttributes::Invisible);
|
||||
expectedAttr.SetExtendedAttributes(expectedExtendedAttrs);
|
||||
vtSeq = L"\x1b[28m";
|
||||
validate(expectedAttr, vtSeq);
|
||||
}
|
||||
if (crossedOut)
|
||||
{
|
||||
WI_ClearFlag(expectedExtendedAttrs, ExtendedAttributes::CrossedOut);
|
||||
expectedAttr.SetExtendedAttributes(expectedExtendedAttrs);
|
||||
vtSeq = L"\x1b[29m";
|
||||
validate(expectedAttr, vtSeq);
|
||||
}
|
||||
|
||||
stateMachine.ProcessString(L"\x1b[0m");
|
||||
}
|
||||
|
||||
void ScreenBufferTests::CursorUpDownAcrossMargins()
|
||||
{
|
||||
// Test inspired by: https://github.com/microsoft/terminal/issues/2929
|
||||
|
|
|
@ -390,25 +390,41 @@ void VtRendererTest::Xterm256TestColors()
|
|||
L"These values were picked for ease of formatting raw COLORREF values."));
|
||||
qExpectedInput.push_back("\x1b[38;2;1;2;3m");
|
||||
qExpectedInput.push_back("\x1b[48;2;5;6;7m");
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(0x00030201, 0x00070605, 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(0x00030201,
|
||||
0x00070605,
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
|
||||
TestPaint(*engine, [&]() {
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Change only the BG----"));
|
||||
qExpectedInput.push_back("\x1b[48;2;7;8;9m");
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(0x00030201, 0x00090807, 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(0x00030201,
|
||||
0x00090807,
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Change only the FG----"));
|
||||
qExpectedInput.push_back("\x1b[38;2;10;11;12m");
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(0x000c0b0a, 0x00090807, 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(0x000c0b0a,
|
||||
0x00090807,
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
});
|
||||
|
||||
TestPaint(*engine, [&]() {
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Make sure that color setting persists across EndPaint/StartPaint"));
|
||||
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(0x000c0b0a, 0x00090807, 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(0x000c0b0a,
|
||||
0x00090807,
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback
|
||||
});
|
||||
|
||||
|
@ -420,41 +436,69 @@ void VtRendererTest::Xterm256TestColors()
|
|||
L"Begin by setting the default colors - FG,BG = BRIGHT_WHITE,DARK_BLACK"));
|
||||
|
||||
qExpectedInput.push_back("\x1b[m");
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15], g_ColorTable[0], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
||||
g_ColorTable[0],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
|
||||
TestPaint(*engine, [&]() {
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Change only the BG----"));
|
||||
qExpectedInput.push_back("\x1b[41m"); // Background DARK_RED
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15], g_ColorTable[4], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
||||
g_ColorTable[4],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Change only the FG----"));
|
||||
qExpectedInput.push_back("\x1b[37m"); // Foreground DARK_WHITE
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7], g_ColorTable[4], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7],
|
||||
g_ColorTable[4],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Change only the BG to something not in the table----"));
|
||||
qExpectedInput.push_back("\x1b[48;2;1;1;1m"); // Background DARK_BLACK
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7], 0x010101, 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7],
|
||||
0x010101,
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Change only the BG to the 'Default' background----"));
|
||||
qExpectedInput.push_back("\x1b[49m"); // Background DARK_BLACK
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7], g_ColorTable[0], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7],
|
||||
g_ColorTable[0],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Back to defaults----"));
|
||||
|
||||
qExpectedInput.push_back("\x1b[m");
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15], g_ColorTable[0], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
||||
g_ColorTable[0],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
});
|
||||
|
||||
TestPaint(*engine, [&]() {
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Make sure that color setting persists across EndPaint/StartPaint"));
|
||||
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15], g_ColorTable[0], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
||||
g_ColorTable[0],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback
|
||||
});
|
||||
}
|
||||
|
@ -725,41 +769,65 @@ void VtRendererTest::XtermTestColors()
|
|||
L"Begin by setting the default colors - FG,BG = BRIGHT_WHITE,DARK_BLACK"));
|
||||
|
||||
qExpectedInput.push_back("\x1b[m");
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15], g_ColorTable[0], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
||||
g_ColorTable[0],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
|
||||
TestPaint(*engine, [&]() {
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Change only the BG----"));
|
||||
qExpectedInput.push_back("\x1b[41m"); // Background DARK_RED
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15], g_ColorTable[4], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
||||
g_ColorTable[4],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Change only the FG----"));
|
||||
qExpectedInput.push_back("\x1b[37m"); // Foreground DARK_WHITE
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7], g_ColorTable[4], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7],
|
||||
g_ColorTable[4],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Change only the BG to something not in the table----"));
|
||||
qExpectedInput.push_back("\x1b[40m"); // Background DARK_BLACK
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7], 0x010101, 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7], 0x010101, 0, ExtendedAttributes::Normal, false));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Change only the BG to the 'Default' background----"));
|
||||
qExpectedInput.push_back("\x1b[40m"); // Background DARK_BLACK
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7], g_ColorTable[0], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7],
|
||||
g_ColorTable[0],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Back to defaults----"));
|
||||
|
||||
qExpectedInput.push_back("\x1b[m");
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15], g_ColorTable[0], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
||||
g_ColorTable[0],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
});
|
||||
|
||||
TestPaint(*engine, [&]() {
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Make sure that color setting persists across EndPaint/StartPaint"));
|
||||
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15], g_ColorTable[0], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
||||
g_ColorTable[0],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback
|
||||
});
|
||||
}
|
||||
|
@ -961,40 +1029,64 @@ void VtRendererTest::WinTelnetTestColors()
|
|||
L"Begin by setting the default colors - FG,BG = BRIGHT_WHITE,DARK_BLACK"));
|
||||
|
||||
qExpectedInput.push_back("\x1b[m");
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15], g_ColorTable[0], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
||||
g_ColorTable[0],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
|
||||
TestPaint(*engine, [&]() {
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Change only the BG----"));
|
||||
qExpectedInput.push_back("\x1b[41m"); // Background DARK_RED
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15], g_ColorTable[4], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
||||
g_ColorTable[4],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Change only the FG----"));
|
||||
qExpectedInput.push_back("\x1b[37m"); // Foreground DARK_WHITE
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7], g_ColorTable[4], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7],
|
||||
g_ColorTable[4],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Change only the BG to something not in the table----"));
|
||||
qExpectedInput.push_back("\x1b[40m"); // Background DARK_BLACK
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7], 0x010101, 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7], 0x010101, 0, ExtendedAttributes::Normal, false));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Change only the BG to the 'Default' background----"));
|
||||
qExpectedInput.push_back("\x1b[40m"); // Background DARK_BLACK
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7], g_ColorTable[0], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7],
|
||||
g_ColorTable[0],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"----Back to defaults----"));
|
||||
qExpectedInput.push_back("\x1b[m");
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15], g_ColorTable[0], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
||||
g_ColorTable[0],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
});
|
||||
|
||||
TestPaint(*engine, [&]() {
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Make sure that color setting persists across EndPaint/StartPaint"));
|
||||
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15], g_ColorTable[0], 0, false, false));
|
||||
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
||||
g_ColorTable[0],
|
||||
0,
|
||||
ExtendedAttributes::Normal,
|
||||
false));
|
||||
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,6 +8,21 @@ Licensed under the MIT license.
|
|||
#define BG_ATTRS (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY)
|
||||
#define META_ATTRS (COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE | COMMON_LVB_GRID_HORIZONTAL | COMMON_LVB_GRID_LVERTICAL | COMMON_LVB_GRID_RVERTICAL | COMMON_LVB_REVERSE_VIDEO | COMMON_LVB_UNDERSCORE)
|
||||
|
||||
enum class ExtendedAttributes : BYTE
|
||||
{
|
||||
Normal = 0x00,
|
||||
Bold = 0x01,
|
||||
Italics = 0x02,
|
||||
Blinking = 0x04,
|
||||
Invisible = 0x08,
|
||||
CrossedOut = 0x10,
|
||||
// TODO:GH#2916 add support for these to the parser as well.
|
||||
Underlined = 0x20, // _technically_ different from LVB_UNDERSCORE, see TODO:GH#2915
|
||||
DoublyUnderlined = 0x40, // Included for completeness, but not currently supported.
|
||||
Faint = 0x80, // Included for completeness, but not currently supported.
|
||||
};
|
||||
DEFINE_ENUM_FLAG_OPERATORS(ExtendedAttributes);
|
||||
|
||||
WORD FindNearestTableIndex(const COLORREF Color,
|
||||
_In_reads_(cColorTable) const COLORREF* const ColorTable,
|
||||
const WORD cColorTable);
|
||||
|
|
|
@ -196,7 +196,7 @@ BgfxEngine::BgfxEngine(PVOID SharedViewBase, LONG DisplayHeight, LONG DisplayWid
|
|||
[[nodiscard]] HRESULT BgfxEngine::UpdateDrawingBrushes(COLORREF const /*colorForeground*/,
|
||||
COLORREF const /*colorBackground*/,
|
||||
const WORD legacyColorAttribute,
|
||||
const bool /*isBold*/,
|
||||
const ExtendedAttributes /*extendedAttrs*/,
|
||||
bool const /*isSettingDefaultBrushes*/) noexcept
|
||||
{
|
||||
_currentLegacyColorAttribute = legacyColorAttribute;
|
||||
|
|
|
@ -60,7 +60,7 @@ namespace Microsoft::Console::Render
|
|||
[[nodiscard]] HRESULT UpdateDrawingBrushes(COLORREF const colorForeground,
|
||||
COLORREF const colorBackground,
|
||||
const WORD legacyColorAttribute,
|
||||
const bool isBold,
|
||||
const ExtendedAttributes extendedAttrs,
|
||||
bool const isSettingDefaultBrushes) noexcept override;
|
||||
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo) noexcept override;
|
||||
[[nodiscard]] HRESULT UpdateDpi(int const iDpi) noexcept override;
|
||||
|
|
|
@ -872,11 +872,11 @@ void Renderer::_PaintSelection(_In_ IRenderEngine* const pEngine)
|
|||
const COLORREF rgbForeground = _pData->GetForegroundColor(textAttributes);
|
||||
const COLORREF rgbBackground = _pData->GetBackgroundColor(textAttributes);
|
||||
const WORD legacyAttributes = textAttributes.GetLegacyAttributes();
|
||||
const bool isBold = textAttributes.IsBold();
|
||||
const auto extendedAttrs = textAttributes.GetExtendedAttributes();
|
||||
|
||||
// The last color needs to be each engine's responsibility. If it's local to this function,
|
||||
// then on the next engine we might not update the color.
|
||||
RETURN_IF_FAILED(pEngine->UpdateDrawingBrushes(rgbForeground, rgbBackground, legacyAttributes, isBold, isSettingDefaultBrushes));
|
||||
RETURN_IF_FAILED(pEngine->UpdateDrawingBrushes(rgbForeground, rgbBackground, legacyAttributes, extendedAttrs, isSettingDefaultBrushes));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
@ -1218,14 +1218,14 @@ enum class CursorPaintType
|
|||
// - colorForeground - Foreground brush color
|
||||
// - colorBackground - Background brush color
|
||||
// - legacyColorAttribute - <unused>
|
||||
// - isBold - <unused>
|
||||
// - extendedAttrs - <unused>
|
||||
// - isSettingDefaultBrushes - Lets us know that these are the default brushes to paint the swapchain background or selection
|
||||
// Return Value:
|
||||
// - S_OK or relevant DirectX error.
|
||||
[[nodiscard]] HRESULT DxEngine::UpdateDrawingBrushes(COLORREF const colorForeground,
|
||||
COLORREF const colorBackground,
|
||||
const WORD /*legacyColorAttribute*/,
|
||||
const bool /*isBold*/,
|
||||
const ExtendedAttributes /*extendedAttrs*/,
|
||||
bool const isSettingDefaultBrushes) noexcept
|
||||
{
|
||||
_foregroundColor = _ColorFFromColorRef(colorForeground);
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace Microsoft::Console::Render
|
|||
[[nodiscard]] HRESULT UpdateDrawingBrushes(COLORREF const colorForeground,
|
||||
COLORREF const colorBackground,
|
||||
const WORD legacyColorAttribute,
|
||||
const bool isBold,
|
||||
const ExtendedAttributes extendedAttrs,
|
||||
bool const isSettingDefaultBrushes) noexcept override;
|
||||
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo) noexcept override;
|
||||
[[nodiscard]] HRESULT UpdateDpi(int const iDpi) noexcept override;
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace Microsoft::Console::Render
|
|||
[[nodiscard]] HRESULT UpdateDrawingBrushes(const COLORREF colorForeground,
|
||||
const COLORREF colorBackground,
|
||||
const WORD legacyColorAttribute,
|
||||
const bool isBold,
|
||||
const ExtendedAttributes extendedAttrs,
|
||||
const bool isSettingDefaultBrushes) noexcept override;
|
||||
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& FontInfoDesired,
|
||||
_Out_ FontInfo& FontInfo) noexcept override;
|
||||
|
|
|
@ -176,7 +176,7 @@ GdiEngine::~GdiEngine()
|
|||
// - colorForeground - Foreground Color
|
||||
// - colorBackground - Background colo
|
||||
// - legacyColorAttribute - <unused>
|
||||
// - isBold - <unused>
|
||||
// - extendedAttrs - <unused>
|
||||
// - isSettingDefaultBrushes - Lets us know that the default brushes are being set so we can update the DC background
|
||||
// and the hung app background painting color
|
||||
// Return Value:
|
||||
|
@ -184,7 +184,7 @@ GdiEngine::~GdiEngine()
|
|||
[[nodiscard]] HRESULT GdiEngine::UpdateDrawingBrushes(const COLORREF colorForeground,
|
||||
const COLORREF colorBackground,
|
||||
const WORD /*legacyColorAttribute*/,
|
||||
const bool /*isBold*/,
|
||||
const ExtendedAttributes /*extendedAttrs*/,
|
||||
const bool isSettingDefaultBrushes) noexcept
|
||||
{
|
||||
RETURN_IF_FAILED(_FlushBufferLines());
|
||||
|
|
|
@ -105,7 +105,7 @@ namespace Microsoft::Console::Render
|
|||
[[nodiscard]] virtual HRESULT UpdateDrawingBrushes(const COLORREF colorForeground,
|
||||
const COLORREF colorBackground,
|
||||
const WORD legacyColorAttribute,
|
||||
const bool isBold,
|
||||
const ExtendedAttributes extendedAttrs,
|
||||
const bool isSettingDefaultBrushes) noexcept = 0;
|
||||
[[nodiscard]] virtual HRESULT UpdateFont(const FontInfoDesired& FontInfoDesired,
|
||||
_Out_ FontInfo& FontInfo) noexcept = 0;
|
||||
|
|
|
@ -345,3 +345,91 @@ using namespace Microsoft::Console::Render;
|
|||
{
|
||||
return _Write("\x1b[24m");
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Writes a sequence to tell the terminal to start italicizing text
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT VtEngine::_BeginItalics() noexcept
|
||||
{
|
||||
return _Write("\x1b[3m");
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Writes a sequence to tell the terminal to stop italicizing text
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT VtEngine::_EndItalics() noexcept
|
||||
{
|
||||
return _Write("\x1b[23m");
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Writes a sequence to tell the terminal to start blinking text
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT VtEngine::_BeginBlink() noexcept
|
||||
{
|
||||
return _Write("\x1b[5m");
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Writes a sequence to tell the terminal to stop blinking text
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT VtEngine::_EndBlink() noexcept
|
||||
{
|
||||
return _Write("\x1b[25m");
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Writes a sequence to tell the terminal to start marking text as invisible
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT VtEngine::_BeginInvisible() noexcept
|
||||
{
|
||||
return _Write("\x1b[8m");
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Writes a sequence to tell the terminal to stop marking text as invisible
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT VtEngine::_EndInvisible() noexcept
|
||||
{
|
||||
return _Write("\x1b[28m");
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Writes a sequence to tell the terminal to start crossing-out text
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT VtEngine::_BeginCrossedOut() noexcept
|
||||
{
|
||||
return _Write("\x1b[9m");
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Writes a sequence to tell the terminal to stop crossing-out text
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT VtEngine::_EndCrossedOut() noexcept
|
||||
{
|
||||
return _Write("\x1b[29m");
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ WinTelnetEngine::WinTelnetEngine(_In_ wil::unique_hfile hPipe,
|
|||
// - colorBackground: The RGB Color to use to paint the background of the text.
|
||||
// - legacyColorAttribute: A console attributes bit field specifying the brush
|
||||
// colors we should use.
|
||||
// - extendedAttrs - extended text attributes (italic, underline, etc.) to use.
|
||||
// - isSettingDefaultBrushes: indicates if we should change the background color of
|
||||
// the window. Unused for VT
|
||||
// Return Value:
|
||||
|
@ -36,10 +37,14 @@ WinTelnetEngine::WinTelnetEngine(_In_ wil::unique_hfile hPipe,
|
|||
[[nodiscard]] HRESULT WinTelnetEngine::UpdateDrawingBrushes(const COLORREF colorForeground,
|
||||
const COLORREF colorBackground,
|
||||
const WORD /*legacyColorAttribute*/,
|
||||
const bool isBold,
|
||||
const ExtendedAttributes extendedAttrs,
|
||||
const bool /*isSettingDefaultBrushes*/) noexcept
|
||||
{
|
||||
return VtEngine::_16ColorUpdateDrawingBrushes(colorForeground, colorBackground, isBold, _ColorTable, _cColorTable);
|
||||
return VtEngine::_16ColorUpdateDrawingBrushes(colorForeground,
|
||||
colorBackground,
|
||||
WI_IsFlagSet(extendedAttrs, ExtendedAttributes::Bold),
|
||||
_ColorTable,
|
||||
_cColorTable);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace Microsoft::Console::Render
|
|||
[[nodiscard]] HRESULT UpdateDrawingBrushes(const COLORREF colorForeground,
|
||||
const COLORREF colorBackground,
|
||||
const WORD legacyColorAttribute,
|
||||
const bool isBold,
|
||||
const ExtendedAttributes extendedAttrs,
|
||||
const bool isSettingDefaultBrushes) noexcept override;
|
||||
[[nodiscard]] HRESULT ScrollFrame() noexcept override;
|
||||
|
||||
|
|
|
@ -14,7 +14,8 @@ Xterm256Engine::Xterm256Engine(_In_ wil::unique_hfile hPipe,
|
|||
const Viewport initialViewport,
|
||||
_In_reads_(cColorTable) const COLORREF* const ColorTable,
|
||||
const WORD cColorTable) :
|
||||
XtermEngine(std::move(hPipe), shutdownEvent, colorProvider, initialViewport, ColorTable, cColorTable, false)
|
||||
XtermEngine(std::move(hPipe), shutdownEvent, colorProvider, initialViewport, ColorTable, cColorTable, false),
|
||||
_lastExtendedAttrsState{ ExtendedAttributes::Normal }
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -26,6 +27,7 @@ Xterm256Engine::Xterm256Engine(_In_ wil::unique_hfile hPipe,
|
|||
// - colorBackground: The RGB Color to use to paint the background of the text.
|
||||
// - legacyColorAttribute: A console attributes bit field specifying the brush
|
||||
// colors we should use.
|
||||
// - extendedAttrs - extended text attributes (italic, underline, etc.) to use.
|
||||
// - isSettingDefaultBrushes: indicates if we should change the background color of
|
||||
// the window. Unused for VT
|
||||
// Return Value:
|
||||
|
@ -33,7 +35,7 @@ Xterm256Engine::Xterm256Engine(_In_ wil::unique_hfile hPipe,
|
|||
[[nodiscard]] HRESULT Xterm256Engine::UpdateDrawingBrushes(const COLORREF colorForeground,
|
||||
const COLORREF colorBackground,
|
||||
const WORD legacyColorAttribute,
|
||||
const bool isBold,
|
||||
const ExtendedAttributes extendedAttrs,
|
||||
const bool /*isSettingDefaultBrushes*/) noexcept
|
||||
{
|
||||
//When we update the brushes, check the wAttrs to see if the LVB_UNDERSCORE
|
||||
|
@ -42,11 +44,70 @@ Xterm256Engine::Xterm256Engine(_In_ wil::unique_hfile hPipe,
|
|||
// We have to do this here, instead of in PaintBufferGridLines, because
|
||||
// we'll have already painted the text by the time PaintBufferGridLines
|
||||
// is called.
|
||||
// TODO:GH#2915 Treat underline separately from LVB_UNDERSCORE
|
||||
RETURN_IF_FAILED(_UpdateUnderline(legacyColorAttribute));
|
||||
|
||||
// Only do extended attributes in xterm-256color, as to not break telnet.exe.
|
||||
RETURN_IF_FAILED(_UpdateExtendedAttrs(extendedAttrs));
|
||||
|
||||
return VtEngine::_RgbUpdateDrawingBrushes(colorForeground,
|
||||
colorBackground,
|
||||
isBold,
|
||||
WI_IsFlagSet(extendedAttrs, ExtendedAttributes::Bold),
|
||||
_ColorTable,
|
||||
_cColorTable);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Write a VT sequence to either start or stop underlining text.
|
||||
// Arguments:
|
||||
// - legacyColorAttribute: A console attributes bit field containing information
|
||||
// about the underlining state of the text.
|
||||
// Return Value:
|
||||
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT Xterm256Engine::_UpdateExtendedAttrs(const ExtendedAttributes extendedAttrs) noexcept
|
||||
{
|
||||
// Helper lambda to check if a state (attr) has changed since it's last
|
||||
// value (lastState), and appropriately start/end that state with the given
|
||||
// begin/end functions.
|
||||
auto updateFlagAndState = [extendedAttrs, this](const ExtendedAttributes attr,
|
||||
std::function<HRESULT(Xterm256Engine*)> beginFn,
|
||||
std::function<HRESULT(Xterm256Engine*)> endFn) -> HRESULT {
|
||||
const bool flagSet = WI_AreAllFlagsSet(extendedAttrs, attr);
|
||||
const bool lastState = WI_AreAllFlagsSet(_lastExtendedAttrsState, attr);
|
||||
if (flagSet != lastState)
|
||||
{
|
||||
if (flagSet)
|
||||
{
|
||||
RETURN_IF_FAILED(beginFn(this));
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN_IF_FAILED(endFn(this));
|
||||
}
|
||||
WI_SetAllFlags(_lastExtendedAttrsState, attr);
|
||||
}
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
auto hr = updateFlagAndState(ExtendedAttributes::Italics,
|
||||
&Xterm256Engine::_BeginItalics,
|
||||
&Xterm256Engine::_EndItalics);
|
||||
RETURN_IF_FAILED(hr);
|
||||
|
||||
hr = updateFlagAndState(ExtendedAttributes::Blinking,
|
||||
&Xterm256Engine::_BeginBlink,
|
||||
&Xterm256Engine::_EndBlink);
|
||||
RETURN_IF_FAILED(hr);
|
||||
|
||||
hr = updateFlagAndState(ExtendedAttributes::Invisible,
|
||||
&Xterm256Engine::_BeginInvisible,
|
||||
&Xterm256Engine::_EndInvisible);
|
||||
RETURN_IF_FAILED(hr);
|
||||
|
||||
hr = updateFlagAndState(ExtendedAttributes::CrossedOut,
|
||||
&Xterm256Engine::_BeginCrossedOut,
|
||||
&Xterm256Engine::_EndCrossedOut);
|
||||
RETURN_IF_FAILED(hr);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
@ -35,10 +35,16 @@ namespace Microsoft::Console::Render
|
|||
[[nodiscard]] HRESULT UpdateDrawingBrushes(const COLORREF colorForeground,
|
||||
const COLORREF colorBackground,
|
||||
const WORD legacyColorAttribute,
|
||||
const bool isBold,
|
||||
const ExtendedAttributes extendedAttrs,
|
||||
const bool isSettingDefaultBrushes) noexcept override;
|
||||
|
||||
private:
|
||||
[[nodiscard]] HRESULT _UpdateExtendedAttrs(const ExtendedAttributes extendedAttrs) noexcept;
|
||||
|
||||
// We're only using Italics, Blinking, Invisible and Crossed Out for now
|
||||
// See GH#2916 for adding a more complete implementation.
|
||||
ExtendedAttributes _lastExtendedAttrsState;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class VtRendererTest;
|
||||
#endif
|
||||
|
|
|
@ -172,6 +172,7 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
|
|||
// - colorBackground: The RGB Color to use to paint the background of the text.
|
||||
// - legacyColorAttribute: A console attributes bit field specifying the brush
|
||||
// colors we should use.
|
||||
// - extendedAttrs - extended text attributes (italic, underline, etc.) to use.
|
||||
// - isSettingDefaultBrushes: indicates if we should change the background color of
|
||||
// the window. Unused for VT
|
||||
// Return Value:
|
||||
|
@ -179,7 +180,7 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
|
|||
[[nodiscard]] HRESULT XtermEngine::UpdateDrawingBrushes(const COLORREF colorForeground,
|
||||
const COLORREF colorBackground,
|
||||
const WORD legacyColorAttribute,
|
||||
const bool isBold,
|
||||
const ExtendedAttributes extendedAttrs,
|
||||
const bool /*isSettingDefaultBrushes*/) noexcept
|
||||
{
|
||||
//When we update the brushes, check the wAttrs to see if the LVB_UNDERSCORE
|
||||
|
@ -188,10 +189,14 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
|
|||
// We have to do this here, instead of in PaintBufferGridLines, because
|
||||
// we'll have already painted the text by the time PaintBufferGridLines
|
||||
// is called.
|
||||
|
||||
// TODO:GH#2915 Treat underline separately from LVB_UNDERSCORE
|
||||
RETURN_IF_FAILED(_UpdateUnderline(legacyColorAttribute));
|
||||
// The base xterm mode only knows about 16 colors
|
||||
return VtEngine::_16ColorUpdateDrawingBrushes(colorForeground, colorBackground, isBold, _ColorTable, _cColorTable);
|
||||
return VtEngine::_16ColorUpdateDrawingBrushes(colorForeground,
|
||||
colorBackground,
|
||||
WI_IsFlagSet(extendedAttrs, ExtendedAttributes::Bold),
|
||||
_ColorTable,
|
||||
_cColorTable);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace Microsoft::Console::Render
|
|||
[[nodiscard]] virtual HRESULT UpdateDrawingBrushes(const COLORREF colorForeground,
|
||||
const COLORREF colorBackground,
|
||||
const WORD legacyColorAttribute,
|
||||
const bool isBold,
|
||||
const ExtendedAttributes extendedAttrs,
|
||||
const bool isSettingDefaultBrushes) noexcept override;
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
const COORD coord,
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace Microsoft::Console::Render
|
|||
[[nodiscard]] virtual HRESULT UpdateDrawingBrushes(const COLORREF colorForeground,
|
||||
const COLORREF colorBackground,
|
||||
const WORD legacyColorAttribute,
|
||||
const bool isBold,
|
||||
const ExtendedAttributes extendedAttrs,
|
||||
const bool isSettingDefaultBrushes) noexcept = 0;
|
||||
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& pfiFontInfoDesired,
|
||||
_Out_ FontInfo& pfiFontInfo) noexcept override;
|
||||
|
@ -172,9 +172,20 @@ namespace Microsoft::Console::Render
|
|||
[[nodiscard]] HRESULT _ResizeWindow(const short sWidth, const short sHeight) noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT _BeginUnderline() noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT _EndUnderline() noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT _BeginItalics() noexcept;
|
||||
[[nodiscard]] HRESULT _EndItalics() noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT _BeginBlink() noexcept;
|
||||
[[nodiscard]] HRESULT _EndBlink() noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT _BeginInvisible() noexcept;
|
||||
[[nodiscard]] HRESULT _EndInvisible() noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT _BeginCrossedOut() noexcept;
|
||||
[[nodiscard]] HRESULT _EndCrossedOut() noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT _RequestCursor() noexcept;
|
||||
|
||||
[[nodiscard]] virtual HRESULT _MoveCursor(const COORD coord) noexcept = 0;
|
||||
|
|
|
@ -307,7 +307,7 @@ bool WddmConEngine::IsInitialized()
|
|||
[[nodiscard]] HRESULT WddmConEngine::UpdateDrawingBrushes(COLORREF const /*colorForeground*/,
|
||||
COLORREF const /*colorBackground*/,
|
||||
const WORD legacyColorAttribute,
|
||||
const bool /*isBold*/,
|
||||
const ExtendedAttributes /*extendedAttrs*/,
|
||||
bool const /*isSettingDefaultBrushes*/) noexcept
|
||||
{
|
||||
_currentLegacyColorAttribute = legacyColorAttribute;
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace Microsoft::Console::Render
|
|||
[[nodiscard]] HRESULT UpdateDrawingBrushes(COLORREF const colorForeground,
|
||||
COLORREF const colorBackground,
|
||||
const WORD legacyColorAttribute,
|
||||
const bool isBold,
|
||||
const ExtendedAttributes extendedAttrs,
|
||||
bool const isSettingDefaultBrushes) noexcept override;
|
||||
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo) noexcept override;
|
||||
[[nodiscard]] HRESULT UpdateDpi(int const iDpi) noexcept override;
|
||||
|
|
|
@ -13,21 +13,28 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes
|
|||
Scrollback = 3
|
||||
};
|
||||
|
||||
// TODO:GH#2916 add support for DoublyUnderlined, Faint(2) to the adapter as well.
|
||||
enum GraphicsOptions : unsigned int
|
||||
{
|
||||
Off = 0,
|
||||
BoldBright = 1,
|
||||
RGBColor = 2,
|
||||
// 2 is also Faint, decreased intensity (ISO 6429).
|
||||
// The 2 and 5 entries here are for BOTH the extended graphics options,
|
||||
// as well as the Faint/Blink options.
|
||||
RGBColorOrFaint = 2, // 2 is also Faint, decreased intensity (ISO 6429).
|
||||
Italics = 3,
|
||||
Underline = 4,
|
||||
Xterm256Index = 5,
|
||||
// 5 is also Blink (appears as Bold).
|
||||
// the 2 and 5 entries here are only for the extended graphics options
|
||||
// as we do not currently support those features individually
|
||||
BlinkOrXterm256Index = 5, // 5 is also Blink (appears as Bold).
|
||||
Negative = 7,
|
||||
Invisible = 8,
|
||||
CrossedOut = 9,
|
||||
DoublyUnderlined = 21,
|
||||
UnBold = 22,
|
||||
NotItalics = 23,
|
||||
NoUnderline = 24,
|
||||
Positive = 27,
|
||||
Steady = 25, // _not_ blink
|
||||
Positive = 27, // _not_ inverse
|
||||
Visible = 28, // _not_ invisible
|
||||
NotCrossedOut = 29,
|
||||
ForegroundBlack = 30,
|
||||
ForegroundRed = 31,
|
||||
ForegroundGreen = 32,
|
||||
|
|
|
@ -6,19 +6,7 @@
|
|||
#include "adaptDispatch.hpp"
|
||||
#include "conGetSet.hpp"
|
||||
#include "../../types/inc/Viewport.hpp"
|
||||
|
||||
// Inspired from RETURN_IF_WIN32_BOOL_FALSE
|
||||
// WIL doesn't include a RETURN_IF_FALSE, and RETURN_IF_WIN32_BOOL_FALSE
|
||||
// will actually return the value of GLE.
|
||||
#define RETURN_IF_FALSE(b) \
|
||||
do \
|
||||
{ \
|
||||
BOOL __boolRet = wil::verify_bool(b); \
|
||||
if (!__boolRet) \
|
||||
{ \
|
||||
return b; \
|
||||
} \
|
||||
} while (0, 0)
|
||||
#include "../../types/inc/utils.hpp"
|
||||
|
||||
using namespace Microsoft::Console::Types;
|
||||
using namespace Microsoft::Console::VirtualTerminal;
|
||||
|
@ -504,15 +492,15 @@ bool AdaptDispatch::_InsertDeleteHelper(_In_ unsigned int const uiCount, const b
|
|||
{
|
||||
// We'll be doing short math on the distance since all console APIs use shorts. So check that we can successfully convert the uint into a short first.
|
||||
SHORT sDistance;
|
||||
RETURN_IF_FALSE(SUCCEEDED(UIntToShort(uiCount, &sDistance)));
|
||||
RETURN_BOOL_IF_FALSE(SUCCEEDED(UIntToShort(uiCount, &sDistance)));
|
||||
|
||||
// get current cursor, attributes
|
||||
CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 };
|
||||
csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
|
||||
// Make sure to reset the viewport (with MoveToBottom )to where it was
|
||||
// before the user scrolled the console output
|
||||
RETURN_IF_FALSE(_conApi->MoveToBottom());
|
||||
RETURN_IF_FALSE(_conApi->GetConsoleScreenBufferInfoEx(&csbiex));
|
||||
RETURN_BOOL_IF_FALSE(_conApi->MoveToBottom());
|
||||
RETURN_BOOL_IF_FALSE(_conApi->GetConsoleScreenBufferInfoEx(&csbiex));
|
||||
|
||||
const auto cursor = csbiex.dwCursorPosition;
|
||||
// Rectangle to cut out of the existing buffer. This is inclusive.
|
||||
|
|
|
@ -170,10 +170,12 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
|
||||
bool _SetBoldColorHelper(const DispatchTypes::GraphicsOptions option);
|
||||
bool _SetDefaultColorHelper(const DispatchTypes::GraphicsOptions option);
|
||||
bool _SetExtendedTextAttributeHelper(const DispatchTypes::GraphicsOptions option);
|
||||
|
||||
static bool s_IsXtermColorOption(const DispatchTypes::GraphicsOptions opt);
|
||||
static bool s_IsRgbColorOption(const DispatchTypes::GraphicsOptions opt);
|
||||
static bool s_IsBoldColorOption(const DispatchTypes::GraphicsOptions opt) noexcept;
|
||||
static bool s_IsDefaultColorOption(const DispatchTypes::GraphicsOptions opt) noexcept;
|
||||
static bool s_IsExtendedTextAttribute(const DispatchTypes::GraphicsOptions opt) noexcept;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "adaptDispatch.hpp"
|
||||
#include "conGetSet.hpp"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
|
||||
#define ENABLE_INTSAFE_SIGNED_FUNCTIONS
|
||||
#include <intsafe.h>
|
||||
|
@ -36,7 +37,9 @@ void AdaptDispatch::s_DisableAllColors(_Inout_ WORD* const pAttr, const bool fIs
|
|||
// Arguments:
|
||||
// - pAttr - Pointer to font attributes field to adjust
|
||||
// - wApplyThis - Color values to apply to the low or high word of the font attributes field.
|
||||
// - fIsForeground - TRUE = foreground color. FALSE = background color. Specifies which half of the bit field to reset and then apply wApplyThis upon.
|
||||
// - fIsForeground - TRUE = foreground color. FALSE = background color.
|
||||
// Specifies which half of the bit field to reset and then apply wApplyThis
|
||||
// upon.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void AdaptDispatch::s_ApplyColors(_Inout_ WORD* const pAttr, const WORD wApplyThis, const bool fIsForeground)
|
||||
|
@ -62,7 +65,9 @@ void AdaptDispatch::s_ApplyColors(_Inout_ WORD* const pAttr, const WORD wApplyTh
|
|||
|
||||
// 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.
|
||||
// - 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
|
||||
|
@ -83,6 +88,7 @@ void AdaptDispatch::_SetGraphicsOptionHelper(const DispatchTypes::GraphicsOption
|
|||
_fChangedMetaAttrs = true;
|
||||
break;
|
||||
case DispatchTypes::GraphicsOptions::Underline:
|
||||
// TODO:GH#2915 Treat underline separately from LVB_UNDERSCORE
|
||||
*pAttr |= COMMON_LVB_UNDERSCORE;
|
||||
_fChangedMetaAttrs = true;
|
||||
break;
|
||||
|
@ -261,6 +267,30 @@ void AdaptDispatch::_SetGraphicsOptionHelper(const DispatchTypes::GraphicsOption
|
|||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// Returns true if the GraphicsOption represents an extended text attribute.
|
||||
// These include things such as Underlined, Italics, Blinking, etc.
|
||||
// Return Value:
|
||||
// - true if the opt is the indicator for an extended text attribute, false otherwise.
|
||||
bool AdaptDispatch::s_IsExtendedTextAttribute(const DispatchTypes::GraphicsOptions opt) noexcept
|
||||
{
|
||||
// TODO:GH#2916 add support for DoublyUnderlined, Faint(RGBColorOrFaint).
|
||||
// These two are currently partially implemented as other things:
|
||||
// * Faint is approximately the opposite of bold does, though it's much
|
||||
// [more complicated](
|
||||
// https://github.com/microsoft/terminal/issues/2916#issuecomment-535860910)
|
||||
// and less supported/used.
|
||||
// * Doubly underlined should exist in a trinary state with Underlined
|
||||
return opt == DispatchTypes::GraphicsOptions::Italics ||
|
||||
opt == DispatchTypes::GraphicsOptions::NotItalics ||
|
||||
opt == DispatchTypes::GraphicsOptions::BlinkOrXterm256Index ||
|
||||
opt == DispatchTypes::GraphicsOptions::Steady ||
|
||||
opt == DispatchTypes::GraphicsOptions::Invisible ||
|
||||
opt == DispatchTypes::GraphicsOptions::Visible ||
|
||||
opt == DispatchTypes::GraphicsOptions::CrossedOut ||
|
||||
opt == DispatchTypes::GraphicsOptions::NotCrossedOut;
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
@ -338,7 +368,7 @@ bool AdaptDispatch::_SetRgbColorsHelper(_In_reads_(cOptions) const DispatchTypes
|
|||
*pfIsForeground = false;
|
||||
}
|
||||
|
||||
if (typeOpt == DispatchTypes::GraphicsOptions::RGBColor && cOptions >= 5)
|
||||
if (typeOpt == DispatchTypes::GraphicsOptions::RGBColorOrFaint && cOptions >= 5)
|
||||
{
|
||||
*pcOptionsConsumed = 5;
|
||||
// ensure that each value fits in a byte
|
||||
|
@ -350,7 +380,7 @@ bool AdaptDispatch::_SetRgbColorsHelper(_In_reads_(cOptions) const DispatchTypes
|
|||
|
||||
fSuccess = !!_conApi->SetConsoleRGBTextAttribute(*prgbColor, *pfIsForeground);
|
||||
}
|
||||
else if (typeOpt == DispatchTypes::GraphicsOptions::Xterm256Index && cOptions >= 3)
|
||||
else if (typeOpt == DispatchTypes::GraphicsOptions::BlinkOrXterm256Index && cOptions >= 3)
|
||||
{
|
||||
*pcOptionsConsumed = 3;
|
||||
if (rgOptions[2] <= 255) // ensure that the provided index is on the table
|
||||
|
@ -374,31 +404,92 @@ bool AdaptDispatch::_SetDefaultColorHelper(const DispatchTypes::GraphicsOptions
|
|||
{
|
||||
const bool fg = option == GraphicsOptions::Off || option == GraphicsOptions::ForegroundDefault;
|
||||
const bool bg = option == GraphicsOptions::Off || option == GraphicsOptions::BackgroundDefault;
|
||||
|
||||
bool success = _conApi->PrivateSetDefaultAttributes(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 = _conApi->PrivateSetLegacyAttributes(0, false, false, true) &&
|
||||
_conApi->PrivateBoldText(false);
|
||||
_conApi->PrivateBoldText(false) &&
|
||||
_conApi->PrivateSetExtendedTextAttributes(ExtendedAttributes::Normal);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - SGR - Modifies the graphical rendering options applied to the next characters written into the buffer.
|
||||
// - Options include colors, invert, underlines, and other "font style" type options.
|
||||
// Method Description:
|
||||
// - Sets the attributes for extended text attributes. Retrieves the current
|
||||
// extended attrs from the console, modifies them according to the new
|
||||
// GraphicsOption, and the sets them again.
|
||||
// - Notably does _not_ handle Bold, Faint, Underline, DoublyUnderlined, or
|
||||
// NoUnderline. Those should be handled in TODO:GH#2916.
|
||||
// Arguments:
|
||||
// - rgOptions - An array of options that will be applied from 0 to N, in order, one at a time by setting or removing flags in the font style properties.
|
||||
// - opt: the graphics option to set
|
||||
// Return Value:
|
||||
// - True if handled successfully. False otherwise.
|
||||
bool AdaptDispatch::_SetExtendedTextAttributeHelper(const DispatchTypes::GraphicsOptions opt)
|
||||
{
|
||||
ExtendedAttributes attrs{ ExtendedAttributes::Normal };
|
||||
|
||||
RETURN_BOOL_IF_FALSE(_conApi->PrivateGetExtendedTextAttributes(&attrs));
|
||||
|
||||
switch (opt)
|
||||
{
|
||||
case DispatchTypes::GraphicsOptions::Italics:
|
||||
WI_SetFlag(attrs, ExtendedAttributes::Italics);
|
||||
break;
|
||||
case DispatchTypes::GraphicsOptions::NotItalics:
|
||||
WI_ClearFlag(attrs, ExtendedAttributes::Italics);
|
||||
break;
|
||||
case DispatchTypes::GraphicsOptions::BlinkOrXterm256Index:
|
||||
WI_SetFlag(attrs, ExtendedAttributes::Blinking);
|
||||
break;
|
||||
case DispatchTypes::GraphicsOptions::Steady:
|
||||
WI_ClearFlag(attrs, ExtendedAttributes::Blinking);
|
||||
break;
|
||||
case DispatchTypes::GraphicsOptions::Invisible:
|
||||
WI_SetFlag(attrs, ExtendedAttributes::Invisible);
|
||||
break;
|
||||
case DispatchTypes::GraphicsOptions::Visible:
|
||||
WI_ClearFlag(attrs, ExtendedAttributes::Invisible);
|
||||
break;
|
||||
case DispatchTypes::GraphicsOptions::CrossedOut:
|
||||
WI_SetFlag(attrs, ExtendedAttributes::CrossedOut);
|
||||
break;
|
||||
case DispatchTypes::GraphicsOptions::NotCrossedOut:
|
||||
WI_ClearFlag(attrs, ExtendedAttributes::CrossedOut);
|
||||
break;
|
||||
// TODO:GH#2916 add support for the following
|
||||
// case DispatchTypes::GraphicsOptions::DoublyUnderlined:
|
||||
// case DispatchTypes::GraphicsOptions::RGBColorOrFaint:
|
||||
// case DispatchTypes::GraphicsOptions::DoublyUnderlined:
|
||||
}
|
||||
|
||||
return _conApi->PrivateSetExtendedTextAttributes(attrs);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - SGR - Modifies the graphical rendering options applied to the next
|
||||
// characters written into the buffer.
|
||||
// - Options include colors, invert, underlines, and other "font style"
|
||||
// type options.
|
||||
|
||||
// Arguments:
|
||||
// - rgOptions - An array of options that will be applied from 0 to N, in order,
|
||||
// one at a time by setting or removing flags in the font style properties.
|
||||
// - cOptions - The count of options (a.k.a. the N in the above line of comments)
|
||||
// Return Value:
|
||||
// - True if handled successfully. False otherwise.
|
||||
bool AdaptDispatch::SetGraphicsRendition(_In_reads_(cOptions) const DispatchTypes::GraphicsOptions* const rgOptions, const size_t cOptions)
|
||||
bool AdaptDispatch::SetGraphicsRendition(_In_reads_(cOptions) const DispatchTypes::GraphicsOptions* const rgOptions,
|
||||
const size_t cOptions)
|
||||
{
|
||||
// We use the private function here to get just the default color attributes as a performance optimization.
|
||||
// Calling the public GetConsoleScreenBufferInfoEx costs a lot of performance time/power in a tight loop
|
||||
// because it has to fill the Largest Window Size by asking the OS and wastes time memcpying colors and other data
|
||||
// we do not need to resolve this Set Graphics Rendition request.
|
||||
// We use the private function here to get just the default color attributes
|
||||
// as a performance optimization. Calling the public
|
||||
// GetConsoleScreenBufferInfoEx costs a lot of performance time/power in a
|
||||
// tight loop because it has to fill the Largest Window Size by asking the
|
||||
// OS and wastes time memcpying colors and other data we do not need to
|
||||
// resolve this Set Graphics Rendition request.
|
||||
WORD attr;
|
||||
bool fSuccess = !!_conApi->PrivateGetConsoleScreenBufferAttributes(&attr);
|
||||
|
||||
|
@ -416,6 +507,10 @@ bool AdaptDispatch::SetGraphicsRendition(_In_reads_(cOptions) const DispatchType
|
|||
{
|
||||
fSuccess = _SetBoldColorHelper(rgOptions[i]);
|
||||
}
|
||||
else if (s_IsExtendedTextAttribute(opt))
|
||||
{
|
||||
fSuccess = _SetExtendedTextAttributeHelper(rgOptions[i]);
|
||||
}
|
||||
else if (s_IsRgbColorOption(opt))
|
||||
{
|
||||
COLORREF rgbColor;
|
||||
|
@ -424,14 +519,21 @@ bool AdaptDispatch::SetGraphicsRendition(_In_reads_(cOptions) const DispatchType
|
|||
size_t cOptionsConsumed = 0;
|
||||
|
||||
// _SetRgbColorsHelper will call the appropriate ConApi function
|
||||
fSuccess = _SetRgbColorsHelper(&(rgOptions[i]), cOptions - i, &rgbColor, &fIsForeground, &cOptionsConsumed);
|
||||
fSuccess = _SetRgbColorsHelper(&(rgOptions[i]),
|
||||
cOptions - i,
|
||||
&rgbColor,
|
||||
&fIsForeground,
|
||||
&cOptionsConsumed);
|
||||
|
||||
i += (cOptionsConsumed - 1); // cOptionsConsumed includes the opt we're currently on.
|
||||
}
|
||||
else
|
||||
{
|
||||
_SetGraphicsOptionHelper(opt, &attr);
|
||||
fSuccess = !!_conApi->PrivateSetLegacyAttributes(attr, _fChangedForeground, _fChangedBackground, _fChangedMetaAttrs);
|
||||
fSuccess = !!_conApi->PrivateSetLegacyAttributes(attr,
|
||||
_fChangedForeground,
|
||||
_fChangedBackground,
|
||||
_fChangedMetaAttrs);
|
||||
|
||||
// Make sure we un-bold
|
||||
if (fSuccess && opt == DispatchTypes::GraphicsOptions::Off)
|
||||
|
|
|
@ -52,6 +52,8 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
const bool fIsForeground) = 0;
|
||||
virtual BOOL SetConsoleRGBTextAttribute(const COLORREF rgbColor, const bool fIsForeground) = 0;
|
||||
virtual BOOL PrivateBoldText(const bool bolded) = 0;
|
||||
virtual BOOL PrivateGetExtendedTextAttributes(ExtendedAttributes* const pAttrs) = 0;
|
||||
virtual BOOL PrivateSetExtendedTextAttributes(const ExtendedAttributes attrs) = 0;
|
||||
|
||||
virtual BOOL PrivateWriteConsoleInputW(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& events,
|
||||
_Out_ size_t& eventsWritten) = 0;
|
||||
|
|
|
@ -339,6 +339,18 @@ public:
|
|||
return !!_fPrivateBoldTextResult;
|
||||
}
|
||||
|
||||
BOOL PrivateGetExtendedTextAttributes(ExtendedAttributes* const /*pAttrs*/)
|
||||
{
|
||||
Log::Comment(L"PrivateGetExtendedTextAttributes MOCK called...");
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL PrivateSetExtendedTextAttributes(const ExtendedAttributes /*attrs*/)
|
||||
{
|
||||
Log::Comment(L"PrivateSetExtendedTextAttributes MOCK called...");
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL PrivateWriteConsoleInputW(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& events,
|
||||
_Out_ size_t& eventsWritten) override
|
||||
{
|
||||
|
@ -2630,7 +2642,7 @@ public:
|
|||
|
||||
Log::Comment(L"Test 1: Change Foreground");
|
||||
rgOptions[0] = DispatchTypes::GraphicsOptions::ForegroundExtended;
|
||||
rgOptions[1] = DispatchTypes::GraphicsOptions::Xterm256Index;
|
||||
rgOptions[1] = DispatchTypes::GraphicsOptions::BlinkOrXterm256Index;
|
||||
rgOptions[2] = (DispatchTypes::GraphicsOptions)2; // Green
|
||||
_testGetSet->_wExpectedAttribute = FOREGROUND_GREEN;
|
||||
_testGetSet->_iExpectedXtermTableEntry = 2;
|
||||
|
@ -2640,7 +2652,7 @@ public:
|
|||
|
||||
Log::Comment(L"Test 2: Change Background");
|
||||
rgOptions[0] = DispatchTypes::GraphicsOptions::BackgroundExtended;
|
||||
rgOptions[1] = DispatchTypes::GraphicsOptions::Xterm256Index;
|
||||
rgOptions[1] = DispatchTypes::GraphicsOptions::BlinkOrXterm256Index;
|
||||
rgOptions[2] = (DispatchTypes::GraphicsOptions)9; // Bright Red
|
||||
_testGetSet->_wExpectedAttribute = FOREGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
|
||||
_testGetSet->_iExpectedXtermTableEntry = 9;
|
||||
|
@ -2650,7 +2662,7 @@ public:
|
|||
|
||||
Log::Comment(L"Test 3: Change Foreground to RGB color");
|
||||
rgOptions[0] = DispatchTypes::GraphicsOptions::ForegroundExtended;
|
||||
rgOptions[1] = DispatchTypes::GraphicsOptions::Xterm256Index;
|
||||
rgOptions[1] = DispatchTypes::GraphicsOptions::BlinkOrXterm256Index;
|
||||
rgOptions[2] = (DispatchTypes::GraphicsOptions)42; // Arbitrary Color
|
||||
_testGetSet->_iExpectedXtermTableEntry = 42;
|
||||
_testGetSet->_fExpectedIsForeground = true;
|
||||
|
@ -2659,7 +2671,7 @@ public:
|
|||
|
||||
Log::Comment(L"Test 4: Change Background to RGB color");
|
||||
rgOptions[0] = DispatchTypes::GraphicsOptions::BackgroundExtended;
|
||||
rgOptions[1] = DispatchTypes::GraphicsOptions::Xterm256Index;
|
||||
rgOptions[1] = DispatchTypes::GraphicsOptions::BlinkOrXterm256Index;
|
||||
rgOptions[2] = (DispatchTypes::GraphicsOptions)142; // Arbitrary Color
|
||||
_testGetSet->_iExpectedXtermTableEntry = 142;
|
||||
_testGetSet->_fExpectedIsForeground = false;
|
||||
|
@ -2671,7 +2683,7 @@ public:
|
|||
// to have its own color table and translate the pre-existing RGB BG into a legacy BG.
|
||||
// Fortunately, the ft_api:RgbColorTests IS smart enough to test that.
|
||||
rgOptions[0] = DispatchTypes::GraphicsOptions::ForegroundExtended;
|
||||
rgOptions[1] = DispatchTypes::GraphicsOptions::Xterm256Index;
|
||||
rgOptions[1] = DispatchTypes::GraphicsOptions::BlinkOrXterm256Index;
|
||||
rgOptions[2] = (DispatchTypes::GraphicsOptions)9; // Bright Red
|
||||
_testGetSet->_wExpectedAttribute = FOREGROUND_RED | FOREGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_INTENSITY;
|
||||
_testGetSet->_iExpectedXtermTableEntry = 9;
|
||||
|
|
|
@ -11,6 +11,19 @@ Author(s):
|
|||
- Mike Griese (migrie) 12-Jun-2018
|
||||
--*/
|
||||
|
||||
// Inspired from RETURN_IF_WIN32_BOOL_FALSE
|
||||
// WIL doesn't include a RETURN_BOOL_IF_FALSE, and RETURN_IF_WIN32_BOOL_FALSE
|
||||
// will actually return the value of GLE.
|
||||
#define RETURN_BOOL_IF_FALSE(b) \
|
||||
do \
|
||||
{ \
|
||||
BOOL __boolRet = wil::verify_bool(b); \
|
||||
if (!__boolRet) \
|
||||
{ \
|
||||
return __boolRet; \
|
||||
} \
|
||||
} while (0, 0)
|
||||
|
||||
namespace Microsoft::Console::Utils
|
||||
{
|
||||
bool IsValidHandle(const HANDLE handle) noexcept;
|
||||
|
|
Loading…
Reference in New Issue