diff --git a/src/buffer/out/TextAttribute.cpp b/src/buffer/out/TextAttribute.cpp index abc7f703d330..4d6e2a8d3da8 100644 --- a/src/buffer/out/TextAttribute.cpp +++ b/src/buffer/out/TextAttribute.cpp @@ -221,17 +221,17 @@ bool TextAttribute::IsRightVerticalDisplayed() const noexcept return WI_IsFlagSet(_wAttrLegacy, COMMON_LVB_GRID_RVERTICAL); } -void TextAttribute::SetLeftVerticalDisplayed(bool isDisplayed) noexcept +void TextAttribute::SetLeftVerticalDisplayed(const bool isDisplayed) noexcept { WI_UpdateFlag(_wAttrLegacy, COMMON_LVB_GRID_LVERTICAL, isDisplayed); } -void TextAttribute::SetRightVerticalDisplayed(bool isDisplayed) noexcept +void TextAttribute::SetRightVerticalDisplayed(const bool isDisplayed) noexcept { WI_UpdateFlag(_wAttrLegacy, COMMON_LVB_GRID_RVERTICAL, isDisplayed); } -void TextAttribute::SetBottomHorizontalDisplayed(bool isDisplayed) noexcept +void TextAttribute::SetBottomHorizontalDisplayed(const bool isDisplayed) noexcept { WI_UpdateFlag(_wAttrLegacy, COMMON_LVB_UNDERSCORE, isDisplayed); } diff --git a/src/buffer/out/TextAttribute.hpp b/src/buffer/out/TextAttribute.hpp index 0120fea40e5a..f6cbd9c0a125 100644 --- a/src/buffer/out/TextAttribute.hpp +++ b/src/buffer/out/TextAttribute.hpp @@ -107,9 +107,9 @@ class TextAttribute final bool IsLeftVerticalDisplayed() const noexcept; bool IsRightVerticalDisplayed() const noexcept; - void SetLeftVerticalDisplayed(bool isDisplayed) noexcept; - void SetRightVerticalDisplayed(bool isDisplayed) noexcept; - void SetBottomHorizontalDisplayed(bool isDisplayed) noexcept; + void SetLeftVerticalDisplayed(const bool isDisplayed) noexcept; + void SetRightVerticalDisplayed(const bool isDisplayed) noexcept; + void SetBottomHorizontalDisplayed(const bool isDisplayed) noexcept; void SetFromLegacy(const WORD wLegacy) noexcept; diff --git a/src/buffer/out/sgrStack.hpp b/src/buffer/out/sgrStack.hpp new file mode 100644 index 000000000000..0ccf6e966c42 --- /dev/null +++ b/src/buffer/out/sgrStack.hpp @@ -0,0 +1,230 @@ +/*++ +Copyright (c) Microsoft Corporation +Licensed under the MIT license. + +Module Name: +- sgrStack.hpp + +Abstract: +- Encapsulates logic for the XTPUSHSGR / XTPOPSGR VT control sequences, which save and + restore text attributes on a stack. + +--*/ + +#pragma once + +#include "TextAttribute.hpp" +#include "..\..\terminal\adapter\DispatchTypes.hpp" + +namespace Microsoft::Console::VirtualTerminal +{ + class SgrStack + { + public: + SgrStack() noexcept : + _numSgrPushes{ 0 }, + _validAttributes{ 0 }, + _storedSgrAttributes{ 0 } + { + } + + // Method Description: + // - Saves the specified text attributes onto an internal stack. + // Arguments: + // - currentAttributes - The attributes to save onto the stack. + // - rgOptions, cOptions - If not supplied, the full attributes are saved. If + // options are supplied, only the specified parts of currentAttributes are + // saved. + // Return Value: + // - + void Push(const TextAttribute& currentAttributes, + const gsl::span options) noexcept + { + uint32_t validParts = 0; + + if (options.size() == 0) + { + // We save all current attributes. + validParts = UINT32_MAX; + } + else + { + // Each option is encoded as a bit in validParts. Options that aren't + // supported are ignored. So if you try to save only unsuppported aspects + // of the current text attributes, validParts will be zero, and you'll do + // what is effectively an "empty" push (the subsequent pop will not change + // the current attributes). + for (auto option : options) + { + validParts |= _GraphicsOptionToFlag(option); + } + } + + if (_numSgrPushes < _countof(_storedSgrAttributes)) + { +// Must disable 26482 "Only index into arrays using constant expressions" because we are +// implementing a stack, and that's the whole point. +#pragma warning(push) +#pragma warning(disable : 26482) + gsl::at(_storedSgrAttributes, _numSgrPushes) = currentAttributes; + gsl::at(_validAttributes, _numSgrPushes) = validParts; +#pragma warning(pop) + } + + if (_numSgrPushes < c_MaxBalancedPushes) + { + _numSgrPushes++; + } + } + + // Method Description: + // - Restores text attributes by removing from the top of the internal stack, + // combining them with the supplied currentAttributes, if appropriate. + // Arguments: + // - currentAttributes - The current text attributes. If only a portion of + // attributes were saved on the internal stack, then those attributes will be + // combined with the currentAttributes passed in to form the return value. + // Return Value: + // - The TextAttribute that has been removed from the top of the stack, possibly + // combined with currentAttributes. + const TextAttribute Pop(const TextAttribute& currentAttributes) noexcept + { + if (_numSgrPushes > 0) + { + _numSgrPushes--; + + if (_numSgrPushes < _countof(_storedSgrAttributes)) + { + uint32_t validParts = _validAttributes[_numSgrPushes]; + + if (validParts == UINT32_MAX) + { + return _storedSgrAttributes[_numSgrPushes]; + } + else + { + return _CombineWithCurrentAttributes(currentAttributes, + _storedSgrAttributes[_numSgrPushes], + validParts); + } + } + } + + return currentAttributes; + } + + // Xterm allows the save stack to go ten deep, so we'll follow suit. Pushes after + // ten deep will still remain "balanced"--once you pop back down below ten, you'll + // restore the appropriate text attributes. However, if you get more than a + // hundred pushes deep, we'll stop counting. Why unbalance somebody doing so many + // pushes? Putting a bound on it allows us to provide "reset" functionality: at + // any given point, you can execute 101 pops and know that you've taken the stack + // (push count) to zero. (Then you reset text attributes, and your state is + // clean.) + static constexpr int c_MaxStoredSgrPushes = 10; + static constexpr int c_MaxBalancedPushes = 100; + + private: + static constexpr uint32_t _GraphicsOptionToFlag(DispatchTypes::GraphicsOptions option) + { + int iOption = static_cast(option); + + if (iOption < (sizeof(uint32_t) * 8)) + { + iOption = 1 << iOption; + } + // else it's a bad parameter; we'll just ignore it + + return iOption; + } + + TextAttribute _CombineWithCurrentAttributes(const TextAttribute& currentAttributes, + const TextAttribute& savedAttribute, + uint32_t validParts) // of savedAttribute + { + TextAttribute result = currentAttributes; + + // From xterm documentation: + // + // CSI # { + // CSI Ps ; Ps # { + // Push video attributes onto stack (XTPUSHSGR), xterm. The + // optional parameters correspond to the SGR encoding for video + // attributes, except for colors (which do not have a unique SGR + // code): + // Ps = 1 -> Bold. + // Ps = 2 -> Faint. + // Ps = 3 -> Italicized. + // Ps = 4 -> Underlined. + // Ps = 5 -> Blink. + // Ps = 7 -> Inverse. + // Ps = 8 -> Invisible. + // Ps = 9 -> Crossed-out characters. + // Ps = 1 0 -> Foreground color. + // Ps = 1 1 -> Background color. + // Ps = 2 1 -> Doubly-underlined. + // + // (some closing braces for people with editors that get thrown off without them: }}) + // + // Attributes that are not currently supported are simply ignored. + + if (_GraphicsOptionToFlag(DispatchTypes::GraphicsOptions::BoldBright) & validParts) + { + if (savedAttribute.IsBold()) + { + result.Embolden(); + } + else + { + result.Debolden(); + } + } + + if (_GraphicsOptionToFlag(DispatchTypes::GraphicsOptions::Underline) & validParts) + { + if (savedAttribute.IsUnderline()) + { + result.EnableUnderline(); + } + else + { + result.DisableUnderline(); + } + } + + if (_GraphicsOptionToFlag(DispatchTypes::GraphicsOptions::Negative) & validParts) + { + if (savedAttribute.IsReverseVideo()) + { + if (!result.IsReverseVideo()) + { + result.Invert(); + } + } + else + { + if (result.IsReverseVideo()) + { + result.Invert(); + } + } + } + + if (_GraphicsOptionToFlag(DispatchTypes::GraphicsOptions::SaveForegroundColor) & validParts) + { + result.SetForegroundFrom(savedAttribute); + } + + if (_GraphicsOptionToFlag(DispatchTypes::GraphicsOptions::SaveBackgroundColor) & validParts) + { + result.SetBackgroundFrom(savedAttribute); + } + + return result; + } + + int _numSgrPushes; // used as an index into the following arrays + TextAttribute _storedSgrAttributes[c_MaxStoredSgrPushes]; + uint32_t _validAttributes[c_MaxStoredSgrPushes]; // flags that indicate which portions of the attributes are valid + }; +} diff --git a/src/cascadia/TerminalCore/ITerminalApi.hpp b/src/cascadia/TerminalCore/ITerminalApi.hpp index 2bf09bf7b31e..e0ae44cb7354 100644 --- a/src/cascadia/TerminalCore/ITerminalApi.hpp +++ b/src/cascadia/TerminalCore/ITerminalApi.hpp @@ -44,6 +44,9 @@ namespace Microsoft::Terminal::Core virtual bool SetDefaultForeground(const DWORD dwColor) = 0; virtual bool SetDefaultBackground(const DWORD dwColor) = 0; + virtual bool PushGraphicsRendition(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::GraphicsOptions* options, size_t cOptions) = 0; + virtual bool PopGraphicsRendition() = 0; + protected: ITerminalApi() = default; }; diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index e565b17a9ec5..93f3135db76d 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -6,6 +6,7 @@ #include #include "../../buffer/out/textBuffer.hpp" +#include "../../buffer/out/sgrStack.hpp" #include "../../renderer/inc/IRenderData.hpp" #include "../../terminal/parser/StateMachine.hpp" #include "../../terminal/input/terminalInput.hpp" @@ -83,6 +84,8 @@ class Microsoft::Terminal::Core::Terminal final : bool SetCursorStyle(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::CursorStyle cursorStyle) override; bool SetDefaultForeground(const COLORREF dwColor) override; bool SetDefaultBackground(const COLORREF dwColor) override; + bool PushGraphicsRendition(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::GraphicsOptions* options, size_t cOptions) override; + bool PopGraphicsRendition() override; #pragma endregion #pragma region ITerminalInput @@ -243,4 +246,6 @@ class Microsoft::Terminal::Core::Terminal final : SMALL_RECT _GetSelectionRow(const SHORT row, const COORD higherCoord, const COORD lowerCoord) const; void _ExpandSelectionRow(SMALL_RECT& selectionRow) const; #pragma endregion + + Microsoft::Console::VirtualTerminal::SgrStack _sgrStack; }; diff --git a/src/cascadia/TerminalCore/TerminalApi.cpp b/src/cascadia/TerminalCore/TerminalApi.cpp index 049f268dc0ee..eb3fad352411 100644 --- a/src/cascadia/TerminalCore/TerminalApi.cpp +++ b/src/cascadia/TerminalCore/TerminalApi.cpp @@ -474,3 +474,31 @@ bool Terminal::SetDefaultBackground(const COLORREF dwColor) _buffer->GetRenderTarget().TriggerRedrawAll(); return true; } + +// Method Description: +// - Saves the current text attributes to an internal stack. +// Arguments: +// - options, cOptions: if present, specify which portions of the current text attributes +// should be saved. Only a small subset of GraphicsOptions are actually supported; +// others are ignored. If no options are specified, all attributes are stored. +// Return Value: +// - true +bool Terminal::PushGraphicsRendition(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::GraphicsOptions* options, size_t cOptions) +{ + _sgrStack.Push(_buffer->GetCurrentAttributes(), { options, (int) cOptions }); + return true; +} + +// Method Description: +// - Restores text attributes from the internal stack. If only portions of text attributes +// were saved, combines those with the current attributes. +// Arguments: +// - +// Return Value: +// - true +bool Terminal::PopGraphicsRendition() +{ + TextAttribute current = _buffer->GetCurrentAttributes(); + _buffer->SetCurrentAttributes(_sgrStack.Pop(current)); + return true; +} diff --git a/src/cascadia/TerminalCore/TerminalDispatch.hpp b/src/cascadia/TerminalCore/TerminalDispatch.hpp index 5fa9758856ee..2988d60f41d3 100644 --- a/src/cascadia/TerminalCore/TerminalDispatch.hpp +++ b/src/cascadia/TerminalCore/TerminalDispatch.hpp @@ -16,6 +16,10 @@ class TerminalDispatch : public Microsoft::Console::VirtualTerminal::TermDispatc bool SetGraphicsRendition(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::GraphicsOptions* const rgOptions, const size_t cOptions) override; + bool PushGraphicsRendition(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::GraphicsOptions* const rgOptions, + const size_t cOptions) override; + bool PopGraphicsRendition() override; + virtual bool CursorPosition(const unsigned int uiLine, const unsigned int uiColumn) override; // CUP diff --git a/src/cascadia/TerminalCore/TerminalDispatchGraphics.cpp b/src/cascadia/TerminalCore/TerminalDispatchGraphics.cpp index b73b9adee1b2..27fe12ede963 100644 --- a/src/cascadia/TerminalCore/TerminalDispatchGraphics.cpp +++ b/src/cascadia/TerminalCore/TerminalDispatchGraphics.cpp @@ -326,3 +326,14 @@ bool TerminalDispatch::SetGraphicsRendition(const DispatchTypes::GraphicsOptions } return fSuccess; } + +bool TerminalDispatch::PushGraphicsRendition(const DispatchTypes::GraphicsOptions* const rgOptions, + const size_t cOptions) +{ + return _terminalApi.PushGraphicsRendition(rgOptions, cOptions); +} + +bool TerminalDispatch::PopGraphicsRendition() +{ + return _terminalApi.PopGraphicsRendition(); +} diff --git a/src/host/outputStream.cpp b/src/host/outputStream.cpp index 4b34499edfaa..412862f8d3cf 100644 --- a/src/host/outputStream.cpp +++ b/src/host/outputStream.cpp @@ -229,7 +229,7 @@ BOOL ConhostInternalGetSet::PrivateSetDefaultAttributes(const bool fForeground, // - fBackground - The new attributes contain an update to the background attributes // - fMeta - The new attributes contain an update to the meta attributes // Return Value: -// - TRUE if successful (see DoSrvVtSetLegacyAttributes). FALSE otherwise. +// - TRUE. BOOL ConhostInternalGetSet::PrivateSetLegacyAttributes(const WORD wAttr, const bool fForeground, const bool fBackground, @@ -239,6 +239,12 @@ BOOL ConhostInternalGetSet::PrivateSetLegacyAttributes(const WORD wAttr, return TRUE; } +// Routine Description: +// - Similar to PrivateSetLegacyAttributes, but sets the full fidelity TextAttribute. +// Arguments: +// - attributes - new text attributes to apply as default within the console text buffer +// Return Value: +// - TRUE. BOOL ConhostInternalGetSet::PrivateSetAttributes(const TextAttribute& attributes) { DoSrvPrivateSetAttributes(_io.GetActiveOutputBuffer(), attributes); diff --git a/src/terminal/adapter/DispatchTypes.hpp b/src/terminal/adapter/DispatchTypes.hpp index 17f26c66d858..fed2bd5721f5 100644 --- a/src/terminal/adapter/DispatchTypes.hpp +++ b/src/terminal/adapter/DispatchTypes.hpp @@ -27,6 +27,10 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes Negative = 7, Invisible = 8, CrossedOut = 9, + // 10 - 19 are actually for selecting fonts, but rarely implemented. 10 and 11 + // have been repurposed by xterm for XTPUSHGR. + SaveForegroundColor = 10, + SaveBackgroundColor = 11, DoublyUnderlined = 21, UnBold = 22, NotItalics = 23, diff --git a/src/terminal/adapter/ITermDispatch.hpp b/src/terminal/adapter/ITermDispatch.hpp index 59b9d7490023..b4fe1793fab6 100644 --- a/src/terminal/adapter/ITermDispatch.hpp +++ b/src/terminal/adapter/ITermDispatch.hpp @@ -77,6 +77,10 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch virtual bool SetGraphicsRendition(_In_reads_(cOptions) const DispatchTypes::GraphicsOptions* const rgOptions, const size_t cOptions) = 0; // SGR + virtual bool PushGraphicsRendition(_In_reads_(cOptions) const DispatchTypes::GraphicsOptions* const rgOptions, + const size_t cOptions) = 0; // XTPUSHSGR + virtual bool PopGraphicsRendition() = 0; // XTPOPSGR + virtual bool SetPrivateModes(_In_reads_(cParams) const DispatchTypes::PrivateModeParams* const rgParams, const size_t cParams) = 0; // DECSET diff --git a/src/terminal/adapter/adaptDispatch.hpp b/src/terminal/adapter/adaptDispatch.hpp index 255dd2c2e6e2..b0448abbc9ae 100644 --- a/src/terminal/adapter/adaptDispatch.hpp +++ b/src/terminal/adapter/adaptDispatch.hpp @@ -19,6 +19,7 @@ Author(s): #include "conGetSet.hpp" #include "adaptDefaults.hpp" #include "terminalOutput.hpp" +#include "..\..\buffer\out\sgrStack.hpp" #include #define XTERM_COLOR_TABLE_SIZE (256) @@ -58,6 +59,9 @@ namespace Microsoft::Console::VirtualTerminal bool DeleteCharacter(_In_ unsigned int const uiCount) override; // DCH bool SetGraphicsRendition(_In_reads_(cOptions) const DispatchTypes::GraphicsOptions* const rgOptions, const size_t cOptions) override; // SGR + bool PushGraphicsRendition(_In_reads_(cOptions) const DispatchTypes::GraphicsOptions* const rgOptions, + const size_t cOptions) override; // XTPUSHSGR + bool PopGraphicsRendition() override; // XTPOPSGR bool DeviceStatusReport(const DispatchTypes::AnsiStatusType statusType) override; // DSR bool DeviceAttributes() override; // DA bool ScrollUp(_In_ unsigned int const uiDistance) override; // SU @@ -154,14 +158,14 @@ namespace Microsoft::Console::VirtualTerminal bool _fIsOriginModeRelative; bool _fIsSavedOriginModeRelative; - bool _fIsSetColumnsEnabled; - bool _fIsDECCOLMAllowed; bool _fChangedForeground; bool _fChangedBackground; bool _fChangedMetaAttrs; + SgrStack _sgrStack; + bool _SetRgbColorsHelper(_In_reads_(cOptions) const DispatchTypes::GraphicsOptions* const rgOptions, const size_t cOptions, _Out_ COLORREF* const prgbColor, diff --git a/src/terminal/adapter/adaptDispatchGraphics.cpp b/src/terminal/adapter/adaptDispatchGraphics.cpp index 7315251b8e0b..663f7e6023c2 100644 --- a/src/terminal/adapter/adaptDispatchGraphics.cpp +++ b/src/terminal/adapter/adaptDispatchGraphics.cpp @@ -550,3 +550,49 @@ bool AdaptDispatch::SetGraphicsRendition(_In_reads_(cOptions) const DispatchType return fSuccess; } + +// Method Description: +// - Saves the current text attributes to an internal stack. +// Arguments: +// - rgOptions, cOptions: if present, specify which portions of the current text attributes +// should be saved. Only a small subset of GraphicsOptions are actually supported; +// others are ignored. If no options are specified, all attributes are stored. +// Return Value: +// - True if handled successfully. False otherwise. +bool AdaptDispatch::PushGraphicsRendition(_In_reads_(cOptions) const DispatchTypes::GraphicsOptions* const rgOptions, + const size_t cOptions) +{ + bool fSuccess = true; + TextAttribute currentAttributes; + + fSuccess = _conApi->PrivateGetConsoleScreenBufferAttributes(¤tAttributes); + + if (fSuccess) + { + _sgrStack.Push(currentAttributes, { rgOptions, (int) cOptions }); + } + + return fSuccess; +} + +// Method Description: +// - Restores text attributes from the internal stack. If only portions of text attributes +// were saved, combines those with the current attributes. +// Arguments: +// - +// Return Value: +// - True if handled successfully. False otherwise. +bool AdaptDispatch::PopGraphicsRendition() +{ + bool fSuccess = true; + TextAttribute currentAttributes; + + fSuccess = _conApi->PrivateGetConsoleScreenBufferAttributes(¤tAttributes); + + if (fSuccess) + { + fSuccess = _conApi->PrivateSetAttributes(_sgrStack.Pop(currentAttributes)); + } + + return fSuccess; +} diff --git a/src/terminal/adapter/termDispatch.hpp b/src/terminal/adapter/termDispatch.hpp index 8fb7bce91613..e8dc85bc0d33 100644 --- a/src/terminal/adapter/termDispatch.hpp +++ b/src/terminal/adapter/termDispatch.hpp @@ -74,6 +74,10 @@ class Microsoft::Console::VirtualTerminal::TermDispatch : public Microsoft::Cons bool SetGraphicsRendition(_In_reads_(_Param_(2)) const DispatchTypes::GraphicsOptions* const /*rgOptions*/, const size_t /*cOptions*/) override { return false; } // SGR + bool PushGraphicsRendition(_In_reads_(_Param_(2)) const DispatchTypes::GraphicsOptions* const /*rgOptions*/, + const size_t /*cOptions*/) override { return false; } // XTPUSHSGR + bool PopGraphicsRendition() override { return false; } // XTPOPSGR + bool SetPrivateModes(_In_reads_(_Param_(2)) const DispatchTypes::PrivateModeParams* const /*rgParams*/, const size_t /*cParams*/) override { return false; } // DECSET diff --git a/src/terminal/parser/OutputStateMachineEngine.cpp b/src/terminal/parser/OutputStateMachineEngine.cpp index 66daa8fd23df..72f446d940db 100644 --- a/src/terminal/parser/OutputStateMachineEngine.cpp +++ b/src/terminal/parser/OutputStateMachineEngine.cpp @@ -523,6 +523,9 @@ bool OutputStateMachineEngine::ActionCsiDispatch(const wchar_t wch, case L' ': fSuccess = _IntermediateSpaceDispatch(wch, rgusParams, cParams); break; + case L'#': + fSuccess = _IntermediateHashDispatch(wch, rgusParams, cParams); + break; default: // If no functions to call, overall dispatch was a failure. fSuccess = false; @@ -560,7 +563,7 @@ bool OutputStateMachineEngine::_IntermediateQuestionMarkDispatch(const wchar_t w { case VTActionCodes::DECSET_PrivateModeSet: case VTActionCodes::DECRST_PrivateModeReset: - fSuccess = _GetPrivateModeParams(rgusParams, cParams, rgPrivateModeParams, &cOptions); + fSuccess = _GetTypedParams(rgusParams, cParams, rgPrivateModeParams, &cOptions); break; default: @@ -658,6 +661,71 @@ bool OutputStateMachineEngine::_IntermediateSpaceDispatch(const wchar_t wchActio return fSuccess; } +// Routine Description: +// - Handles actions that have an intermediate '#' (0x23), such as XTPUSHSGR, XTPOPSGR +// Arguments: +// - wch - Character to dispatch. +// Return Value: +// - True if handled successfully. False otherwise. +bool OutputStateMachineEngine::_IntermediateHashDispatch(const wchar_t wchAction, + _In_reads_(cParams) const unsigned short* const rgusParams, + const unsigned short cParams) +{ + bool fSuccess = false; + + DispatchTypes::GraphicsOptions rgPushPopParams[StateMachine::s_cParamsMax]; + size_t cOptions = StateMachine::s_cParamsMax; + // Ensure that there was the right number of params + switch (wchAction) + { + case VTActionCodes::XT_PushSgr: + case VTActionCodes::XT_PushSgrAlias: + fSuccess = _GetTypedParams(rgusParams, cParams, rgPushPopParams, &cOptions); + break; + + case VTActionCodes::XT_PopSgr: + case VTActionCodes::XT_PopSgrAlias: + if (cParams > 0) + { + // Can't supply params for XTPOPSGR. + fSuccess = false; + } + else + { + fSuccess = true; + } + break; + + default: + // If no params to fill, param filling was successful. + fSuccess = true; + break; + } + if (fSuccess) + { + switch (wchAction) + { + case VTActionCodes::XT_PushSgr: + case VTActionCodes::XT_PushSgrAlias: + fSuccess = _dispatch->PushGraphicsRendition(rgPushPopParams, cOptions); + // TODO: telemetry + break; + + case VTActionCodes::XT_PopSgr: + case VTActionCodes::XT_PopSgrAlias: + fSuccess = _dispatch->PopGraphicsRendition(); + // TODO: telemetry + break; + + default: + // If no functions to call, overall dispatch was a failure. + fSuccess = false; + break; + } + } + return fSuccess; +} + // Routine Description: // - Triggers the Clear action to indicate that the state machine should erase // all internal state. @@ -1090,6 +1158,7 @@ _Success_(return ) bool OutputStateMachineEngine::_GetTopBottomMargins(_In_reads } return fSuccess; } + // Routine Description: // - Retrieves the status type parameter for an upcoming device query operation // Arguments: @@ -1122,27 +1191,27 @@ _Success_(return ) bool OutputStateMachineEngine::_GetDeviceStatusOperation(_In_ } // Routine Description: -// - Retrieves the listed private mode params be set/reset by DECSET/DECRST +// - Converts the untyped array of numeric parameters into an array of the specified type. // Arguments: -// - rPrivateModeParams - Pointer to array space (expected 16 max, the max number of params this can generate) that will be filled with valid params from the PrivateModeParams enum -// - pcParams - Pointer to the length of rPrivateModeParams on the way in, and the count of the array used on the way out. +// - rgTypedParams - Pointer to array space (expected 16 max, the max number of params this can generate) that will be filled with valid params from the PrivateModeParams enum +// - pcParams - Pointer to the length of rgTypedParams on the way in, and the count of the array used on the way out. // Return Value: -// - True if we successfully retrieved an array of private mode params from the parameters we've stored. False otherwise. -_Success_(return ) bool OutputStateMachineEngine::_GetPrivateModeParams(_In_reads_(cParams) const unsigned short* const rgusParams, - const unsigned short cParams, - _Out_writes_(*pcParams) DispatchTypes::PrivateModeParams* const rgPrivateModeParams, - _Inout_ size_t* const pcParams) const +// - True if we successfully retrieved an array of strongly-typed params from the parameters we've stored. False otherwise. +template +_Success_(return ) bool OutputStateMachineEngine::_GetTypedParams(_In_reads_(cParams) const unsigned short* const rgusParams, + const unsigned short cParams, + _Out_writes_(*pcParams) TParamType* const rgTypedParams, + _Inout_ size_t* const pcParams) const { bool fSuccess = false; - // Can't just set nothing at all if (cParams > 0) { if (*pcParams >= cParams) { for (size_t i = 0; i < cParams; i++) { - // No memcpy. The parameters are shorts. The graphics options are unsigned ints. - rgPrivateModeParams[i] = (DispatchTypes::PrivateModeParams)rgusParams[i]; + // No memcpy because the parameters are shorts, and the destination type may be a different size. + rgTypedParams[i] = static_cast(rgusParams[i]); } *pcParams = cParams; fSuccess = true; @@ -1152,6 +1221,11 @@ _Success_(return ) bool OutputStateMachineEngine::_GetPrivateModeParams(_In_read fSuccess = false; // not enough space in buffer to hold response. } } + else + { + *pcParams = 0; + fSuccess = true; + } return fSuccess; } diff --git a/src/terminal/parser/OutputStateMachineEngine.hpp b/src/terminal/parser/OutputStateMachineEngine.hpp index b5ac240a0fad..48832f98d5f2 100644 --- a/src/terminal/parser/OutputStateMachineEngine.hpp +++ b/src/terminal/parser/OutputStateMachineEngine.hpp @@ -81,6 +81,9 @@ namespace Microsoft::Console::VirtualTerminal bool _IntermediateSpaceDispatch(const wchar_t wchAction, _In_reads_(cParams) const unsigned short* const rgusParams, const unsigned short cParams); + bool _IntermediateHashDispatch(const wchar_t wchAction, + _In_reads_(cParams) const unsigned short* const rgusParams, + const unsigned short cParams); enum VTActionCodes : wchar_t { @@ -126,7 +129,11 @@ namespace Microsoft::Console::VirtualTerminal // 'q' is overloaded - no postfix is DECLL, ' ' postfix is DECSCUSR, and '"' is DECSCA DECSCUSR_SetCursorStyle = L'q', // I believe we'll only ever implement DECSCUSR DTTERM_WindowManipulation = L't', - REP_RepeatCharacter = L'b' + REP_RepeatCharacter = L'b', + XT_PushSgr = L'{', + XT_PushSgrAlias = L'p', + XT_PopSgr = L'}', + XT_PopSgrAlias = L'q', }; enum OscActionCodes : unsigned int @@ -194,10 +201,11 @@ namespace Microsoft::Console::VirtualTerminal _Success_(return ) bool _VerifyDeviceAttributesParams(_In_reads_(cParams) const unsigned short* const rgusParams, const unsigned short cParams) const; - _Success_(return ) bool _GetPrivateModeParams(_In_reads_(cParams) const unsigned short* const rgusParams, - const unsigned short cParams, - _Out_writes_(*pcParams) DispatchTypes::PrivateModeParams* const rgPrivateModeParams, - _Inout_ size_t* const pcParams) const; + template + _Success_(return ) bool _GetTypedParams(_In_reads_(cParams) const unsigned short* const rgusParams, + const unsigned short cParams, + _Out_writes_(*pcParams) TParamType* const rgXtPushParams, + _Inout_ size_t* const pcParams) const; static const SHORT s_sDefaultTopMargin = 0; static const SHORT s_sDefaultBottomMargin = 0;