From 8e46c7f350a4d445a46f095531e02008236ab5d4 Mon Sep 17 00:00:00 2001 From: James Holderness Date: Sun, 9 Feb 2020 17:15:01 +0000 Subject: [PATCH] Add support for character sets with two character ids in the designation sequence. --- src/terminal/adapter/ITermDispatch.hpp | 4 +- src/terminal/adapter/adaptDispatch.cpp | 8 +- src/terminal/adapter/adaptDispatch.hpp | 4 +- src/terminal/adapter/termDispatch.hpp | 4 +- src/terminal/adapter/terminalOutput.cpp | 15 +++- src/terminal/adapter/terminalOutput.hpp | 4 +- .../parser/OutputStateMachineEngine.cpp | 86 ++++++++++++------- .../parser/OutputStateMachineEngine.hpp | 2 + 8 files changed, 81 insertions(+), 46 deletions(-) diff --git a/src/terminal/adapter/ITermDispatch.hpp b/src/terminal/adapter/ITermDispatch.hpp index a05c6782d81a..37049a8e1daa 100644 --- a/src/terminal/adapter/ITermDispatch.hpp +++ b/src/terminal/adapter/ITermDispatch.hpp @@ -94,8 +94,8 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch virtual bool DeviceAttributes() = 0; // DA virtual bool DesignateCodingSystem(const wchar_t codingSystem) = 0; // DOCS - virtual bool Designate94Charset(const size_t gsetNumber, const wchar_t newCharset) = 0; // SCS - virtual bool Designate96Charset(const size_t gsetNumber, const wchar_t newCharset) = 0; // SCS + virtual bool Designate94Charset(const size_t gsetNumber, const std::pair newCharset) = 0; // SCS + virtual bool Designate96Charset(const size_t gsetNumber, const std::pair newCharset) = 0; // SCS virtual bool LockingShift(const size_t gsetNumber) = 0; // LSx virtual bool LockingShiftRight(const size_t gsetNumber) = 0; // LSxR virtual bool SingleShift(const size_t gsetNumber) = 0; // SSx diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp index 682750b95b0c..0df5280096aa 100644 --- a/src/terminal/adapter/adaptDispatch.cpp +++ b/src/terminal/adapter/adaptDispatch.cpp @@ -1429,10 +1429,10 @@ bool AdaptDispatch::DesignateCodingSystem(const wchar_t codingSystem) // If the specified charset is unsupported, we do nothing (remain on the current one) //Arguments: // - gsetNumber - The G-set into which the charset will be selected. -// - newCharset - The character indicating the charset that will be used. +// - newCharset - The characters indicating the charset that will be used. // Return value: // True if handled successfully. False otherwise. -bool AdaptDispatch::Designate94Charset(const size_t gsetNumber, const wchar_t newCharset) +bool AdaptDispatch::Designate94Charset(const size_t gsetNumber, const std::pair newCharset) { return _termOutput.Designate94Charset(gsetNumber, newCharset); } @@ -1445,10 +1445,10 @@ bool AdaptDispatch::Designate94Charset(const size_t gsetNumber, const wchar_t ne //Arguments: // - gsetNumber - The G-set into which the charset will be selected. // - setSize - The size of the selected charset - 94 or 96. -// - newCharset - The character indicating the charset that will be used. +// - newCharset - The characters indicating the charset that will be used. // Return value: // True if handled successfully. False otherwise. -bool AdaptDispatch::Designate96Charset(const size_t gsetNumber, const wchar_t newCharset) +bool AdaptDispatch::Designate96Charset(const size_t gsetNumber, const std::pair newCharset) { return _termOutput.Designate96Charset(gsetNumber, newCharset); } diff --git a/src/terminal/adapter/adaptDispatch.hpp b/src/terminal/adapter/adaptDispatch.hpp index 6e95086d7150..5fdbc272c7ba 100644 --- a/src/terminal/adapter/adaptDispatch.hpp +++ b/src/terminal/adapter/adaptDispatch.hpp @@ -85,8 +85,8 @@ namespace Microsoft::Console::VirtualTerminal bool BackwardsTab(const size_t numTabs) override; // CBT bool TabClear(const size_t clearType) override; // TBC bool DesignateCodingSystem(const wchar_t codingSystem) override; // DOCS - bool Designate94Charset(const size_t gsetNumber, const wchar_t newCharset) override; // SCS - bool Designate96Charset(const size_t gsetNumber, const wchar_t newCharset) override; // SCS + bool Designate94Charset(const size_t gsetNumber, const std::pair newCharset) override; // SCS + bool Designate96Charset(const size_t gsetNumber, const std::pair newCharset) override; // SCS bool LockingShift(const size_t gsetNumber) override; // LSx bool LockingShiftRight(const size_t gsetNumber) override; // LSxR bool SingleShift(const size_t gsetNumber) override; // SSx diff --git a/src/terminal/adapter/termDispatch.hpp b/src/terminal/adapter/termDispatch.hpp index 5bc55190da3b..a9667b93dceb 100644 --- a/src/terminal/adapter/termDispatch.hpp +++ b/src/terminal/adapter/termDispatch.hpp @@ -88,8 +88,8 @@ class Microsoft::Console::VirtualTerminal::TermDispatch : public Microsoft::Cons bool DeviceAttributes() noexcept override { return false; } // DA bool DesignateCodingSystem(const wchar_t /*codingSystem*/) noexcept override { return false; } // DOCS - bool Designate94Charset(const size_t /*gsetNumber*/, const wchar_t /*newCharset*/) noexcept override { return false; } // SCS - bool Designate96Charset(const size_t /*gsetNumber*/, const wchar_t /*newCharset*/) noexcept override { return false; } // SCS + bool Designate94Charset(const size_t /*gsetNumber*/, const std::pair /*newCharset*/) noexcept override { return false; } // SCS + bool Designate96Charset(const size_t /*gsetNumber*/, const std::pair /*newCharset*/) noexcept override { return false; } // SCS bool LockingShift(const size_t /*gsetNumber*/) noexcept override { return false; } // LSx bool LockingShiftRight(const size_t /*gsetNumber*/) noexcept override { return false; } // LSxR bool SingleShift(const size_t /*gsetNumber*/) noexcept override { return false; } // SSx diff --git a/src/terminal/adapter/terminalOutput.cpp b/src/terminal/adapter/terminalOutput.cpp index ce9726ea2fd1..2a97f73db125 100644 --- a/src/terminal/adapter/terminalOutput.cpp +++ b/src/terminal/adapter/terminalOutput.cpp @@ -265,9 +265,9 @@ TerminalOutput::TerminalOutput() noexcept _gsetTranslationTables.at(3) = Latin1; } -bool TerminalOutput::Designate94Charset(size_t gsetNumber, const wchar_t newCharset) +bool TerminalOutput::Designate94Charset(size_t gsetNumber, const std::pair newCharset) { - switch (newCharset) + switch (newCharset.first) { case L'B': // US ASCII case L'1': // Alternate Character ROM @@ -302,14 +302,21 @@ bool TerminalOutput::Designate94Charset(size_t gsetNumber, const wchar_t newChar return _SetTranslationTable(gsetNumber, SwedishNrcs); case L'=': // Swiss NRCS return _SetTranslationTable(gsetNumber, SwissNrcs); + case L'%': + switch (newCharset.second) + { + case L'5': // DEC Supplemental + return _SetTranslationTable(gsetNumber, DecSupplemental); + } + return false; default: return false; } } -bool TerminalOutput::Designate96Charset(size_t gsetNumber, const wchar_t newCharset) +bool TerminalOutput::Designate96Charset(size_t gsetNumber, const std::pair newCharset) { - switch (newCharset) + switch (newCharset.first) { case L'A': // ISO Latin-1 Supplemental return _SetTranslationTable(gsetNumber, Latin1); diff --git a/src/terminal/adapter/terminalOutput.hpp b/src/terminal/adapter/terminalOutput.hpp index bf043dd7b877..2a1983d97677 100644 --- a/src/terminal/adapter/terminalOutput.hpp +++ b/src/terminal/adapter/terminalOutput.hpp @@ -26,8 +26,8 @@ namespace Microsoft::Console::VirtualTerminal TerminalOutput() noexcept; wchar_t TranslateKey(const wchar_t wch) const noexcept; - bool Designate94Charset(const size_t gsetNumber, const wchar_t newCharset); - bool Designate96Charset(const size_t gsetNumber, const wchar_t newCharset); + bool Designate94Charset(const size_t gsetNumber, const std::pair newCharset); + bool Designate96Charset(const size_t gsetNumber, const std::pair newCharset); bool LockingShift(const size_t gsetNumber); bool LockingShiftRight(const size_t gsetNumber); bool SingleShift(const size_t gsetNumber); diff --git a/src/terminal/parser/OutputStateMachineEngine.cpp b/src/terminal/parser/OutputStateMachineEngine.cpp index 3ee37f4b1ccf..4955a1d96998 100644 --- a/src/terminal/parser/OutputStateMachineEngine.cpp +++ b/src/terminal/parser/OutputStateMachineEngine.cpp @@ -265,34 +265,6 @@ bool OutputStateMachineEngine::ActionEscDispatch(const wchar_t wch, { switch (til::at(intermediates, 0)) { - case L'(': - success = _dispatch->Designate94Charset(0, wch); - TermTelemetry::Instance().Log(TermTelemetry::Codes::DesignateG0); - break; - case L')': - success = _dispatch->Designate94Charset(1, wch); - TermTelemetry::Instance().Log(TermTelemetry::Codes::DesignateG1); - break; - case L'*': - success = _dispatch->Designate94Charset(2, wch); - TermTelemetry::Instance().Log(TermTelemetry::Codes::DesignateG2); - break; - case L'+': - success = _dispatch->Designate94Charset(3, wch); - TermTelemetry::Instance().Log(TermTelemetry::Codes::DesignateG3); - break; - case L'-': - success = _dispatch->Designate96Charset(1, wch); - TermTelemetry::Instance().Log(TermTelemetry::Codes::DesignateG1); - break; - case L'.': - success = _dispatch->Designate96Charset(2, wch); - TermTelemetry::Instance().Log(TermTelemetry::Codes::DesignateG2); - break; - case L'/': - success = _dispatch->Designate96Charset(3, wch); - TermTelemetry::Instance().Log(TermTelemetry::Codes::DesignateG3); - break; case L'%': success = _dispatch->DesignateCodingSystem(wch); TermTelemetry::Instance().Log(TermTelemetry::Codes::DOCS); @@ -311,17 +283,71 @@ bool OutputStateMachineEngine::ActionEscDispatch(const wchar_t wch, } break; default: - // If no functions to call, overall dispatch was a failure. - success = false; + success = _IntermediateScsDispatch(wch, intermediates); break; } } + else if (intermediates.size() == 2) + { + success = _IntermediateScsDispatch(wch, intermediates); + } _ClearLastChar(); return success; } +// Routine Description: +// - Handles SCS charset designation actions that can have one or two possible intermediates. +// Arguments: +// - wch - Character to dispatch. +// - intermediates - Intermediate characters in the sequence +// Return Value: +// - True if handled successfully. False otherwise. +bool OutputStateMachineEngine::_IntermediateScsDispatch(const wchar_t wch, + const std::basic_string_view intermediates) +{ + bool success = false; + + // If we have more than one intermediate, the second intermediate forms part of + // the charset identifier. Otherwise it's identified by just the final character. + const auto newCharset = intermediates.size() > 1 ? std::make_pair(intermediates.at(1), wch) : std::make_pair(wch, L'\0'); + + switch (intermediates.at(0)) + { + case L'(': + success = _dispatch->Designate94Charset(0, newCharset); + TermTelemetry::Instance().Log(TermTelemetry::Codes::DesignateG0); + break; + case L')': + success = _dispatch->Designate94Charset(1, newCharset); + TermTelemetry::Instance().Log(TermTelemetry::Codes::DesignateG1); + break; + case L'*': + success = _dispatch->Designate94Charset(2, newCharset); + TermTelemetry::Instance().Log(TermTelemetry::Codes::DesignateG2); + break; + case L'+': + success = _dispatch->Designate94Charset(3, newCharset); + TermTelemetry::Instance().Log(TermTelemetry::Codes::DesignateG3); + break; + case L'-': + success = _dispatch->Designate96Charset(1, newCharset); + TermTelemetry::Instance().Log(TermTelemetry::Codes::DesignateG1); + break; + case L'.': + success = _dispatch->Designate96Charset(2, newCharset); + TermTelemetry::Instance().Log(TermTelemetry::Codes::DesignateG2); + break; + case L'/': + success = _dispatch->Designate96Charset(3, newCharset); + TermTelemetry::Instance().Log(TermTelemetry::Codes::DesignateG3); + break; + } + + return success; +} + // Routine Description: // - Triggers the CsiDispatch action to indicate that the listener should handle // a control sequence. These sequences perform various API-type commands diff --git a/src/terminal/parser/OutputStateMachineEngine.hpp b/src/terminal/parser/OutputStateMachineEngine.hpp index f71c9a7d08ae..aba4562f8097 100644 --- a/src/terminal/parser/OutputStateMachineEngine.hpp +++ b/src/terminal/parser/OutputStateMachineEngine.hpp @@ -68,6 +68,8 @@ namespace Microsoft::Console::VirtualTerminal std::function _pfnFlushToTerminal; wchar_t _lastPrintedChar; + bool _IntermediateScsDispatch(const wchar_t wch, + const std::basic_string_view intermediates); bool _IntermediateQuestionMarkDispatch(const wchar_t wchAction, const std::basic_string_view parameters); bool _IntermediateExclamationDispatch(const wchar_t wch);