diff --git a/OpenConsole.sln b/OpenConsole.sln index 910cb108eb5..a0d80b9d704 100644 --- a/OpenConsole.sln +++ b/OpenConsole.sln @@ -353,8 +353,8 @@ Global {2FD12FBB-1DDB-46D8-B818-1023C624CACA}.Release|x86.Build.0 = Release|Win32 {3AE13314-1939-4DFA-9C14-38CA0834050C}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 {3AE13314-1939-4DFA-9C14-38CA0834050C}.AuditMode|ARM64.ActiveCfg = Release|ARM64 - {3AE13314-1939-4DFA-9C14-38CA0834050C}.AuditMode|x64.ActiveCfg = Release|x64 - {3AE13314-1939-4DFA-9C14-38CA0834050C}.AuditMode|x64.Build.0 = Release|x64 + {3AE13314-1939-4DFA-9C14-38CA0834050C}.AuditMode|x64.ActiveCfg = AuditMode|x64 + {3AE13314-1939-4DFA-9C14-38CA0834050C}.AuditMode|x64.Build.0 = AuditMode|x64 {3AE13314-1939-4DFA-9C14-38CA0834050C}.AuditMode|x86.ActiveCfg = Release|Win32 {3AE13314-1939-4DFA-9C14-38CA0834050C}.Debug|Any CPU.ActiveCfg = Debug|Win32 {3AE13314-1939-4DFA-9C14-38CA0834050C}.Debug|ARM64.ActiveCfg = Debug|ARM64 @@ -372,7 +372,8 @@ Global {3AE13314-1939-4DFA-9C14-38CA0834050C}.Release|x86.Build.0 = Release|Win32 {DCF55140-EF6A-4736-A403-957E4F7430BB}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 {DCF55140-EF6A-4736-A403-957E4F7430BB}.AuditMode|ARM64.ActiveCfg = Release|ARM64 - {DCF55140-EF6A-4736-A403-957E4F7430BB}.AuditMode|x64.ActiveCfg = Release|x64 + {DCF55140-EF6A-4736-A403-957E4F7430BB}.AuditMode|x64.ActiveCfg = AuditMode|x64 + {DCF55140-EF6A-4736-A403-957E4F7430BB}.AuditMode|x64.Build.0 = AuditMode|x64 {DCF55140-EF6A-4736-A403-957E4F7430BB}.AuditMode|x86.ActiveCfg = Release|Win32 {DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|Any CPU.ActiveCfg = Debug|Win32 {DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|ARM64.ActiveCfg = Debug|ARM64 @@ -390,8 +391,8 @@ Global {DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|x86.Build.0 = Release|Win32 {1CF55140-EF6A-4736-A403-957E4F7430BB}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 {1CF55140-EF6A-4736-A403-957E4F7430BB}.AuditMode|ARM64.ActiveCfg = Release|ARM64 - {1CF55140-EF6A-4736-A403-957E4F7430BB}.AuditMode|x64.ActiveCfg = Release|x64 - {1CF55140-EF6A-4736-A403-957E4F7430BB}.AuditMode|x64.Build.0 = Release|x64 + {1CF55140-EF6A-4736-A403-957E4F7430BB}.AuditMode|x64.ActiveCfg = AuditMode|x64 + {1CF55140-EF6A-4736-A403-957E4F7430BB}.AuditMode|x64.Build.0 = AuditMode|x64 {1CF55140-EF6A-4736-A403-957E4F7430BB}.AuditMode|x86.ActiveCfg = Release|Win32 {1CF55140-EF6A-4736-A403-957E4F7430BB}.Debug|Any CPU.ActiveCfg = Debug|Win32 {1CF55140-EF6A-4736-A403-957E4F7430BB}.Debug|ARM64.ActiveCfg = Debug|ARM64 diff --git a/src/cascadia/TerminalCore/TerminalDispatch.cpp b/src/cascadia/TerminalCore/TerminalDispatch.cpp index 6b8e6215a08..bf168856406 100644 --- a/src/cascadia/TerminalCore/TerminalDispatch.cpp +++ b/src/cascadia/TerminalCore/TerminalDispatch.cpp @@ -31,7 +31,7 @@ void TerminalDispatch::PrintString(const std::wstring_view string) } bool TerminalDispatch::CursorPosition(const size_t line, - const size_t column) + const size_t column) noexcept { const auto columnInBufferSpace = column - 1; const auto lineInBufferSpace = line - 1; @@ -40,33 +40,33 @@ bool TerminalDispatch::CursorPosition(const size_t line, return _terminalApi.SetCursorPosition(x, y); } -bool TerminalDispatch::CursorForward(const size_t distance) +bool TerminalDispatch::CursorForward(const size_t distance) noexcept { const auto cursorPos = _terminalApi.GetCursorPosition(); const COORD newCursorPos{ cursorPos.X + gsl::narrow(distance), cursorPos.Y }; return _terminalApi.SetCursorPosition(newCursorPos.X, newCursorPos.Y); } -bool TerminalDispatch::CursorBackward(const size_t distance) +bool TerminalDispatch::CursorBackward(const size_t distance) noexcept { const auto cursorPos = _terminalApi.GetCursorPosition(); const COORD newCursorPos{ cursorPos.X - gsl::narrow(distance), cursorPos.Y }; return _terminalApi.SetCursorPosition(newCursorPos.X, newCursorPos.Y); } -bool TerminalDispatch::CursorUp(const size_t distance) +bool TerminalDispatch::CursorUp(const size_t distance) noexcept { const auto cursorPos = _terminalApi.GetCursorPosition(); const COORD newCursorPos{ cursorPos.X, cursorPos.Y + gsl::narrow(distance) }; return _terminalApi.SetCursorPosition(newCursorPos.X, newCursorPos.Y); } -bool TerminalDispatch::EraseCharacters(const size_t numChars) +bool TerminalDispatch::EraseCharacters(const size_t numChars) noexcept { return _terminalApi.EraseCharacters(numChars); } -bool TerminalDispatch::SetWindowTitle(std::wstring_view title) +bool TerminalDispatch::SetWindowTitle(std::wstring_view title) noexcept { return _terminalApi.SetWindowTitle(title); } @@ -79,12 +79,12 @@ bool TerminalDispatch::SetWindowTitle(std::wstring_view title) // Return Value: // True if handled successfully. False otherwise. bool TerminalDispatch::SetColorTableEntry(const size_t tableIndex, - const DWORD color) + const DWORD color) noexcept { return _terminalApi.SetColorTableEntry(tableIndex, color); } -bool TerminalDispatch::SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle) +bool TerminalDispatch::SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle) noexcept { return _terminalApi.SetCursorStyle(cursorStyle); } @@ -95,7 +95,7 @@ bool TerminalDispatch::SetCursorStyle(const DispatchTypes::CursorStyle cursorSty // - color: The new RGB color value to use, in 0x00BBGGRR form // Return Value: // True if handled successfully. False otherwise. -bool TerminalDispatch::SetDefaultForeground(const DWORD color) +bool TerminalDispatch::SetDefaultForeground(const DWORD color) noexcept { return _terminalApi.SetDefaultForeground(color); } @@ -106,7 +106,7 @@ bool TerminalDispatch::SetDefaultForeground(const DWORD color) // - color: The new RGB color value to use, in 0x00BBGGRR form // Return Value: // True if handled successfully. False otherwise. -bool TerminalDispatch::SetDefaultBackground(const DWORD color) +bool TerminalDispatch::SetDefaultBackground(const DWORD color) noexcept { return _terminalApi.SetDefaultBackground(color); } @@ -117,7 +117,7 @@ bool TerminalDispatch::SetDefaultBackground(const DWORD color) // - eraseType: the erase type (from beginning, to end, or all) // Return Value: // True if handled successfully. False otherwise. -bool TerminalDispatch::EraseInLine(const DispatchTypes::EraseType eraseType) +bool TerminalDispatch::EraseInLine(const DispatchTypes::EraseType eraseType) noexcept { return _terminalApi.EraseInLine(eraseType); } @@ -128,7 +128,7 @@ bool TerminalDispatch::EraseInLine(const DispatchTypes::EraseType eraseType) // - count, the number of characters to delete // Return Value: // True if handled successfully. False otherwise. -bool TerminalDispatch::DeleteCharacter(const size_t count) +bool TerminalDispatch::DeleteCharacter(const size_t count) noexcept { return _terminalApi.DeleteCharacter(count); } @@ -139,7 +139,7 @@ bool TerminalDispatch::DeleteCharacter(const size_t count) // - count, the number of spaces to add // Return Value: // True if handled successfully, false otherwise -bool TerminalDispatch::InsertCharacter(const size_t count) +bool TerminalDispatch::InsertCharacter(const size_t count) noexcept { return _terminalApi.InsertCharacter(count); } @@ -150,7 +150,7 @@ bool TerminalDispatch::InsertCharacter(const size_t count) // - eraseType: the desired erase type // Return Value: // True if handled successfully. False otherwise -bool TerminalDispatch::EraseInDisplay(const DispatchTypes::EraseType eraseType) +bool TerminalDispatch::EraseInDisplay(const DispatchTypes::EraseType eraseType) noexcept { return _terminalApi.EraseInDisplay(eraseType); } diff --git a/src/cascadia/TerminalCore/TerminalDispatch.hpp b/src/cascadia/TerminalCore/TerminalDispatch.hpp index df418ad886d..f9f88917434 100644 --- a/src/cascadia/TerminalCore/TerminalDispatch.hpp +++ b/src/cascadia/TerminalCore/TerminalDispatch.hpp @@ -13,27 +13,27 @@ class TerminalDispatch : public Microsoft::Console::VirtualTerminal::TermDispatc virtual void Print(const wchar_t wchPrintable) override; virtual void PrintString(const std::wstring_view string) override; - bool SetGraphicsRendition(const std::basic_string_view<::Microsoft::Console::VirtualTerminal::DispatchTypes::GraphicsOptions> options) override; + bool SetGraphicsRendition(const std::basic_string_view<::Microsoft::Console::VirtualTerminal::DispatchTypes::GraphicsOptions> options) noexcept override; virtual bool CursorPosition(const size_t line, - const size_t column) override; // CUP + const size_t column) noexcept override; // CUP - bool CursorForward(const size_t distance) override; - bool CursorBackward(const size_t distance) override; - bool CursorUp(const size_t distance) override; + bool CursorForward(const size_t distance) noexcept override; + bool CursorBackward(const size_t distance) noexcept override; + bool CursorUp(const size_t distance) noexcept override; - bool EraseCharacters(const size_t numChars) override; - bool SetWindowTitle(std::wstring_view title) override; + bool EraseCharacters(const size_t numChars) noexcept override; + bool SetWindowTitle(std::wstring_view title) noexcept override; - bool SetColorTableEntry(const size_t tableIndex, const DWORD color) override; - bool SetCursorStyle(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::CursorStyle cursorStyle) override; + bool SetColorTableEntry(const size_t tableIndex, const DWORD color) noexcept override; + bool SetCursorStyle(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::CursorStyle cursorStyle) noexcept override; - bool SetDefaultForeground(const DWORD color) override; - bool SetDefaultBackground(const DWORD color) override; - bool EraseInLine(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) override; // ED - bool DeleteCharacter(const size_t count) override; - bool InsertCharacter(const size_t count) override; - bool EraseInDisplay(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) override; + bool SetDefaultForeground(const DWORD color) noexcept override; + bool SetDefaultBackground(const DWORD color) noexcept override; + bool EraseInLine(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) noexcept override; // ED + bool DeleteCharacter(const size_t count) noexcept override; + bool InsertCharacter(const size_t count) noexcept override; + bool EraseInDisplay(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) noexcept override; private: ::Microsoft::Terminal::Core::ITerminalApi& _terminalApi; diff --git a/src/cascadia/TerminalCore/TerminalDispatchGraphics.cpp b/src/cascadia/TerminalCore/TerminalDispatchGraphics.cpp index 4e2d4ece6d7..4c85c675dd0 100644 --- a/src/cascadia/TerminalCore/TerminalDispatchGraphics.cpp +++ b/src/cascadia/TerminalCore/TerminalDispatchGraphics.cpp @@ -287,7 +287,7 @@ void TerminalDispatch::_SetGraphicsOptionHelper(const DispatchTypes::GraphicsOpt } } -bool TerminalDispatch::SetGraphicsRendition(const std::basic_string_view options) +bool TerminalDispatch::SetGraphicsRendition(const std::basic_string_view options) noexcept { bool success = false; // Run through the graphics options and apply them diff --git a/src/inc/ITerminalOutputConnection.hpp b/src/inc/ITerminalOutputConnection.hpp index 0d7569e63e7..729691be256 100644 --- a/src/inc/ITerminalOutputConnection.hpp +++ b/src/inc/ITerminalOutputConnection.hpp @@ -19,6 +19,8 @@ namespace Microsoft::Console class ITerminalOutputConnection { public: +#pragma warning(push) +#pragma warning(disable : 26432) // suppress rule of 5 violation on interface because tampering with this is fraught with peril virtual ~ITerminalOutputConnection() = 0; [[nodiscard]] virtual HRESULT WriteTerminalUtf8(const std::string_view str) = 0; @@ -26,4 +28,5 @@ namespace Microsoft::Console }; inline Microsoft::Console::ITerminalOutputConnection::~ITerminalOutputConnection() {} +#pragma warning(pop) } diff --git a/src/inc/LibraryIncludes.h b/src/inc/LibraryIncludes.h index fb65e0a8a47..3033cc1055c 100644 --- a/src/inc/LibraryIncludes.h +++ b/src/inc/LibraryIncludes.h @@ -78,6 +78,9 @@ // WRL #include +// TIL - Terminal Implementation Library +#include "til.h" + #pragma warning(pop) // clang-format on diff --git a/src/inc/til.h b/src/inc/til.h new file mode 100644 index 00000000000..d0b3ed8c7fd --- /dev/null +++ b/src/inc/til.h @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +namespace til // Terminal Implementation Library. Also: "Today I Learned" +{ + // The at function declares that you've already sufficiently checked that your array access + // is in range before retrieving an item inside it at an offset. + // This is to save double/triple/quadruple testing in circumstances where you are already + // pivoting on the length of a set and now want to pull elements out of it by offset + // without checking again. + // gsl::at will do the check again. As will .at(). And using [] will have a warning in audit. + template + constexpr auto at(T& cont, const size_t i) -> decltype(cont[cont.size()]) + { +#pragma warning(suppress : 26482) // Suppress bounds.2 check for indexing with constant expressions +#pragma warning(suppress : 26446) // Suppress bounds.4 check for subscript operator. + return cont[i]; + } +} + +// These sit outside the namespace because they sit outside for WIL too. + +// 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 \ + { \ + const bool __boolRet = wil::verify_bool(b); \ + if (!__boolRet) \ + { \ + return __boolRet; \ + } \ + } while (0, 0) + +// Due to a bug (DevDiv 441931), Warning 4297 (function marked noexcept throws exception) is detected even when the throwing code is unreachable, such as the end of scope after a return, in function-level catch. +#define CATCH_LOG_RETURN_FALSE() \ + catch (...) \ + { \ + __pragma(warning(suppress : 4297)); \ + LOG_CAUGHT_EXCEPTION(); \ + return false; \ + } diff --git a/src/terminal/adapter/DispatchCommon.cpp b/src/terminal/adapter/DispatchCommon.cpp index a7ef93f38f1..f855694ba72 100644 --- a/src/terminal/adapter/DispatchCommon.cpp +++ b/src/terminal/adapter/DispatchCommon.cpp @@ -25,17 +25,17 @@ bool DispatchCommon::s_ResizeWindow(ConGetSet& conApi, SHORT sRows = 0; // We should do nothing if 0 is passed in for a size. - bool fSuccess = SUCCEEDED(SizeTToShort(width, &sColumns)) && - SUCCEEDED(SizeTToShort(height, &sRows)) && - (width > 0 && height > 0); + bool success = SUCCEEDED(SizeTToShort(width, &sColumns)) && + SUCCEEDED(SizeTToShort(height, &sRows)) && + (width > 0 && height > 0); - if (fSuccess) + if (success) { CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); - fSuccess = !!conApi.GetConsoleScreenBufferInfoEx(csbiex); + success = conApi.GetConsoleScreenBufferInfoEx(csbiex); - if (fSuccess) + if (success) { const Viewport oldViewport = Viewport::FromInclusive(csbiex.srWindow); const Viewport newViewport = Viewport::FromDimensions(oldViewport.Origin(), @@ -51,20 +51,20 @@ bool DispatchCommon::s_ResizeWindow(ConGetSet& conApi, } // SetConsoleWindowInfo expect inclusive rects - SMALL_RECT sri = newViewport.ToInclusive(); + const auto sri = newViewport.ToInclusive(); // SetConsoleScreenBufferInfoEx however expects exclusive rects - SMALL_RECT sre = newViewport.ToExclusive(); + const auto sre = newViewport.ToExclusive(); csbiex.srWindow = sre; - fSuccess = conApi.SetConsoleScreenBufferInfoEx(csbiex); - if (fSuccess) + success = conApi.SetConsoleScreenBufferInfoEx(csbiex); + if (success) { - fSuccess = conApi.SetConsoleWindowInfo(true, sri); + success = conApi.SetConsoleWindowInfo(true, sri); } } } - return fSuccess; + return success; } // Routine Description: diff --git a/src/terminal/adapter/IInteractDispatch.hpp b/src/terminal/adapter/IInteractDispatch.hpp index d974e93b060..6110bd2575b 100644 --- a/src/terminal/adapter/IInteractDispatch.hpp +++ b/src/terminal/adapter/IInteractDispatch.hpp @@ -23,7 +23,10 @@ namespace Microsoft::Console::VirtualTerminal class IInteractDispatch { public: +#pragma warning(push) +#pragma warning(disable : 26432) // suppress rule of 5 violation on interface because tampering with this is fraught with peril virtual ~IInteractDispatch() = default; +#pragma warning(pop) virtual bool WriteInput(std::deque>& inputEvents) = 0; diff --git a/src/terminal/adapter/ITermDispatch.hpp b/src/terminal/adapter/ITermDispatch.hpp index c5bbd81494d..782c6b14d8e 100644 --- a/src/terminal/adapter/ITermDispatch.hpp +++ b/src/terminal/adapter/ITermDispatch.hpp @@ -22,7 +22,10 @@ namespace Microsoft::Console::VirtualTerminal class Microsoft::Console::VirtualTerminal::ITermDispatch { public: +#pragma warning(push) +#pragma warning(disable : 26432) // suppress rule of 5 violation on interface because tampering with this is fraught with peril virtual ~ITermDispatch() = 0; + virtual void Execute(const wchar_t wchControl) = 0; virtual void Print(const wchar_t wchPrintable) = 0; virtual void PrintString(const std::wstring_view string) = 0; @@ -97,3 +100,4 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch const std::basic_string_view parameters) = 0; }; inline Microsoft::Console::VirtualTerminal::ITermDispatch::~ITermDispatch() {} +#pragma warning(pop) diff --git a/src/terminal/adapter/InteractDispatch.cpp b/src/terminal/adapter/InteractDispatch.cpp index a78db37b18c..827dc490340 100644 --- a/src/terminal/adapter/InteractDispatch.cpp +++ b/src/terminal/adapter/InteractDispatch.cpp @@ -115,7 +115,7 @@ bool InteractDispatch::WindowManipulation(const DispatchTypes::WindowManipulatio // the ConGetSet interface, that specifically handles a conpty resize. if (parameters.size() == 2) { - success = DispatchCommon::s_ResizeWindow(*_pConApi, parameters[1], parameters[0]); + success = DispatchCommon::s_ResizeWindow(*_pConApi, til::at(parameters, 1), til::at(parameters, 0)); if (success) { DispatchCommon::s_SuppressResizeRepaint(*_pConApi); diff --git a/src/terminal/adapter/InteractDispatch.hpp b/src/terminal/adapter/InteractDispatch.hpp index 503c5cd980b..cac59f304bd 100644 --- a/src/terminal/adapter/InteractDispatch.hpp +++ b/src/terminal/adapter/InteractDispatch.hpp @@ -25,8 +25,6 @@ namespace Microsoft::Console::VirtualTerminal public: InteractDispatch(std::unique_ptr pConApi); - ~InteractDispatch() = default; - bool WriteInput(std::deque>& inputEvents) override; bool WriteCtrlC() override; bool WriteString(const std::wstring_view string) override; diff --git a/src/terminal/adapter/MouseInput.cpp b/src/terminal/adapter/MouseInput.cpp index a9dffd299a5..d08e360d8dc 100644 --- a/src/terminal/adapter/MouseInput.cpp +++ b/src/terminal/adapter/MouseInput.cpp @@ -5,50 +5,39 @@ #include #include "MouseInput.hpp" -#include "strsafe.h" -#include -#include using namespace Microsoft::Console::VirtualTerminal; -#define WIL_SUPPORT_BITOPERATION_PASCAL_NAMES -#include - #ifdef BUILD_ONECORE_INTERACTIVITY #include "..\..\interactivity\inc\VtApiRedirection.hpp" #endif // This magic flag is "documented" at https://msdn.microsoft.com/en-us/library/windows/desktop/ms646301(v=vs.85).aspx // "If the high-order bit is 1, the key is down; otherwise, it is up." -#define KEY_PRESSED 0x8000 +static constexpr short KeyPressed{ gsl::narrow_cast(0x8000) }; // Alternate scroll sequences -#define CURSOR_UP_SEQUENCE (L"\x1b[A") -#define CURSOR_DOWN_SEQUENCE (L"\x1b[B") -#define CCH_CURSOR_SEQUENCES (3) +static constexpr std::wstring_view CursorUpSequence{ L"\x1b[A" }; +static constexpr std::wstring_view CursorDownSequence{ L"\x1b[B" }; -MouseInput::MouseInput(const WriteInputEvents pfnWriteEvents) : +MouseInput::MouseInput(const WriteInputEvents pfnWriteEvents) noexcept : _pfnWriteEvents(pfnWriteEvents), - _coordLastPos{ -1, -1 }, + _lastPos{ -1, -1 }, _lastButton{ 0 } { } -MouseInput::~MouseInput() -{ -} - // Routine Description: // - Determines if the input windows message code describes a button event // (left, middle, right button and any of up, down or double click) // Also returns true for wheel events, which are buttons in *nix terminals // Parameters: -// - uiButton - the message to decode. +// - button - the message to decode. // Return value: -// - true iff uiButton is a button message to translate -bool MouseInput::s_IsButtonMsg(const unsigned int uiButton) +// - true iff button is a button message to translate +static constexpr bool _isButtonMsg(const unsigned int button) noexcept { - bool fIsButton = false; - switch (uiButton) + bool isButton = false; + switch (button) { case WM_LBUTTONDBLCLK: case WM_LBUTTONDOWN: @@ -61,34 +50,34 @@ bool MouseInput::s_IsButtonMsg(const unsigned int uiButton) case WM_MBUTTONDBLCLK: case WM_MOUSEWHEEL: case WM_MOUSEHWHEEL: - fIsButton = true; + isButton = true; break; } - return fIsButton; + return isButton; } // Routine Description: // - Determines if the input windows message code describes a hover event // Parameters: -// - uiButtonCode - the message to decode. +// - buttonCode - the message to decode. // Return value: -// - true iff uiButtonCode is a hover enent to translate -bool MouseInput::s_IsHoverMsg(const unsigned int uiButtonCode) +// - true iff buttonCode is a hover enent to translate +static constexpr bool _isHoverMsg(const unsigned int buttonCode) noexcept { - return uiButtonCode == WM_MOUSEMOVE; + return buttonCode == WM_MOUSEMOVE; } // Routine Description: // - Determines if the input windows message code describes a button press // (either down or doubleclick) // Parameters: -// - uiButton - the message to decode. +// - button - the message to decode. // Return value: -// - true iff uiButton is a button down event -bool MouseInput::s_IsButtonDown(const unsigned int uiButton) +// - true iff button is a button down event +static constexpr bool _isButtonDown(const unsigned int button) noexcept { - bool fIsButtonDown = false; - switch (uiButton) + bool isButtonDown = false; + switch (button) { case WM_LBUTTONDBLCLK: case WM_LBUTTONDOWN: @@ -98,10 +87,10 @@ bool MouseInput::s_IsButtonDown(const unsigned int uiButton) case WM_MBUTTONDBLCLK: case WM_MOUSEWHEEL: case WM_MOUSEHWHEEL: - fIsButtonDown = true; + isButtonDown = true; break; } - return fIsButtonDown; + return isButtonDown; } // Routine Description: @@ -127,51 +116,54 @@ bool MouseInput::s_IsButtonDown(const unsigned int uiButton) // so wheel up? is 64, and wheel down? is 65. // // Parameters: -// - uiButton - the message to decode. +// - button - the message to decode. +// - isHover - whether or not this is a hover event +// - modifierKeyState - alt/ctrl/shift key hold state +// - delta - scroll wheel delta // Return value: // - the int representing the equivalent X button encoding. -int MouseInput::s_WindowsButtonToXEncoding(const unsigned int uiButton, - const bool fIsHover, - const short sModifierKeystate, - const short sWheelDelta) +static constexpr int _windowsButtonToXEncoding(const unsigned int button, + const bool isHover, + const short modifierKeyState, + const short delta) noexcept { - int iXValue = 0; - switch (uiButton) + int xvalue = 0; + switch (button) { case WM_LBUTTONDBLCLK: case WM_LBUTTONDOWN: - iXValue = 0; + xvalue = 0; break; case WM_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: - iXValue = 3; + xvalue = 3; break; case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: - iXValue = 2; + xvalue = 2; break; case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: - iXValue = 1; + xvalue = 1; break; case WM_MOUSEWHEEL: case WM_MOUSEHWHEEL: - iXValue = sWheelDelta > 0 ? 0x40 : 0x41; + xvalue = delta > 0 ? 0x40 : 0x41; } - if (fIsHover) + if (isHover) { - iXValue += 0x20; + xvalue += 0x20; } // Shift will never pass through to us, because shift is used by the host to skip VT mouse and use the default handler. // TODO: MSFT:8804719 Add an option to disable/remap shift as a bypass for VT mousemode handling - // iXValue += (sModifierKeystate & MK_SHIFT) ? 0x04 : 0x00; - iXValue += (sModifierKeystate & MK_CONTROL) ? 0x08 : 0x00; + // xvalue += (modifierKeyState & MK_SHIFT) ? 0x04 : 0x00; + xvalue += (modifierKeyState & MK_CONTROL) ? 0x08 : 0x00; // Unfortunately, we don't get meta/alt as a part of mouse events. Only Ctrl and Shift. - // iXValue += (sModifierKeystate & MK_META) ? 0x10 : 0x00; + // xvalue += (modifierKeyState & MK_META) ? 0x10 : 0x00; - return iXValue; + return xvalue; } // Routine Description: @@ -181,52 +173,75 @@ int MouseInput::s_WindowsButtonToXEncoding(const unsigned int uiButton, // 3 is reserved for mouse hovers with _no_ buttons pressed. // See MSFT:19461988 and https://github.com/Microsoft/console/issues/296 // Parameters: -// - uiButton - the message to decode. +// - button - the message to decode. // Return value: // - the int representing the equivalent X button encoding. -int MouseInput::s_WindowsButtonToSGREncoding(const unsigned int uiButton, - const bool fIsHover, - const short sModifierKeystate, - const short sWheelDelta) +static constexpr int _windowsButtonToSGREncoding(const unsigned int button, + const bool isHover, + const short modifierKeyState, + const short delta) noexcept { - int iXValue = 0; - switch (uiButton) + int xvalue = 0; + switch (button) { case WM_LBUTTONDBLCLK: case WM_LBUTTONDOWN: case WM_LBUTTONUP: - iXValue = 0; + xvalue = 0; break; case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: - iXValue = 2; + xvalue = 2; break; case WM_MBUTTONUP: case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: - iXValue = 1; + xvalue = 1; break; case WM_MOUSEMOVE: - iXValue = 3; + xvalue = 3; break; case WM_MOUSEWHEEL: case WM_MOUSEHWHEEL: - iXValue = sWheelDelta > 0 ? 0x40 : 0x41; + xvalue = delta > 0 ? 0x40 : 0x41; } - if (fIsHover) + if (isHover) { - iXValue += 0x20; + xvalue += 0x20; } // Shift will never pass through to us, because shift is used by the host to skip VT mouse and use the default handler. // TODO: MSFT:8804719 Add an option to disable/remap shift as a bypass for VT mousemode handling - // iXValue += (sModifierKeystate & MK_SHIFT) ? 0x04 : 0x00; - iXValue += (sModifierKeystate & MK_CONTROL) ? 0x08 : 0x00; + // xvalue += (modifierKeyState & MK_SHIFT) ? 0x04 : 0x00; + xvalue += (modifierKeyState & MK_CONTROL) ? 0x08 : 0x00; // Unfortunately, we don't get meta/alt as a part of mouse events. Only Ctrl and Shift. - // iXValue += (sModifierKeystate & MK_META) ? 0x10 : 0x00; + // xvalue += (modifierKeyState & MK_META) ? 0x10 : 0x00; + + return xvalue; +} - return iXValue; +// Routine Description: +// - Translates the given coord from windows coordinate space (origin=0,0) to VT space (origin=1,1) +// Parameters: +// - coordWinCoordinate - the coordinate to translate +// Return value: +// - the translated coordinate. +static constexpr COORD _winToVTCoord(const COORD coordWinCoordinate) noexcept +{ + return { coordWinCoordinate.X + 1, coordWinCoordinate.Y + 1 }; +} + +// Routine Description: +// - Encodes the given value as a default (or utf-8) encoding value. +// 32 is added so that the value 0 can be emitted as the printable characher ' '. +// Parameters: +// - sCoordinateValue - the value to encode. +// Return value: +// - the encoded value. +static constexpr short _encodeDefaultCoordinate(const short sCoordinateValue) noexcept +{ + return sCoordinateValue + 32; } // Routine Description: @@ -234,185 +249,161 @@ int MouseInput::s_WindowsButtonToSGREncoding(const unsigned int uiButton, // If the event should be transmitted in the selected mouse mode, then we'll try and // encode the event according to the rules of the selected ExtendedMode, and insert those characters into the input buffer. // Parameters: -// - coordMousePosition - The windows coordinates (top,left = 0,0) of the mouse event -// - uiButton - the message to decode. -// - sModifierKeystate - the modifier keys pressed with this button -// - sWheelDelta - the amount that the scroll wheel changed (should be 0 unless uiButton is a WM_MOUSE*WHEEL) +// - position - The windows coordinates (top,left = 0,0) of the mouse event +// - button - the message to decode. +// - modifierKeyState - the modifier keys pressed with this button +// - delta - the amount that the scroll wheel changed (should be 0 unless button is a WM_MOUSE*WHEEL) // Return value: // - true if the event was handled and we should stop event propagation to the default window handler. -bool MouseInput::HandleMouse(const COORD coordMousePosition, - const unsigned int uiButton, - const short sModifierKeystate, - const short sWheelDelta) +bool MouseInput::HandleMouse(const COORD position, + const unsigned int button, + const short modifierKeyState, + const short delta) { - bool fSuccess = false; - if (_ShouldSendAlternateScroll(uiButton, sWheelDelta)) + bool success = false; + if (_ShouldSendAlternateScroll(button, delta)) { - fSuccess = _SendAlternateScroll(sWheelDelta); + success = _SendAlternateScroll(delta); } else { - fSuccess = (_TrackingMode != TrackingMode::None); - if (fSuccess) + success = (_trackingMode != TrackingMode::None); + if (success) { - // fIsHover is only true for WM_MOUSEMOVE events - const bool fIsHover = s_IsHoverMsg(uiButton); - const bool fIsButton = s_IsButtonMsg(uiButton); + // isHover is only true for WM_MOUSEMOVE events + const bool isHover = _isHoverMsg(button); + const bool isButton = _isButtonMsg(button); - const bool fSameCoord = (coordMousePosition.X == _coordLastPos.X) && - (coordMousePosition.Y == _coordLastPos.Y) && - (_lastButton == uiButton); + const bool sameCoord = (position.X == _lastPos.X) && + (position.Y == _lastPos.Y) && + (_lastButton == button); // If we have a WM_MOUSEMOVE, we need to know if any of the mouse // buttons are actually pressed. If they are, // s_GetPressedButton will return the first pressed mouse button. // If it returns WM_LBUTTONUP, then we can assume that the mouse // moved without a button being pressed. - const unsigned int uiRealButton = fIsHover ? s_GetPressedButton() : uiButton; + const unsigned int realButton = isHover ? s_GetPressedButton() : button; // In default mode, only button presses/releases are sent // In ButtonEvent mode, changing coord hovers WITH A BUTTON PRESSED // (WM_LBUTTONUP is our sentinel that no button was pressed) are also sent. // In AnyEvent, all coord change hovers are sent - const bool physicalButtonPressed = uiRealButton != WM_LBUTTONUP; + const bool physicalButtonPressed = realButton != WM_LBUTTONUP; - fSuccess = (fIsButton && _TrackingMode != TrackingMode::None) || - (fIsHover && _TrackingMode == TrackingMode::ButtonEvent && ((!fSameCoord) && (physicalButtonPressed))) || - (fIsHover && _TrackingMode == TrackingMode::AnyEvent && !fSameCoord); - if (fSuccess) + success = (isButton && _trackingMode != TrackingMode::None) || + (isHover && _trackingMode == TrackingMode::ButtonEvent && ((!sameCoord) && (physicalButtonPressed))) || + (isHover && _trackingMode == TrackingMode::AnyEvent && !sameCoord); + if (success) { - wchar_t* pwchSequence = nullptr; - size_t cchSequenceLength = 0; - switch (_ExtendedMode) + std::wstring sequence; + switch (_extendedMode) { case ExtendedMode::None: - fSuccess = _GenerateDefaultSequence(coordMousePosition, - uiRealButton, - fIsHover, - sModifierKeystate, - sWheelDelta, - &pwchSequence, - &cchSequenceLength); + sequence = _GenerateDefaultSequence(position, + realButton, + isHover, + modifierKeyState, + delta); break; case ExtendedMode::Utf8: - fSuccess = _GenerateUtf8Sequence(coordMousePosition, - uiRealButton, - fIsHover, - sModifierKeystate, - sWheelDelta, - &pwchSequence, - &cchSequenceLength); + sequence = _GenerateUtf8Sequence(position, + realButton, + isHover, + modifierKeyState, + delta); break; case ExtendedMode::Sgr: // For SGR encoding, if no physical buttons were pressed, // then we want to handle hovers with WM_MOUSEMOVE. // However, if we're dragging (WM_MOUSEMOVE with a button pressed), // then use that pressed button instead. - fSuccess = _GenerateSGRSequence(coordMousePosition, - physicalButtonPressed ? uiRealButton : uiButton, - s_IsButtonDown(uiRealButton), // Use uiRealButton here, to properly get the up/down state - fIsHover, - sModifierKeystate, - sWheelDelta, - &pwchSequence, - &cchSequenceLength); + sequence = _GenerateSGRSequence(position, + physicalButtonPressed ? realButton : button, + _isButtonDown(realButton), // Use realButton here, to properly get the up/down state + isHover, + modifierKeyState, + delta); break; case ExtendedMode::Urxvt: default: - fSuccess = false; + success = false; break; } - if (fSuccess) + + success = !sequence.empty(); + + if (success) { - _SendInputSequence(pwchSequence, cchSequenceLength); - delete[] pwchSequence; - fSuccess = true; + _SendInputSequence(sequence); + success = true; } - if (_TrackingMode == TrackingMode::ButtonEvent || _TrackingMode == TrackingMode::AnyEvent) + if (_trackingMode == TrackingMode::ButtonEvent || _trackingMode == TrackingMode::AnyEvent) { - _coordLastPos.X = coordMousePosition.X; - _coordLastPos.Y = coordMousePosition.Y; - _lastButton = uiButton; + _lastPos.X = position.X; + _lastPos.Y = position.Y; + _lastButton = button; } } } } - return fSuccess; + return success; } // Routine Description: // - Generates a sequence encoding the mouse event according to the default scheme. // see http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking // Parameters: -// - coordMousePosition - The windows coordinates (top,left = 0,0) of the mouse event -// - uiButton - the message to decode. -// - fIsHover - true if the sequence is generated in response to a mouse hover -// - sModifierKeystate - the modifier keys pressed with this button -// - sWheelDelta - the amount that the scroll wheel changed (should be 0 unless uiButton is a WM_MOUSE*WHEEL) -// - ppwchSequence - On success, where to put the pointer to the generated sequence -// - pcchLength - On success, where to put the length of the generated sequence +// - position - The windows coordinates (top,left = 0,0) of the mouse event +// - button - the message to decode. +// - isHover - true if the sequence is generated in response to a mouse hover +// - modifierKeyState - the modifier keys pressed with this button +// - delta - the amount that the scroll wheel changed (should be 0 unless button is a WM_MOUSE*WHEEL) // Return value: -// - true if we were able to successfully generate a sequence. -// On success, caller is responsible for delete[]ing *ppwchSequence. -bool MouseInput::_GenerateDefaultSequence(const COORD coordMousePosition, - const unsigned int uiButton, - const bool fIsHover, - const short sModifierKeystate, - const short sWheelDelta, - _Outptr_result_buffer_(*pcchLength) wchar_t** const ppwchSequence, - _Out_ size_t* const pcchLength) const +// - The generated sequence. Will be empty if we couldn't generate. +std::wstring MouseInput::_GenerateDefaultSequence(const COORD position, + const unsigned int button, + const bool isHover, + const short modifierKeyState, + const short delta) { - bool fSuccess = false; - // In the default, non-extended encoding scheme, coordinates above 94 shouldn't be supported, // because (95+32+1)=128, which is not an ASCII character. // There are more details in _GenerateUtf8Sequence, but basically, we can't put anything above x80 into the input // stream without bash.exe trying to convert it into utf8, and generating extra bytes in the process. - if (coordMousePosition.X <= MouseInput::s_MaxDefaultCoordinate && coordMousePosition.Y <= MouseInput::s_MaxDefaultCoordinate) + if (position.X <= MouseInput::s_MaxDefaultCoordinate && position.Y <= MouseInput::s_MaxDefaultCoordinate) { - const COORD coordVTCoords = s_WinToVTCoord(coordMousePosition); - const short sEncodedX = s_EncodeDefaultCoordinate(coordVTCoords.X); - const short sEncodedY = s_EncodeDefaultCoordinate(coordVTCoords.Y); - wchar_t* pwchFormat = new (std::nothrow) wchar_t[7]{ L"\x1b[Mbxy" }; - if (pwchFormat != nullptr) - { - pwchFormat[3] = ' ' + (short)s_WindowsButtonToXEncoding(uiButton, fIsHover, sModifierKeystate, sWheelDelta); - pwchFormat[4] = sEncodedX; - pwchFormat[5] = sEncodedY; - - *ppwchSequence = pwchFormat; - *pcchLength = 7; - fSuccess = true; - } + const COORD vtCoords = _winToVTCoord(position); + const short encodedX = _encodeDefaultCoordinate(vtCoords.X); + const short encodedY = _encodeDefaultCoordinate(vtCoords.Y); + + std::wstring format{ L"\x1b[Mbxy" }; + format.at(3) = ' ' + gsl::narrow_cast(_windowsButtonToXEncoding(button, isHover, modifierKeyState, delta)); + format.at(4) = encodedX; + format.at(5) = encodedY; + return format; } - return fSuccess; + return {}; } // Routine Description: // - Generates a sequence encoding the mouse event according to the UTF8 Extended scheme. // see http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Extended-coordinates // Parameters: -// - coordMousePosition - The windows coordinates (top,left = 0,0) of the mouse event -// - uiButton - the message to decode. -// - fIsHover - true if the sequence is generated in response to a mouse hover -// - sModifierKeystate - the modifier keys pressed with this button -// - sWheelDelta - the amount that the scroll wheel changed (should be 0 unless uiButton is a WM_MOUSE*WHEEL) -// - ppwchSequence - On success, where to put the pointer to the generated sequence -// - pcchLength - On success, where to put the length of the generated sequence +// - position - The windows coordinates (top,left = 0,0) of the mouse event +// - button - the message to decode. +// - isHover - true if the sequence is generated in response to a mouse hover +// - modifierKeyState - the modifier keys pressed with this button +// - delta - the amount that the scroll wheel changed (should be 0 unless button is a WM_MOUSE*WHEEL) // Return value: -// - true if we were able to successfully generate a sequence. -// On success, caller is responsible for delete[]ing *ppwchSequence. -bool MouseInput::_GenerateUtf8Sequence(const COORD coordMousePosition, - const unsigned int uiButton, - const bool fIsHover, - const short sModifierKeystate, - const short sWheelDelta, - _Outptr_result_buffer_(*pcchLength) wchar_t** const ppwchSequence, - _Out_ size_t* const pcchLength) const +// - The generated sequence. Will be empty if we couldn't generate. +std::wstring MouseInput::_GenerateUtf8Sequence(const COORD position, + const unsigned int button, + const bool isHover, + const short modifierKeyState, + const short delta) { - bool fSuccess = false; - // So we have some complications here. // The windows input stream is typically encoded as UTF16. // Bash.exe knows this, and converts the utf16 input, character by character, into utf8, to send to wsl. @@ -427,90 +418,51 @@ bool MouseInput::_GenerateUtf8Sequence(const COORD coordMousePosition, // So bash would also need to change, but how could it tell the difference between them? no real good way. // I'm going to emit a utf16 encoded value for now. Besides, if a windows program really wants it, just use the SGR mode, which is unambiguous. // TODO: Followup once the UTF-8 input stack is ready, MSFT:8509613 - if (coordMousePosition.X <= (SHORT_MAX - 33) && coordMousePosition.Y <= (SHORT_MAX - 33)) + if (position.X <= (SHORT_MAX - 33) && position.Y <= (SHORT_MAX - 33)) { - const COORD coordVTCoords = s_WinToVTCoord(coordMousePosition); - const short sEncodedX = s_EncodeDefaultCoordinate(coordVTCoords.X); - const short sEncodedY = s_EncodeDefaultCoordinate(coordVTCoords.Y); - wchar_t* pwchFormat = new (std::nothrow) wchar_t[7]{ L"\x1b[Mbxy" }; - if (pwchFormat != nullptr) - { - // The short cast is safe because we know s_WindowsButtonToXEncoding never returns more than xff - pwchFormat[3] = ' ' + (short)s_WindowsButtonToXEncoding(uiButton, fIsHover, sModifierKeystate, sWheelDelta); - pwchFormat[4] = sEncodedX; - pwchFormat[5] = sEncodedY; - - *ppwchSequence = pwchFormat; - *pcchLength = 7; - fSuccess = true; - } + const COORD vtCoords = _winToVTCoord(position); + const short encodedX = _encodeDefaultCoordinate(vtCoords.X); + const short encodedY = _encodeDefaultCoordinate(vtCoords.Y); + std::wstring format{ L"\x1b[Mbxy" }; + // The short cast is safe because we know s_WindowsButtonToXEncoding never returns more than xff + format.at(3) = ' ' + gsl::narrow_cast(_windowsButtonToXEncoding(button, isHover, modifierKeyState, delta)); + format.at(4) = encodedX; + format.at(5) = encodedY; + return format; } - return fSuccess; + return {}; } // Routine Description: // - Generates a sequence encoding the mouse event according to the SGR Extended scheme. // see http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Extended-coordinates // Parameters: -// - coordMousePosition - The windows coordinates (top,left = 0,0) of the mouse event -// - uiButton - the message to decode. WM_MOUSERMOVE is used for mouse hovers with no buttons pressed. +// - position - The windows coordinates (top,left = 0,0) of the mouse event +// - button - the message to decode. WM_MOUSERMOVE is used for mouse hovers with no buttons pressed. // - isDown - true iff a mouse button was pressed. -// - fIsHover - true if the sequence is generated in response to a mouse hover -// - sModifierKeystate - the modifier keys pressed with this button -// - sWheelDelta - the amount that the scroll wheel changed (should be 0 unless uiButton is a WM_MOUSE*WHEEL) +// - isHover - true if the sequence is generated in response to a mouse hover +// - modifierKeyState - the modifier keys pressed with this button +// - delta - the amount that the scroll wheel changed (should be 0 unless button is a WM_MOUSE*WHEEL) // - ppwchSequence - On success, where to put the pointer to the generated sequence // - pcchLength - On success, where to put the length of the generated sequence // Return value: // - true if we were able to successfully generate a sequence. // On success, caller is responsible for delete[]ing *ppwchSequence. -bool MouseInput::_GenerateSGRSequence(const COORD coordMousePosition, - const unsigned int uiButton, - const bool isDown, - const bool fIsHover, - const short sModifierKeystate, - const short sWheelDelta, - _Outptr_result_buffer_(*pcchLength) wchar_t** const ppwchSequence, - _Out_ size_t* const pcchLength) const +std::wstring MouseInput::_GenerateSGRSequence(const COORD position, + const unsigned int button, + const bool isDown, + const bool isHover, + const short modifierKeyState, + const short delta) { // Format for SGR events is: // "\x1b[<%d;%d;%d;%c", xButton, x+1, y+1, fButtonDown? 'M' : 'm' - bool fSuccess = false; - const int iXButton = s_WindowsButtonToSGREncoding(uiButton, fIsHover, sModifierKeystate, sWheelDelta); - -#pragma warning(push) -#pragma warning(disable : 4996) -// Disable 4996 - The _s version of _snprintf doesn't return the cch if the buffer is null, and we need the cch -#pragma prefast(suppress : 28719, "Using the output of _snwprintf to determine cch. _snwprintf_s used below.") - int iNeededChars = _snwprintf(nullptr, 0, L"\x1b[<%d;%d;%d%c", iXButton, coordMousePosition.X + 1, coordMousePosition.Y + 1, isDown ? L'M' : L'm'); - -#pragma warning(pop) + const int xbutton = _windowsButtonToSGREncoding(button, isHover, modifierKeyState, delta); - iNeededChars += 1; // for null + auto format = wil::str_printf(L"\x1b[<%d;%d;%d%c", xbutton, position.X + 1, position.Y + 1, isDown ? L'M' : L'm'); - wchar_t* pwchFormat = new (std::nothrow) wchar_t[iNeededChars]; - if (pwchFormat != nullptr) - { - int iTakenChars = _snwprintf_s(pwchFormat, - iNeededChars, - iNeededChars, - L"\x1b[<%d;%d;%d%c", - iXButton, - coordMousePosition.X + 1, - coordMousePosition.Y + 1, - isDown ? L'M' : L'm'); - if (iTakenChars == iNeededChars - 1) // again, adjust for null - { - *ppwchSequence = pwchFormat; - *pcchLength = iTakenChars; - fSuccess = true; - } - else - { - delete[] pwchFormat; - } - } - return fSuccess; + return format; } // Routine Description: @@ -519,12 +471,12 @@ bool MouseInput::_GenerateSGRSequence(const COORD coordMousePosition, // typically UTF-16 encoded, it emits a UTF-16 stream. // Does NOT enable or disable mouse mode by itself. This matches the behavior I found in Ubuntu terminals. // Parameters: -// - fEnable - either enable or disable. +// - enable - either enable or disable. // Return value: // -void MouseInput::SetUtf8ExtendedMode(const bool fEnable) +void MouseInput::SetUtf8ExtendedMode(const bool enable) noexcept { - _ExtendedMode = fEnable ? ExtendedMode::Utf8 : ExtendedMode::None; + _extendedMode = enable ? ExtendedMode::Utf8 : ExtendedMode::None; } // Routine Description: @@ -533,25 +485,25 @@ void MouseInput::SetUtf8ExtendedMode(const bool fEnable) // eg, x,y=203,504 -> "^[[ -void MouseInput::SetSGRExtendedMode(const bool fEnable) +void MouseInput::SetSGRExtendedMode(const bool enable) noexcept { - _ExtendedMode = fEnable ? ExtendedMode::Sgr : ExtendedMode::None; + _extendedMode = enable ? ExtendedMode::Sgr : ExtendedMode::None; } // Routine Description: // - Either enables or disables mouse mode handling. Leaves the extended mode alone, // so if we disable then re-enable mouse mode without toggling an extended mode, the mode will persist. // Parameters: -// - fEnable - either enable or disable. +// - enable - either enable or disable. // Return value: // -void MouseInput::EnableDefaultTracking(const bool fEnable) +void MouseInput::EnableDefaultTracking(const bool enable) noexcept { - _TrackingMode = fEnable ? TrackingMode::Default : TrackingMode::None; - _coordLastPos = { -1, -1 }; // Clear out the last saved mouse position & button. + _trackingMode = enable ? TrackingMode::Default : TrackingMode::None; + _lastPos = { -1, -1 }; // Clear out the last saved mouse position & button. _lastButton = 0; } @@ -561,13 +513,13 @@ void MouseInput::EnableDefaultTracking(const bool fEnable) // Leaves the extended mode alone, so if we disable then re-enable mouse mode // without toggling an extended mode, the mode will persist. // Parameters: -// - fEnable - either enable or disable. +// - enable - either enable or disable. // Return value: // -void MouseInput::EnableButtonEventTracking(const bool fEnable) +void MouseInput::EnableButtonEventTracking(const bool enable) noexcept { - _TrackingMode = fEnable ? TrackingMode::ButtonEvent : TrackingMode::None; - _coordLastPos = { -1, -1 }; // Clear out the last saved mouse position & button. + _trackingMode = enable ? TrackingMode::ButtonEvent : TrackingMode::None; + _lastPos = { -1, -1 }; // Clear out the last saved mouse position & button. _lastButton = 0; } @@ -577,13 +529,13 @@ void MouseInput::EnableButtonEventTracking(const bool fEnable) // Leaves the extended mode alone, so if we disable then re-enable mouse mode // without toggling an extended mode, the mode will persist. // Parameters: -// - fEnable - either enable or disable. +// - enable - either enable or disable. // Return value: // -void MouseInput::EnableAnyEventTracking(const bool fEnable) +void MouseInput::EnableAnyEventTracking(const bool enable) noexcept { - _TrackingMode = fEnable ? TrackingMode::AnyEvent : TrackingMode::None; - _coordLastPos = { -1, -1 }; // Clear out the last saved mouse position & button. + _trackingMode = enable ? TrackingMode::AnyEvent : TrackingMode::None; + _lastPos = { -1, -1 }; // Clear out the last saved mouse position & button. _lastButton = 0; } @@ -591,23 +543,19 @@ void MouseInput::EnableAnyEventTracking(const bool fEnable) // - Sends the given sequence into the input callback specified by _pfnWriteEvents. // Typically, this inserts the characters into the input buffer as KeyDown KEY_EVENTs. // Parameters: -// - pwszSequence - sequence to send to _pfnWriteEvents -// - cchLength - the length of pwszSequence +// - sequence - sequence to send to _pfnWriteEvents // Return value: // -void MouseInput::_SendInputSequence(_In_reads_(cchLength) const wchar_t* const pwszSequence, - const size_t cchLength) const +void MouseInput::_SendInputSequence(const std::wstring_view sequence) const noexcept { - size_t cch = 0; - // + 1 to max sequence length for null terminator count which is required by StringCchLengthW - if (SUCCEEDED(StringCchLengthW(pwszSequence, cchLength + 1, &cch)) && cch > 0 && cch < DWORD_MAX) + if (!sequence.empty()) { std::deque> events; try { - for (size_t i = 0; i < cch; ++i) + for (const auto& wch : sequence) { - events.push_back(std::make_unique(true, 1ui16, 0ui16, 0ui16, pwszSequence[i], 0)); + events.push_back(std::make_unique(true, 1ui16, 0ui16, 0ui16, wch, 0)); } _pfnWriteEvents(events); @@ -619,63 +567,40 @@ void MouseInput::_SendInputSequence(_In_reads_(cchLength) const wchar_t* const p } } -// Routine Description: -// - Translates the given coord from windows coordinate space (origin=0,0) to VT space (origin=1,1) -// Parameters: -// - coordWinCoordinate - the coordinate to translate -// Return value: -// - the translated coordinate. -COORD MouseInput::s_WinToVTCoord(const COORD coordWinCoordinate) -{ - return { coordWinCoordinate.X + 1, coordWinCoordinate.Y + 1 }; -} - -// Routine Description: -// - Encodes the given value as a default (or utf-8) encoding value. -// 32 is added so that the value 0 can be emitted as the printable characher ' '. -// Parameters: -// - sCoordinateValue - the value to encode. -// Return value: -// - the encoded value. -short MouseInput::s_EncodeDefaultCoordinate(const short sCoordinateValue) -{ - return sCoordinateValue + 32; -} - // Routine Description: // - Retrieves which mouse button is currently pressed. This is needed because // MOUSEMOVE events do not also tell us if any mouse buttons are pressed during the move. // Parameters: // // Return value: -// - a uiButton corresponding to any pressed mouse buttons, else WM_LBUTTONUP if none are pressed. -unsigned int MouseInput::s_GetPressedButton() +// - a button corresponding to any pressed mouse buttons, else WM_LBUTTONUP if none are pressed. +unsigned int MouseInput::s_GetPressedButton() noexcept { - unsigned int uiButton = WM_LBUTTONUP; // Will be treated as a release, or no button pressed. - if (WI_IsFlagSet(GetKeyState(VK_LBUTTON), KEY_PRESSED)) + unsigned int button = WM_LBUTTONUP; // Will be treated as a release, or no button pressed. + if (WI_IsFlagSet(GetKeyState(VK_LBUTTON), KeyPressed)) { - uiButton = WM_LBUTTONDOWN; + button = WM_LBUTTONDOWN; } - else if (WI_IsFlagSet(GetKeyState(VK_MBUTTON), KEY_PRESSED)) + else if (WI_IsFlagSet(GetKeyState(VK_MBUTTON), KeyPressed)) { - uiButton = WM_MBUTTONDOWN; + button = WM_MBUTTONDOWN; } - else if (WI_IsFlagSet(GetKeyState(VK_RBUTTON), KEY_PRESSED)) + else if (WI_IsFlagSet(GetKeyState(VK_RBUTTON), KeyPressed)) { - uiButton = WM_RBUTTONDOWN; + button = WM_RBUTTONDOWN; } - return uiButton; + return button; } // Routine Description: // - Enables alternate scroll mode. This sends Cursor Up/down sequences when in the alternate buffer // Parameters: -// - fEnable - either enable or disable. +// - enable - either enable or disable. // Return value: // -void MouseInput::EnableAlternateScroll(const bool fEnable) +void MouseInput::EnableAlternateScroll(const bool enable) noexcept { - _fAlternateScroll = fEnable; + _alternateScroll = enable; } // Routine Description: @@ -684,9 +609,9 @@ void MouseInput::EnableAlternateScroll(const bool fEnable) // // Return value: // -void MouseInput::UseAlternateScreenBuffer() +void MouseInput::UseAlternateScreenBuffer() noexcept { - _fInAlternateBuffer = true; + _inAlternateBuffer = true; } // Routine Description: @@ -695,37 +620,42 @@ void MouseInput::UseAlternateScreenBuffer() // // Return value: // -void MouseInput::UseMainScreenBuffer() +void MouseInput::UseMainScreenBuffer() noexcept { - _fInAlternateBuffer = false; + _inAlternateBuffer = false; } // Routine Description: -// - Returns true if we should translate the input event (uiButton, sScrollDelta) +// - Returns true if we should translate the input event (button, sScrollDelta) // into an alternate scroll event instead of the default scroll event, // dependiong on if alternate scroll mode is enabled and we're in the alternate buffer. // Parameters: -// - uiButton: The mouse event code of the input event -// - sScrollDelta: The scroll wheel delta of the input event +// - button: The mouse event code of the input event +// - delta: The scroll wheel delta of the input event // Return value: // True iff the alternate buffer is active and alternate scroll mode is enabled and the event is a mouse wheel event. -bool MouseInput::_ShouldSendAlternateScroll(_In_ unsigned int uiButton, _In_ short sScrollDelta) const +bool MouseInput::_ShouldSendAlternateScroll(const unsigned int button, const short delta) const noexcept { - return _fInAlternateBuffer && - _fAlternateScroll && - (uiButton == WM_MOUSEWHEEL || uiButton == WM_MOUSEHWHEEL) && sScrollDelta != 0; + return _inAlternateBuffer && + _alternateScroll && + (button == WM_MOUSEWHEEL || button == WM_MOUSEHWHEEL) && delta != 0; } // Routine Description: // - Sends a sequence to the input coresponding to cursor up / down depending on the sScrollDelta. // Parameters: -// - sScrollDelta: The scroll wheel delta of the input event +// - delta: The scroll wheel delta of the input event // Return value: // True iff the input sequence was sent successfully. -bool MouseInput::_SendAlternateScroll(_In_ short sScrollDelta) const +bool MouseInput::_SendAlternateScroll(const short delta) const noexcept { - const wchar_t* const pwchSequence = sScrollDelta > 0 ? CURSOR_UP_SEQUENCE : CURSOR_DOWN_SEQUENCE; - _SendInputSequence(pwchSequence, CCH_CURSOR_SEQUENCES); - + if (delta > 0) + { + _SendInputSequence(CursorUpSequence); + } + else + { + _SendInputSequence(CursorDownSequence); + } return true; } diff --git a/src/terminal/adapter/MouseInput.hpp b/src/terminal/adapter/MouseInput.hpp index adb1f86759a..64fc6253d4b 100644 --- a/src/terminal/adapter/MouseInput.hpp +++ b/src/terminal/adapter/MouseInput.hpp @@ -26,24 +26,23 @@ namespace Microsoft::Console::VirtualTerminal class MouseInput sealed { public: - MouseInput(const WriteInputEvents pfnWriteEvents); - ~MouseInput(); + MouseInput(const WriteInputEvents pfnWriteEvents) noexcept; - bool HandleMouse(const COORD coordMousePosition, - const unsigned int uiButton, - const short sModifierKeystate, - const short sWheelDelta); + bool HandleMouse(const COORD position, + const unsigned int button, + const short modifierKeyState, + const short delta); - void SetUtf8ExtendedMode(const bool fEnable); - void SetSGRExtendedMode(const bool fEnable); + void SetUtf8ExtendedMode(const bool enable) noexcept; + void SetSGRExtendedMode(const bool enable) noexcept; - void EnableDefaultTracking(const bool fEnable); - void EnableButtonEventTracking(const bool fEnable); - void EnableAnyEventTracking(const bool fEnable); + void EnableDefaultTracking(const bool enable) noexcept; + void EnableButtonEventTracking(const bool enable) noexcept; + void EnableAnyEventTracking(const bool enable) noexcept; - void EnableAlternateScroll(const bool fEnable); - void UseAlternateScreenBuffer(); - void UseMainScreenBuffer(); + void EnableAlternateScroll(const bool enable) noexcept; + void UseAlternateScreenBuffer() noexcept; + void UseMainScreenBuffer() noexcept; enum class ExtendedMode : unsigned int { @@ -66,57 +65,36 @@ namespace Microsoft::Console::VirtualTerminal WriteInputEvents _pfnWriteEvents; - ExtendedMode _ExtendedMode = ExtendedMode::None; - TrackingMode _TrackingMode = TrackingMode::None; + ExtendedMode _extendedMode = ExtendedMode::None; + TrackingMode _trackingMode = TrackingMode::None; - bool _fAlternateScroll = false; - bool _fInAlternateBuffer = false; + bool _alternateScroll = false; + bool _inAlternateBuffer = false; - COORD _coordLastPos; + COORD _lastPos; unsigned int _lastButton; - void _SendInputSequence(_In_reads_(cchLength) const wchar_t* const pwszSequence, const size_t cchLength) const; - bool _GenerateDefaultSequence(const COORD coordMousePosition, - const unsigned int uiButton, - const bool fIsHover, - const short sModifierKeystate, - const short sWheelDelta, - _Outptr_result_buffer_(*pcchLength) wchar_t** const ppwchSequence, - _Out_ size_t* const pcchLength) const; - bool _GenerateUtf8Sequence(const COORD coordMousePosition, - const unsigned int uiButton, - const bool fIsHover, - const short sModifierKeystate, - const short sWheelDelta, - _Outptr_result_buffer_(*pcchLength) wchar_t** const ppwchSequence, - _Out_ size_t* const pcchLength) const; - bool _GenerateSGRSequence(const COORD coordMousePosition, - const unsigned int uiButton, - const bool isDown, - const bool fIsHover, - const short sModifierKeystate, - const short sWheelDelta, - _Outptr_result_buffer_(*pcchLength) wchar_t** const ppwchSequence, - _Out_ size_t* const pcchLength) const; - - bool _ShouldSendAlternateScroll(_In_ unsigned int uiButton, _In_ short sScrollDelta) const; - bool _SendAlternateScroll(_In_ short sScrollDelta) const; - - static int s_WindowsButtonToXEncoding(const unsigned int uiButton, - const bool fIsHover, - const short sModifierKeystate, - const short sWheelDelta); - - static int s_WindowsButtonToSGREncoding(const unsigned int uiButton, - const bool fIsHover, - const short sModifierKeystate, - const short sWheelDelta); - - static bool s_IsButtonDown(const unsigned int uiButton); - static bool s_IsButtonMsg(const unsigned int uiButton); - static bool s_IsHoverMsg(const unsigned int uiButton); - static COORD s_WinToVTCoord(const COORD coordWinCoordinate); - static short s_EncodeDefaultCoordinate(const short sCoordinateValue); - static unsigned int s_GetPressedButton(); + void _SendInputSequence(const std::wstring_view sequence) const noexcept; + static std::wstring _GenerateDefaultSequence(const COORD position, + const unsigned int button, + const bool isHover, + const short modifierKeyState, + const short delta); + static std::wstring _GenerateUtf8Sequence(const COORD position, + const unsigned int button, + const bool isHover, + const short modifierKeyState, + const short delta); + static std::wstring _GenerateSGRSequence(const COORD position, + const unsigned int button, + const bool isDown, + const bool isHover, + const short modifierKeyState, + const short delta); + + bool _ShouldSendAlternateScroll(const unsigned int button, const short delta) const noexcept; + bool _SendAlternateScroll(const short delta) const noexcept; + + static unsigned int s_GetPressedButton() noexcept; }; } diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp index 63402b2dda8..a886e272d5a 100644 --- a/src/terminal/adapter/adaptDispatch.cpp +++ b/src/terminal/adapter/adaptDispatch.cpp @@ -7,6 +7,7 @@ #include "conGetSet.hpp" #include "../../types/inc/Viewport.hpp" #include "../../types/inc/utils.hpp" +#include "../../inc/unicode.hpp" using namespace Microsoft::Console::Types; using namespace Microsoft::Console::VirtualTerminal; @@ -17,7 +18,7 @@ using namespace Microsoft::Console::VirtualTerminal; // - // Return Value: // - Always false to signify we didn't handle it. -bool NoOp() +bool NoOp() noexcept { return false; } @@ -159,7 +160,7 @@ bool AdaptDispatch::_CursorMovement(const CursorDirection dir, const size_t dist break; } - if (success) + if (success && pModify) { // For up and left, we need to subtract the magnitude of the vector to get the new spot. Right/down = add. // Use safe short subtraction to prevent under/overflow. @@ -345,24 +346,31 @@ bool AdaptDispatch::_CursorMovePosition(const std::optional row, const s } else { - rowActual = csbiex.dwCursorPosition.Y - csbiex.srWindow.Top; // remember, in VT speak, this is relative to the viewport. not absolute. + // remember, in VT speak, this is relative to the viewport. not absolute. + SHORT diff = 0; + success = SUCCEEDED(ShortSub(csbiex.dwCursorPosition.Y, csbiex.srWindow.Top, &diff)) && SUCCEEDED(ShortToSizeT(diff, &rowActual)); } - if (column) + if (success) { - if (column.value() != 0) + if (column) { - columnActual = column.value() - 1; // In VT, the origin is 1,1. For our array, it's 0,0. So subtract 1. + if (column.value() != 0) + { + columnActual = column.value() - 1; // In VT, the origin is 1,1. For our array, it's 0,0. So subtract 1. + } + else + { + success = false; // The parser should never return 0 (0 maps to 1), so this is a failure condition. + } } else { - success = false; // The parser should never return 0 (0 maps to 1), so this is a failure condition. + // remember, in VT speak, this is relative to the viewport. not absolute. + SHORT diff = 0; + success = SUCCEEDED(ShortSub(csbiex.dwCursorPosition.X, csbiex.srWindow.Left, &diff)) && SUCCEEDED(ShortToSizeT(diff, &columnActual)); } } - else - { - columnActual = csbiex.dwCursorPosition.X - csbiex.srWindow.Left; // remember, in VT speak, this is relative to the viewport. not absolute. - } if (success) { @@ -672,8 +680,8 @@ bool AdaptDispatch::EraseCharacters(const size_t numChars) { const COORD startPosition = csbiex.dwCursorPosition; - const size_t remainingSpaces = csbiex.dwSize.X - startPosition.X; - const auto actualRemaining = (remainingSpaces < 0) ? 0 : remainingSpaces; + const SHORT remainingSpaces = csbiex.dwSize.X - startPosition.X; + const size_t actualRemaining = gsl::narrow_cast((remainingSpaces < 0) ? 0 : remainingSpaces); // erase at max the number of characters remaining in the line from the current position. const auto eraseLength = (numChars <= actualRemaining) ? numChars : actualRemaining; @@ -1212,7 +1220,7 @@ bool AdaptDispatch::DeleteLine(const size_t distance) // - relativeMode - set to true to use relative addressing, false for absolute addressing. // Return Value: // - True if handled successfully. False otherwise. -bool AdaptDispatch::SetOriginMode(const bool relativeMode) +bool AdaptDispatch::SetOriginMode(const bool relativeMode) noexcept { _isOriginModeRelative = relativeMode; return true; @@ -1249,7 +1257,7 @@ bool AdaptDispatch::_DoSetTopBottomScrollingMargins(const size_t topMargin, success = SUCCEEDED(SizeTToShort(topMargin, &actualTop)) && SUCCEEDED(SizeTToShort(bottomMargin, &actualBottom)); if (success) { - SHORT screenHeight = csbiex.srWindow.Bottom - csbiex.srWindow.Top; + const SHORT screenHeight = csbiex.srWindow.Bottom - csbiex.srWindow.Top; // The default top margin is line 1 if (actualTop == 0) { @@ -1442,7 +1450,7 @@ bool AdaptDispatch::TabClear(const size_t clearType) // - wchCharset - The character indicating the charset we should switch to. // Return value: // True if handled successfully. False otherwise. -bool AdaptDispatch::DesignateCharset(const wchar_t wchCharset) +bool AdaptDispatch::DesignateCharset(const wchar_t wchCharset) noexcept { return _termOutput.DesignateCharset(wchCharset); } @@ -1504,7 +1512,7 @@ bool AdaptDispatch::SoftReset() } if (success) { - DispatchTypes::GraphicsOptions opt = DispatchTypes::GraphicsOptions::Off; + const auto opt = DispatchTypes::GraphicsOptions::Off; success = SetGraphicsRendition({ &opt, 1 }); // Normal rendition. } if (success) @@ -1586,7 +1594,7 @@ bool AdaptDispatch::ScreenAlignmentPattern() { // Fill the screen with the letter E using the default attributes. auto fillPosition = COORD{ 0, csbiex.srWindow.Top }; - auto fillLength = (csbiex.srWindow.Bottom - csbiex.srWindow.Top) * csbiex.dwSize.X; + const auto fillLength = (csbiex.srWindow.Bottom - csbiex.srWindow.Top) * csbiex.dwSize.X; success = _pConApi->PrivateFillRegion(fillPosition, fillLength, L'E', false); // Reset the meta/extended attributes (but leave the colors unchanged). success = success && _pConApi->PrivateSetLegacyAttributes(0, false, false, true); @@ -1691,83 +1699,83 @@ bool AdaptDispatch::_EraseAll() // Routine Description: // - Enables or disables support for the DECCOLM escape sequence. // Arguments: -// - fEnabled - set to true to allow DECCOLM to be used, false to disallow. +// - enabled - set to true to allow DECCOLM to be used, false to disallow. // Return Value: // - True if handled successfully. False otherwise. -bool AdaptDispatch::EnableDECCOLMSupport(const bool fEnabled) +bool AdaptDispatch::EnableDECCOLMSupport(const bool enabled) noexcept { - _isDECCOLMAllowed = fEnabled; + _isDECCOLMAllowed = enabled; return true; } //Routine Description: // Enable VT200 Mouse Mode - Enables/disables the mouse input handler in default tracking mode. //Arguments: -// - fEnabled - true to enable, false to disable. +// - enabled - true to enable, false to disable. // Return value: // True if handled successfully. False otherwise. -bool AdaptDispatch::EnableVT200MouseMode(const bool fEnabled) +bool AdaptDispatch::EnableVT200MouseMode(const bool enabled) { - return _pConApi->PrivateEnableVT200MouseMode(fEnabled); + return _pConApi->PrivateEnableVT200MouseMode(enabled); } //Routine Description: // Enable UTF-8 Extended Encoding - this changes the encoding scheme for sequences // emitted by the mouse input handler. Does not enable/disable mouse mode on its own. //Arguments: -// - fEnabled - true to enable, false to disable. +// - enabled - true to enable, false to disable. // Return value: // True if handled successfully. False otherwise. -bool AdaptDispatch::EnableUTF8ExtendedMouseMode(const bool fEnabled) +bool AdaptDispatch::EnableUTF8ExtendedMouseMode(const bool enabled) { - return _pConApi->PrivateEnableUTF8ExtendedMouseMode(fEnabled); + return _pConApi->PrivateEnableUTF8ExtendedMouseMode(enabled); } //Routine Description: // Enable SGR Extended Encoding - this changes the encoding scheme for sequences // emitted by the mouse input handler. Does not enable/disable mouse mode on its own. //Arguments: -// - fEnabled - true to enable, false to disable. +// - enabled - true to enable, false to disable. // Return value: // True if handled successfully. False otherwise. -bool AdaptDispatch::EnableSGRExtendedMouseMode(const bool fEnabled) +bool AdaptDispatch::EnableSGRExtendedMouseMode(const bool enabled) { - return _pConApi->PrivateEnableSGRExtendedMouseMode(fEnabled); + return _pConApi->PrivateEnableSGRExtendedMouseMode(enabled); } //Routine Description: // Enable Button Event mode - send mouse move events WITH A BUTTON PRESSED to the input. //Arguments: -// - fEnabled - true to enable, false to disable. +// - enabled - true to enable, false to disable. // Return value: // True if handled successfully. False otherwise. -bool AdaptDispatch::EnableButtonEventMouseMode(const bool fEnabled) +bool AdaptDispatch::EnableButtonEventMouseMode(const bool enabled) { - return _pConApi->PrivateEnableButtonEventMouseMode(fEnabled); + return _pConApi->PrivateEnableButtonEventMouseMode(enabled); } //Routine Description: // Enable Any Event mode - send all mouse events to the input. //Arguments: -// - fEnabled - true to enable, false to disable. +// - enabled - true to enable, false to disable. // Return value: // True if handled successfully. False otherwise. -bool AdaptDispatch::EnableAnyEventMouseMode(const bool fEnabled) +bool AdaptDispatch::EnableAnyEventMouseMode(const bool enabled) { - return _pConApi->PrivateEnableAnyEventMouseMode(fEnabled); + return _pConApi->PrivateEnableAnyEventMouseMode(enabled); } //Routine Description: // Enable Alternate Scroll Mode - When in the Alt Buffer, send CUP and CUD on // scroll up/down events instead of the usual sequences //Arguments: -// - fEnabled - true to enable, false to disable. +// - enabled - true to enable, false to disable. // Return value: // True if handled successfully. False otherwise. -bool AdaptDispatch::EnableAlternateScroll(const bool fEnabled) +bool AdaptDispatch::EnableAlternateScroll(const bool enabled) { - return _pConApi->PrivateEnableAlternateScroll(fEnabled); + return _pConApi->PrivateEnableAlternateScroll(enabled); } //Routine Description: @@ -1957,7 +1965,7 @@ bool AdaptDispatch::WindowManipulation(const DispatchTypes::WindowManipulationTy case DispatchTypes::WindowManipulationType::ResizeWindowInCharacters: if (parameters.size() == 2) { - success = DispatchCommon::s_ResizeWindow(*_pConApi, parameters[1], parameters[0]); + success = DispatchCommon::s_ResizeWindow(*_pConApi, til::at(parameters, 1), til::at(parameters, 0)); } break; default: diff --git a/src/terminal/adapter/adaptDispatch.hpp b/src/terminal/adapter/adaptDispatch.hpp index ce7b948d09b..9ff6a98708a 100644 --- a/src/terminal/adapter/adaptDispatch.hpp +++ b/src/terminal/adapter/adaptDispatch.hpp @@ -66,7 +66,7 @@ namespace Microsoft::Console::VirtualTerminal bool SetCursorKeysMode(const bool applicationMode) override; // DECCKM bool SetKeypadMode(const bool applicationMode) override; // DECKPAM, DECKPNM bool EnableCursorBlinking(const bool enable) override; // ATT610 - bool SetOriginMode(const bool relativeMode) override; // DECOM + bool SetOriginMode(const bool relativeMode) noexcept override; // DECOM bool SetTopBottomScrollingMargins(const size_t topMargin, const size_t bottomMargin) override; // DECSTBM bool ReverseLineFeed() override; // RI @@ -77,11 +77,11 @@ namespace Microsoft::Console::VirtualTerminal bool ForwardTab(const size_t numTabs) override; // CHT bool BackwardsTab(const size_t numTabs) override; // CBT bool TabClear(const size_t clearType) override; // TBC - bool DesignateCharset(const wchar_t wchCharset) override; // DesignateCharset + bool DesignateCharset(const wchar_t wchCharset) noexcept override; // DesignateCharset bool SoftReset() override; // DECSTR bool HardReset() override; // RIS bool ScreenAlignmentPattern() override; // DECALN - bool EnableDECCOLMSupport(const bool enabled) override; // ?40 + bool EnableDECCOLMSupport(const bool enabled) noexcept override; // ?40 bool EnableVT200MouseMode(const bool enabled) override; // ?1000 bool EnableUTF8ExtendedMouseMode(const bool enabled) override; // ?1005 bool EnableSGRExtendedMouseMode(const bool enabled) override; // ?1006 @@ -133,8 +133,8 @@ namespace Microsoft::Console::VirtualTerminal bool _EraseAll(); bool _InsertDeleteHelper(const size_t count, const bool isInsert) const; bool _ScrollMovement(const ScrollDirection dir, const size_t distance) const; - static void s_DisableAllColors(WORD& attr, const bool isForeground); - static void s_ApplyColors(WORD& attr, const WORD applyThis, const bool isForeground); + static void s_DisableAllColors(WORD& attr, const bool isForeground) noexcept; + static void s_ApplyColors(WORD& attr, const WORD applyThis, const bool isForeground) noexcept; bool _DoSetTopBottomScrollingMargins(const size_t topMargin, const size_t bottomMargin); @@ -175,10 +175,5 @@ 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_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; }; } diff --git a/src/terminal/adapter/adaptDispatchGraphics.cpp b/src/terminal/adapter/adaptDispatchGraphics.cpp index d89648c2061..4b7da52bfff 100644 --- a/src/terminal/adapter/adaptDispatchGraphics.cpp +++ b/src/terminal/adapter/adaptDispatchGraphics.cpp @@ -20,7 +20,7 @@ using namespace Microsoft::Console::VirtualTerminal::DispatchTypes; // - isForeground - True if we're modifying the FOREGROUND colors. False if we're doing BACKGROUND. // Return Value: // - -void AdaptDispatch::s_DisableAllColors(WORD& attr, const bool isForeground) +void AdaptDispatch::s_DisableAllColors(WORD& attr, const bool isForeground) noexcept { if (isForeground) { @@ -42,8 +42,9 @@ void AdaptDispatch::s_DisableAllColors(WORD& attr, const bool isForeground) // upon. // Return Value: // - -void AdaptDispatch::s_ApplyColors(WORD& attr, const WORD applyThis, const bool isForeground) +void AdaptDispatch::s_ApplyColors(WORD& attr, const WORD applyThis, const bool isForeground) noexcept { +#pragma warning(suppress : 26496) // SA is wrong. This variable is assigned more than once. // Copy the new attribute to apply WORD wNewColors = applyThis; @@ -267,7 +268,7 @@ void AdaptDispatch::_SetGraphicsOptionHelper(const DispatchTypes::GraphicsOption // 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 +static constexpr bool _isExtendedTextAttribute(const DispatchTypes::GraphicsOptions opt) noexcept { // TODO:GH#2916 add support for DoublyUnderlined, Faint(RGBColorOrFaint). // These two are currently partially implemented as other things: @@ -291,7 +292,7 @@ bool AdaptDispatch::s_IsExtendedTextAttribute(const DispatchTypes::GraphicsOptio // These are followed by up to 4 more values which compose the entire option. // Return Value: // - true if the opt is the indicator for an extended color sequence, false otherwise. -bool AdaptDispatch::s_IsRgbColorOption(const DispatchTypes::GraphicsOptions opt) +static constexpr bool _isRgbColorOption(const DispatchTypes::GraphicsOptions opt) noexcept { return opt == DispatchTypes::GraphicsOptions::ForegroundExtended || opt == DispatchTypes::GraphicsOptions::BackgroundExtended; @@ -302,7 +303,7 @@ bool AdaptDispatch::s_IsRgbColorOption(const DispatchTypes::GraphicsOptions opt) // These are followed by up to 4 more values which compose the entire option. // Return Value: // - true if the opt is the indicator for an extended color sequence, false otherwise. -bool AdaptDispatch::s_IsBoldColorOption(const DispatchTypes::GraphicsOptions opt) noexcept +static constexpr bool _isBoldColorOption(const DispatchTypes::GraphicsOptions opt) noexcept { return opt == DispatchTypes::GraphicsOptions::BoldBright || opt == DispatchTypes::GraphicsOptions::UnBold; @@ -313,7 +314,7 @@ bool AdaptDispatch::s_IsBoldColorOption(const DispatchTypes::GraphicsOptions opt //the default attributes. // Return Value: // - true if the opt sets either/or attribute to the defaults, false otherwise. -bool AdaptDispatch::s_IsDefaultColorOption(const DispatchTypes::GraphicsOptions opt) noexcept +static constexpr bool _isDefaultColorOption(const DispatchTypes::GraphicsOptions opt) noexcept { return opt == DispatchTypes::GraphicsOptions::Off || opt == DispatchTypes::GraphicsOptions::ForegroundDefault || @@ -344,11 +345,11 @@ bool AdaptDispatch::_SetRgbColorsHelper(const std::basic_string_view= 2 && s_IsRgbColorOption(options.at(0))) + if (options.size() >= 2 && _isRgbColorOption(til::at(options, 0))) { optionsConsumed = 2; - DispatchTypes::GraphicsOptions extendedOpt = options.at(0); - DispatchTypes::GraphicsOptions typeOpt = options.at(1); + const auto extendedOpt = til::at(options, 0); + const auto typeOpt = til::at(options, 1); if (extendedOpt == DispatchTypes::GraphicsOptions::ForegroundExtended) { @@ -363,9 +364,9 @@ bool AdaptDispatch::_SetRgbColorsHelper(const std::basic_string_view(options.at(2)), 255u); - unsigned int green = std::min(static_cast(options.at(3)), 255u); - unsigned int blue = std::min(static_cast(options.at(4)), 255u); + unsigned int red = std::min(static_cast(til::at(options, 2)), 255u); + unsigned int green = std::min(static_cast(til::at(options, 3)), 255u); + unsigned int blue = std::min(static_cast(til::at(options, 4)), 255u); rgbColor = RGB(red, green, blue); @@ -374,9 +375,9 @@ bool AdaptDispatch::_SetRgbColorsHelper(const std::basic_string_view= 3) { optionsConsumed = 3; - if (options.at(2) <= 255) // ensure that the provided index is on the table + if (til::at(options, 2) <= 255) // ensure that the provided index is on the table { - unsigned int tableIndex = options.at(2); + const auto tableIndex = til::at(options, 2); success = _pConApi->SetConsoleXtermTextAttribute(tableIndex, isForeground); } @@ -487,22 +488,22 @@ bool AdaptDispatch::SetGraphicsRendition(const std::basic_string_viewadapter TerminalAdapter ConTermAdapt - StaticLibrary + StaticLibrary @@ -48,4 +48,4 @@ - + \ No newline at end of file diff --git a/src/terminal/adapter/lib/adapter.vcxproj.filters b/src/terminal/adapter/lib/adapter.vcxproj.filters index 72098e2e432..5fef08ea49d 100644 --- a/src/terminal/adapter/lib/adapter.vcxproj.filters +++ b/src/terminal/adapter/lib/adapter.vcxproj.filters @@ -21,9 +21,6 @@ Source Files - - Source Files - Source Files @@ -36,6 +33,12 @@ Source Files + + Source Files + + + Source Files + Source Files @@ -56,9 +59,6 @@ Header Files - - Header Files - Header Files @@ -68,5 +68,26 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + \ No newline at end of file diff --git a/src/terminal/adapter/termDispatch.hpp b/src/terminal/adapter/termDispatch.hpp index 4ac7cc4b7b9..fe889a1b316 100644 --- a/src/terminal/adapter/termDispatch.hpp +++ b/src/terminal/adapter/termDispatch.hpp @@ -24,72 +24,72 @@ class Microsoft::Console::VirtualTerminal::TermDispatch : public Microsoft::Cons void Print(const wchar_t wchPrintable) override = 0; void PrintString(const std::wstring_view string) override = 0; - bool CursorUp(const size_t /*distance*/) override { return false; } // CUU - bool CursorDown(const size_t /*distance*/) override { return false; } // CUD - bool CursorForward(const size_t /*distance*/) override { return false; } // CUF - bool CursorBackward(const size_t /*distance*/) override { return false; } // CUB - bool CursorNextLine(const size_t /*distance*/) override { return false; } // CNL - bool CursorPrevLine(const size_t /*distance*/) override { return false; } // CPL - bool CursorHorizontalPositionAbsolute(const size_t /*column*/) override { return false; } // CHA - bool VerticalLinePositionAbsolute(const size_t /*line*/) override { return false; } // VPA - bool CursorPosition(const size_t /*line*/, const size_t /*column*/) override { return false; } // CUP - bool CursorSaveState() override { return false; } // DECSC - bool CursorRestoreState() override { return false; } // DECRC - bool CursorVisibility(const bool /*isVisible*/) override { return false; } // DECTCEM - bool InsertCharacter(const size_t /*count*/) override { return false; } // ICH - bool DeleteCharacter(const size_t /*count*/) override { return false; } // DCH - bool ScrollUp(const size_t /*distance*/) override { return false; } // SU - bool ScrollDown(const size_t /*distance*/) override { return false; } // SD - bool InsertLine(const size_t /*distance*/) override { return false; } // IL - bool DeleteLine(const size_t /*distance*/) override { return false; } // DL - bool SetColumns(const size_t /*columns*/) override { return false; } // DECSCPP, DECCOLM - bool SetCursorKeysMode(const bool /*applicationMode*/) override { return false; } // DECCKM - bool SetKeypadMode(const bool /*applicationMode*/) override { return false; } // DECKPAM, DECKPNM - bool EnableCursorBlinking(const bool /*enable*/) override { return false; } // ATT610 - bool SetOriginMode(const bool /*relativeMode*/) override { return false; }; // DECOM - bool SetTopBottomScrollingMargins(const size_t /*topMargin*/, const size_t /*bottomMargin*/) override { return false; } // DECSTBM - bool ReverseLineFeed() override { return false; } // RI - bool SetWindowTitle(std::wstring_view /*title*/) override { return false; } // OscWindowTitle - bool UseAlternateScreenBuffer() override { return false; } // ASBSET - bool UseMainScreenBuffer() override { return false; } // ASBRST - bool HorizontalTabSet() override { return false; } // HTS - bool ForwardTab(const size_t /*numTabs*/) override { return false; } // CHT - bool BackwardsTab(const size_t /*numTabs*/) override { return false; } // CBT - bool TabClear(const size_t /*clearType*/) override { return false; } // TBC - bool EnableDECCOLMSupport(const bool /*enabled*/) override { return false; } // ?40 - bool EnableVT200MouseMode(const bool /*enabled*/) override { return false; } // ?1000 - bool EnableUTF8ExtendedMouseMode(const bool /*enabled*/) override { return false; } // ?1005 - bool EnableSGRExtendedMouseMode(const bool /*enabled*/) override { return false; } // ?1006 - bool EnableButtonEventMouseMode(const bool /*enabled*/) override { return false; } // ?1002 - bool EnableAnyEventMouseMode(const bool /*enabled*/) override { return false; } // ?1003 - bool EnableAlternateScroll(const bool /*enabled*/) override { return false; } // ?1007 - bool SetColorTableEntry(const size_t /*tableIndex*/, const DWORD /*color*/) override { return false; } // OSCColorTable - bool SetDefaultForeground(const DWORD /*color*/) override { return false; } // OSCDefaultForeground - bool SetDefaultBackground(const DWORD /*color*/) override { return false; } // OSCDefaultBackground + bool CursorUp(const size_t /*distance*/) noexcept override { return false; } // CUU + bool CursorDown(const size_t /*distance*/) noexcept override { return false; } // CUD + bool CursorForward(const size_t /*distance*/) noexcept override { return false; } // CUF + bool CursorBackward(const size_t /*distance*/) noexcept override { return false; } // CUB + bool CursorNextLine(const size_t /*distance*/) noexcept override { return false; } // CNL + bool CursorPrevLine(const size_t /*distance*/) noexcept override { return false; } // CPL + bool CursorHorizontalPositionAbsolute(const size_t /*column*/) noexcept override { return false; } // CHA + bool VerticalLinePositionAbsolute(const size_t /*line*/) noexcept override { return false; } // VPA + bool CursorPosition(const size_t /*line*/, const size_t /*column*/) noexcept override { return false; } // CUP + bool CursorSaveState() noexcept override { return false; } // DECSC + bool CursorRestoreState() noexcept override { return false; } // DECRC + bool CursorVisibility(const bool /*isVisible*/) noexcept override { return false; } // DECTCEM + bool InsertCharacter(const size_t /*count*/) noexcept override { return false; } // ICH + bool DeleteCharacter(const size_t /*count*/) noexcept override { return false; } // DCH + bool ScrollUp(const size_t /*distance*/) noexcept override { return false; } // SU + bool ScrollDown(const size_t /*distance*/) noexcept override { return false; } // SD + bool InsertLine(const size_t /*distance*/) noexcept override { return false; } // IL + bool DeleteLine(const size_t /*distance*/) noexcept override { return false; } // DL + bool SetColumns(const size_t /*columns*/) noexcept override { return false; } // DECSCPP, DECCOLM + bool SetCursorKeysMode(const bool /*applicationMode*/) noexcept override { return false; } // DECCKM + bool SetKeypadMode(const bool /*applicationMode*/) noexcept override { return false; } // DECKPAM, DECKPNM + bool EnableCursorBlinking(const bool /*enable*/) noexcept override { return false; } // ATT610 + bool SetOriginMode(const bool /*relativeMode*/) noexcept override { return false; }; // DECOM + bool SetTopBottomScrollingMargins(const size_t /*topMargin*/, const size_t /*bottomMargin*/) noexcept override { return false; } // DECSTBM + bool ReverseLineFeed() noexcept override { return false; } // RI + bool SetWindowTitle(std::wstring_view /*title*/) noexcept override { return false; } // OscWindowTitle + bool UseAlternateScreenBuffer() noexcept override { return false; } // ASBSET + bool UseMainScreenBuffer() noexcept override { return false; } // ASBRST + bool HorizontalTabSet() noexcept override { return false; } // HTS + bool ForwardTab(const size_t /*numTabs*/) noexcept override { return false; } // CHT + bool BackwardsTab(const size_t /*numTabs*/) noexcept override { return false; } // CBT + bool TabClear(const size_t /*clearType*/) noexcept override { return false; } // TBC + bool EnableDECCOLMSupport(const bool /*enabled*/) noexcept override { return false; } // ?40 + bool EnableVT200MouseMode(const bool /*enabled*/) noexcept override { return false; } // ?1000 + bool EnableUTF8ExtendedMouseMode(const bool /*enabled*/) noexcept override { return false; } // ?1005 + bool EnableSGRExtendedMouseMode(const bool /*enabled*/) noexcept override { return false; } // ?1006 + bool EnableButtonEventMouseMode(const bool /*enabled*/) noexcept override { return false; } // ?1002 + bool EnableAnyEventMouseMode(const bool /*enabled*/) noexcept override { return false; } // ?1003 + bool EnableAlternateScroll(const bool /*enabled*/) noexcept override { return false; } // ?1007 + bool SetColorTableEntry(const size_t /*tableIndex*/, const DWORD /*color*/) noexcept override { return false; } // OSCColorTable + bool SetDefaultForeground(const DWORD /*color*/) noexcept override { return false; } // OSCDefaultForeground + bool SetDefaultBackground(const DWORD /*color*/) noexcept override { return false; } // OSCDefaultBackground - bool EraseInDisplay(const DispatchTypes::EraseType /* eraseType*/) override { return false; } // ED - bool EraseInLine(const DispatchTypes::EraseType /* eraseType*/) override { return false; } // EL - bool EraseCharacters(const size_t /*numChars*/) override { return false; } // ECH + bool EraseInDisplay(const DispatchTypes::EraseType /* eraseType*/) noexcept override { return false; } // ED + bool EraseInLine(const DispatchTypes::EraseType /* eraseType*/) noexcept override { return false; } // EL + bool EraseCharacters(const size_t /*numChars*/) noexcept override { return false; } // ECH - bool SetGraphicsRendition(const std::basic_string_view /*options*/) override { return false; } // SGR + bool SetGraphicsRendition(const std::basic_string_view /*options*/) noexcept override { return false; } // SGR - bool SetPrivateModes(const std::basic_string_view /*params*/) override { return false; } // DECSET + bool SetPrivateModes(const std::basic_string_view /*params*/) noexcept override { return false; } // DECSET - bool ResetPrivateModes(const std::basic_string_view /*params*/) override { return false; } // DECRST + bool ResetPrivateModes(const std::basic_string_view /*params*/) noexcept override { return false; } // DECRST - bool DeviceStatusReport(const DispatchTypes::AnsiStatusType /*statusType*/) override { return false; } // DSR - bool DeviceAttributes() override { return false; } // DA + bool DeviceStatusReport(const DispatchTypes::AnsiStatusType /*statusType*/) noexcept override { return false; } // DSR + bool DeviceAttributes() noexcept override { return false; } // DA - bool DesignateCharset(const wchar_t /*wchCharset*/) override { return false; } // DesignateCharset + bool DesignateCharset(const wchar_t /*wchCharset*/) noexcept override { return false; } // DesignateCharset - bool SoftReset() override { return false; } // DECSTR - bool HardReset() override { return false; } // RIS - bool ScreenAlignmentPattern() override { return false; } // DECALN + bool SoftReset() noexcept override { return false; } // DECSTR + bool HardReset() noexcept override { return false; } // RIS + bool ScreenAlignmentPattern() noexcept override { return false; } // DECALN - bool SetCursorStyle(const DispatchTypes::CursorStyle /*cursorStyle*/) override { return false; } // DECSCUSR - bool SetCursorColor(const COLORREF /*color*/) override { return false; } // OSCSetCursorColor, OSCResetCursorColor + bool SetCursorStyle(const DispatchTypes::CursorStyle /*cursorStyle*/) noexcept override { return false; } // DECSCUSR + bool SetCursorColor(const COLORREF /*color*/) noexcept override { return false; } // OSCSetCursorColor, OSCResetCursorColor // DTTERM_WindowManipulation bool WindowManipulation(const DispatchTypes::WindowManipulationType /*function*/, - const std::basic_string_view /*params*/) override { return false; } + const std::basic_string_view /*params*/) noexcept override { return false; } }; diff --git a/src/terminal/adapter/terminalOutput.cpp b/src/terminal/adapter/terminalOutput.cpp index 978ab002234..8af9a3bbc2f 100644 --- a/src/terminal/adapter/terminalOutput.cpp +++ b/src/terminal/adapter/terminalOutput.cpp @@ -8,18 +8,10 @@ using namespace Microsoft::Console::VirtualTerminal; -TerminalOutput::TerminalOutput() -{ -} - -TerminalOutput::~TerminalOutput() -{ -} - // We include a full table so all we have to do is the lookup. // The tables only ever change the values x20 - x7f, hence why the table starts at \x20 // From http://vt100.net/docs/vt220-rm/table2-4.html -const wchar_t TerminalOutput::s_rgDECSpecialGraphicsTranslations[s_uiNumDisplayCharacters]{ +static constexpr std::array s_decSpecialGraphicsTranslations{ L'\x20', L'\x21', L'\x22', @@ -118,13 +110,13 @@ const wchar_t TerminalOutput::s_rgDECSpecialGraphicsTranslations[s_uiNumDisplayC L'\x7f' // L'\x7f', -> DEL }; -bool TerminalOutput::DesignateCharset(const wchar_t wchNewCharset) +bool TerminalOutput::DesignateCharset(const wchar_t newCharset) noexcept { bool result = false; - if (wchNewCharset == DispatchTypes::VTCharacterSets::DEC_LineDrawing || - wchNewCharset == DispatchTypes::VTCharacterSets::USASCII) + if (newCharset == DispatchTypes::VTCharacterSets::DEC_LineDrawing || + newCharset == DispatchTypes::VTCharacterSets::USASCII) { - _wchCurrentCharset = wchNewCharset; + _currentCharset = newCharset; result = true; } return result; @@ -136,37 +128,35 @@ bool TerminalOutput::DesignateCharset(const wchar_t wchNewCharset) // - // Return Value: // - True if the current charset is not USASCII -bool TerminalOutput::NeedToTranslate() const +bool TerminalOutput::NeedToTranslate() const noexcept { - return _wchCurrentCharset != DispatchTypes::VTCharacterSets::USASCII; + return _currentCharset != DispatchTypes::VTCharacterSets::USASCII; } -const wchar_t* TerminalOutput::_GetTranslationTable() const +const std::wstring_view TerminalOutput::_GetTranslationTable() const noexcept { - const wchar_t* pwchTranslation = nullptr; - switch (_wchCurrentCharset) + switch (_currentCharset) { case DispatchTypes::VTCharacterSets::DEC_LineDrawing: - pwchTranslation = TerminalOutput::s_rgDECSpecialGraphicsTranslations; - break; + return { s_decSpecialGraphicsTranslations.data(), s_decSpecialGraphicsTranslations.size() }; } - return pwchTranslation; + return {}; } -wchar_t TerminalOutput::TranslateKey(const wchar_t wch) const +wchar_t TerminalOutput::TranslateKey(const wchar_t wch) const noexcept { wchar_t wchFound = wch; - if (_wchCurrentCharset == DispatchTypes::VTCharacterSets::USASCII || + if (_currentCharset == DispatchTypes::VTCharacterSets::USASCII || wch < '\x5f' || wch > '\x7f') // filter out the region we know is unchanged { ; // do nothing, these are the same as default. } else { - const wchar_t* pwchTranslationTable = _GetTranslationTable(); - if (pwchTranslationTable != nullptr) + const auto translationTable = _GetTranslationTable(); + if (!translationTable.empty()) { - wchFound = (pwchTranslationTable[wch - '\x20']); + wchFound = translationTable.at(wch - '\x20'); } } return wchFound; diff --git a/src/terminal/adapter/terminalOutput.hpp b/src/terminal/adapter/terminalOutput.hpp index 33d8deb79f4..c0dbb89367d 100644 --- a/src/terminal/adapter/terminalOutput.hpp +++ b/src/terminal/adapter/terminalOutput.hpp @@ -23,20 +23,15 @@ namespace Microsoft::Console::VirtualTerminal class TerminalOutput sealed { public: - TerminalOutput(); - ~TerminalOutput(); + TerminalOutput() = default; - wchar_t TranslateKey(const wchar_t wch) const; - bool DesignateCharset(const wchar_t wchNewCharset); - bool NeedToTranslate() const; + wchar_t TranslateKey(const wchar_t wch) const noexcept; + bool DesignateCharset(const wchar_t wchNewCharset) noexcept; + bool NeedToTranslate() const noexcept; private: - wchar_t _wchCurrentCharset = DispatchTypes::VTCharacterSets::USASCII; + wchar_t _currentCharset = DispatchTypes::VTCharacterSets::USASCII; - // The tables only ever change the values x20 - x7f (96 display characters) - static const unsigned int s_uiNumDisplayCharacters = 96; - static const wchar_t s_rgDECSpecialGraphicsTranslations[s_uiNumDisplayCharacters]; - - const wchar_t* _GetTranslationTable() const; + const std::wstring_view _GetTranslationTable() const noexcept; }; } diff --git a/src/terminal/input/terminalInput.cpp b/src/terminal/input/terminalInput.cpp index 58164349b88..febd7ac2b36 100644 --- a/src/terminal/input/terminalInput.cpp +++ b/src/terminal/input/terminalInput.cpp @@ -27,50 +27,68 @@ TerminalInput::TerminalInput(_In_ std::function s_cursorKeysNormalMapping = { + TermKeyMap{ VK_UP, L"\x1b[A" }, + TermKeyMap{ VK_DOWN, L"\x1b[B" }, + TermKeyMap{ VK_RIGHT, L"\x1b[C" }, + TermKeyMap{ VK_LEFT, L"\x1b[D" }, + TermKeyMap{ VK_HOME, L"\x1b[H" }, + TermKeyMap{ VK_END, L"\x1b[F" }, }; -const TerminalInput::_TermKeyMap TerminalInput::s_rgCursorKeysApplicationMapping[]{ - { VK_UP, L"\x1bOA" }, - { VK_DOWN, L"\x1bOB" }, - { VK_RIGHT, L"\x1bOC" }, - { VK_LEFT, L"\x1bOD" }, - { VK_HOME, L"\x1bOH" }, - { VK_END, L"\x1bOF" }, +static constexpr std::array s_cursorKeysApplicationMapping{ + TermKeyMap{ VK_UP, L"\x1bOA" }, + TermKeyMap{ VK_DOWN, L"\x1bOB" }, + TermKeyMap{ VK_RIGHT, L"\x1bOC" }, + TermKeyMap{ VK_LEFT, L"\x1bOD" }, + TermKeyMap{ VK_HOME, L"\x1bOH" }, + TermKeyMap{ VK_END, L"\x1bOF" }, }; -const TerminalInput::_TermKeyMap TerminalInput::s_rgKeypadNumericMapping[]{ - // HEY YOU. UPDATE THE MAX LENGTH DEF WHEN YOU MAKE CHANGES HERE. - { VK_TAB, L"\x09" }, - { VK_BACK, L"\x7f" }, - { VK_PAUSE, L"\x1a" }, - { VK_ESCAPE, L"\x1b" }, - { VK_INSERT, L"\x1b[2~" }, - { VK_DELETE, L"\x1b[3~" }, - { VK_PRIOR, L"\x1b[5~" }, - { VK_NEXT, L"\x1b[6~" }, - { VK_F1, L"\x1bOP" }, // also \x1b[11~, PuTTY uses \x1b\x1b[A - { VK_F2, L"\x1bOQ" }, // also \x1b[12~, PuTTY uses \x1b\x1b[B - { VK_F3, L"\x1bOR" }, // also \x1b[13~, PuTTY uses \x1b\x1b[C - { VK_F4, L"\x1bOS" }, // also \x1b[14~, PuTTY uses \x1b\x1b[D - { VK_F5, L"\x1b[15~" }, - { VK_F6, L"\x1b[17~" }, - { VK_F7, L"\x1b[18~" }, - { VK_F8, L"\x1b[19~" }, - { VK_F9, L"\x1b[20~" }, - { VK_F10, L"\x1b[21~" }, - { VK_F11, L"\x1b[23~" }, - { VK_F12, L"\x1b[24~" }, +static constexpr std::array s_keypadNumericMapping{ + TermKeyMap{ VK_TAB, L"\x09" }, + TermKeyMap{ VK_BACK, L"\x7f" }, + TermKeyMap{ VK_PAUSE, L"\x1a" }, + TermKeyMap{ VK_ESCAPE, L"\x1b" }, + TermKeyMap{ VK_INSERT, L"\x1b[2~" }, + TermKeyMap{ VK_DELETE, L"\x1b[3~" }, + TermKeyMap{ VK_PRIOR, L"\x1b[5~" }, + TermKeyMap{ VK_NEXT, L"\x1b[6~" }, + TermKeyMap{ VK_F1, L"\x1bOP" }, // also \x1b[11~, PuTTY uses \x1b\x1b[A + TermKeyMap{ VK_F2, L"\x1bOQ" }, // also \x1b[12~, PuTTY uses \x1b\x1b[B + TermKeyMap{ VK_F3, L"\x1bOR" }, // also \x1b[13~, PuTTY uses \x1b\x1b[C + TermKeyMap{ VK_F4, L"\x1bOS" }, // also \x1b[14~, PuTTY uses \x1b\x1b[D + TermKeyMap{ VK_F5, L"\x1b[15~" }, + TermKeyMap{ VK_F6, L"\x1b[17~" }, + TermKeyMap{ VK_F7, L"\x1b[18~" }, + TermKeyMap{ VK_F8, L"\x1b[19~" }, + TermKeyMap{ VK_F9, L"\x1b[20~" }, + TermKeyMap{ VK_F10, L"\x1b[21~" }, + TermKeyMap{ VK_F11, L"\x1b[23~" }, + TermKeyMap{ VK_F12, L"\x1b[24~" }, }; //Application mode - Some terminals support both a "Numeric" input mode, and an "Application" mode @@ -82,28 +100,27 @@ const TerminalInput::_TermKeyMap TerminalInput::s_rgKeypadNumericMapping[]{ //It seems to me as though this was used for early numpad implementations, where presently numlock would enable // "numeric" mode, outputting the numbers on the keys, while "application" mode does things like pgup/down, arrow keys, etc. //These keys aren't translated at all in numeric mode, so I figured I'd leave them out of the numeric table. -const TerminalInput::_TermKeyMap TerminalInput::s_rgKeypadApplicationMapping[]{ - // HEY YOU. UPDATE THE MAX LENGTH DEF WHEN YOU MAKE CHANGES HERE. - { VK_TAB, L"\x09" }, - { VK_BACK, L"\x7f" }, - { VK_PAUSE, L"\x1a" }, - { VK_ESCAPE, L"\x1b" }, - { VK_INSERT, L"\x1b[2~" }, - { VK_DELETE, L"\x1b[3~" }, - { VK_PRIOR, L"\x1b[5~" }, - { VK_NEXT, L"\x1b[6~" }, - { VK_F1, L"\x1bOP" }, // also \x1b[11~, PuTTY uses \x1b\x1b[A - { VK_F2, L"\x1bOQ" }, // also \x1b[12~, PuTTY uses \x1b\x1b[B - { VK_F3, L"\x1bOR" }, // also \x1b[13~, PuTTY uses \x1b\x1b[C - { VK_F4, L"\x1bOS" }, // also \x1b[14~, PuTTY uses \x1b\x1b[D - { VK_F5, L"\x1b[15~" }, - { VK_F6, L"\x1b[17~" }, - { VK_F7, L"\x1b[18~" }, - { VK_F8, L"\x1b[19~" }, - { VK_F9, L"\x1b[20~" }, - { VK_F10, L"\x1b[21~" }, - { VK_F11, L"\x1b[23~" }, - { VK_F12, L"\x1b[24~" }, +static constexpr std::array s_keypadApplicationMapping{ + TermKeyMap{ VK_TAB, L"\x09" }, + TermKeyMap{ VK_BACK, L"\x7f" }, + TermKeyMap{ VK_PAUSE, L"\x1a" }, + TermKeyMap{ VK_ESCAPE, L"\x1b" }, + TermKeyMap{ VK_INSERT, L"\x1b[2~" }, + TermKeyMap{ VK_DELETE, L"\x1b[3~" }, + TermKeyMap{ VK_PRIOR, L"\x1b[5~" }, + TermKeyMap{ VK_NEXT, L"\x1b[6~" }, + TermKeyMap{ VK_F1, L"\x1bOP" }, // also \x1b[11~, PuTTY uses \x1b\x1b[A + TermKeyMap{ VK_F2, L"\x1bOQ" }, // also \x1b[12~, PuTTY uses \x1b\x1b[B + TermKeyMap{ VK_F3, L"\x1bOR" }, // also \x1b[13~, PuTTY uses \x1b\x1b[C + TermKeyMap{ VK_F4, L"\x1bOS" }, // also \x1b[14~, PuTTY uses \x1b\x1b[D + TermKeyMap{ VK_F5, L"\x1b[15~" }, + TermKeyMap{ VK_F6, L"\x1b[17~" }, + TermKeyMap{ VK_F7, L"\x1b[18~" }, + TermKeyMap{ VK_F8, L"\x1b[19~" }, + TermKeyMap{ VK_F9, L"\x1b[20~" }, + TermKeyMap{ VK_F10, L"\x1b[21~" }, + TermKeyMap{ VK_F11, L"\x1b[23~" }, + TermKeyMap{ VK_F12, L"\x1b[24~" }, // The numpad has a variety of mappings, none of which seem standard or really configurable by the OS. // See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-PC-Style-Function-Keys // to see just how convoluted this all is. @@ -111,55 +128,54 @@ const TerminalInput::_TermKeyMap TerminalInput::s_rgKeypadApplicationMapping[]{ // (see http://vim.wikia.com/wiki/PuTTY_numeric_keypad_mappings#Comments) // I think the best solution is to just not do any for the time being. // Putty also provides configuration for choosing which of the 5 mappings it has through the settings, which is more work than we can manage now. - // { VK_MULTIPLY, L"\x1bOj" }, // PuTTY: \x1bOR (I believe putty is treating the top row of the numpad as PF1-PF4) - // { VK_ADD, L"\x1bOk" }, // PuTTY: \x1bOl, \x1bOm (with shift) - // { VK_SEPARATOR, L"\x1bOl" }, // ? I'm not sure which key this is... - // { VK_SUBTRACT, L"\x1bOm" }, // \x1bOS - // { VK_DECIMAL, L"\x1bOn" }, // \x1bOn - // { VK_DIVIDE, L"\x1bOo" }, // \x1bOQ - // { VK_NUMPAD0, L"\x1bOp" }, - // { VK_NUMPAD1, L"\x1bOq" }, - // { VK_NUMPAD2, L"\x1bOr" }, - // { VK_NUMPAD3, L"\x1bOs" }, - // { VK_NUMPAD4, L"\x1bOt" }, - // { VK_NUMPAD5, L"\x1bOu" }, // \x1b0E - // { VK_NUMPAD5, L"\x1bOE" }, // PuTTY \x1b[G - // { VK_NUMPAD6, L"\x1bOv" }, - // { VK_NUMPAD7, L"\x1bOw" }, - // { VK_NUMPAD8, L"\x1bOx" }, - // { VK_NUMPAD9, L"\x1bOy" }, - // { '=', L"\x1bOX" }, // I've also seen these codes mentioned in some documentation, - // { VK_SPACE, L"\x1bO " }, // but I wasn't really sure if they should be included or not... - // { VK_TAB, L"\x1bOI" }, // So I left them here as a reference just in case. + // TermKeyMap{ VK_MULTIPLY, L"\x1bOj" }, // PuTTY: \x1bOR (I believe putty is treating the top row of the numpad as PF1-PF4) + // TermKeyMap{ VK_ADD, L"\x1bOk" }, // PuTTY: \x1bOl, \x1bOm (with shift) + // TermKeyMap{ VK_SEPARATOR, L"\x1bOl" }, // ? I'm not sure which key this is... + // TermKeyMap{ VK_SUBTRACT, L"\x1bOm" }, // \x1bOS + // TermKeyMap{ VK_DECIMAL, L"\x1bOn" }, // \x1bOn + // TermKeyMap{ VK_DIVIDE, L"\x1bOo" }, // \x1bOQ + // TermKeyMap{ VK_NUMPAD0, L"\x1bOp" }, + // TermKeyMap{ VK_NUMPAD1, L"\x1bOq" }, + // TermKeyMap{ VK_NUMPAD2, L"\x1bOr" }, + // TermKeyMap{ VK_NUMPAD3, L"\x1bOs" }, + // TermKeyMap{ VK_NUMPAD4, L"\x1bOt" }, + // TermKeyMap{ VK_NUMPAD5, L"\x1bOu" }, // \x1b0E + // TermKeyMap{ VK_NUMPAD5, L"\x1bOE" }, // PuTTY \x1b[G + // TermKeyMap{ VK_NUMPAD6, L"\x1bOv" }, + // TermKeyMap{ VK_NUMPAD7, L"\x1bOw" }, + // TermKeyMap{ VK_NUMPAD8, L"\x1bOx" }, + // TermKeyMap{ VK_NUMPAD9, L"\x1bOy" }, + // TermKeyMap{ '=', L"\x1bOX" }, // I've also seen these codes mentioned in some documentation, + // TermKeyMap{ VK_SPACE, L"\x1bO " }, // but I wasn't really sure if they should be included or not... + // TermKeyMap{ VK_TAB, L"\x1bOI" }, // So I left them here as a reference just in case. }; // Sequences to send when a modifier is pressed with any of these keys // Basically, the 'm' will be replaced with a character indicating which // modifier keys are pressed. -const TerminalInput::_TermKeyMap TerminalInput::s_rgModifierKeyMapping[]{ - // HEY YOU. UPDATE THE MAX LENGTH DEF WHEN YOU MAKE CHANGES HERE. - { VK_UP, L"\x1b[1;mA" }, - { VK_DOWN, L"\x1b[1;mB" }, - { VK_RIGHT, L"\x1b[1;mC" }, - { VK_LEFT, L"\x1b[1;mD" }, - { VK_HOME, L"\x1b[1;mH" }, - { VK_END, L"\x1b[1;mF" }, - { VK_F1, L"\x1b[1;mP" }, - { VK_F2, L"\x1b[1;mQ" }, - { VK_F3, L"\x1b[1;mR" }, - { VK_F4, L"\x1b[1;mS" }, - { VK_INSERT, L"\x1b[2;m~" }, - { VK_DELETE, L"\x1b[3;m~" }, - { VK_PRIOR, L"\x1b[5;m~" }, - { VK_NEXT, L"\x1b[6;m~" }, - { VK_F5, L"\x1b[15;m~" }, - { VK_F6, L"\x1b[17;m~" }, - { VK_F7, L"\x1b[18;m~" }, - { VK_F8, L"\x1b[19;m~" }, - { VK_F9, L"\x1b[20;m~" }, - { VK_F10, L"\x1b[21;m~" }, - { VK_F11, L"\x1b[23;m~" }, - { VK_F12, L"\x1b[24;m~" }, +static constexpr std::array s_modifierKeyMapping{ + TermKeyMap{ VK_UP, L"\x1b[1;mA" }, + TermKeyMap{ VK_DOWN, L"\x1b[1;mB" }, + TermKeyMap{ VK_RIGHT, L"\x1b[1;mC" }, + TermKeyMap{ VK_LEFT, L"\x1b[1;mD" }, + TermKeyMap{ VK_HOME, L"\x1b[1;mH" }, + TermKeyMap{ VK_END, L"\x1b[1;mF" }, + TermKeyMap{ VK_F1, L"\x1b[1;mP" }, + TermKeyMap{ VK_F2, L"\x1b[1;mQ" }, + TermKeyMap{ VK_F3, L"\x1b[1;mR" }, + TermKeyMap{ VK_F4, L"\x1b[1;mS" }, + TermKeyMap{ VK_INSERT, L"\x1b[2;m~" }, + TermKeyMap{ VK_DELETE, L"\x1b[3;m~" }, + TermKeyMap{ VK_PRIOR, L"\x1b[5;m~" }, + TermKeyMap{ VK_NEXT, L"\x1b[6;m~" }, + TermKeyMap{ VK_F5, L"\x1b[15;m~" }, + TermKeyMap{ VK_F6, L"\x1b[17;m~" }, + TermKeyMap{ VK_F7, L"\x1b[18;m~" }, + TermKeyMap{ VK_F8, L"\x1b[19;m~" }, + TermKeyMap{ VK_F9, L"\x1b[20;m~" }, + TermKeyMap{ VK_F10, L"\x1b[21;m~" }, + TermKeyMap{ VK_F11, L"\x1b[23;m~" }, + TermKeyMap{ VK_F12, L"\x1b[24;m~" }, // Ubuntu's inputrc also defines \x1b[5C, \x1b\x1bC (and D) as 'forward/backward-word' mappings // I believe '\x1b\x1bC' is listed because the C1 ESC (x9B) gets encoded as // \xC2\x9B, but then translated to \x1b\x1b if the C1 codepoint isn't supported by the current encoding @@ -169,95 +185,127 @@ const TerminalInput::_TermKeyMap TerminalInput::s_rgModifierKeyMapping[]{ // These sequences are not later updated to encode the modifier state in the // sequence itself, they are just weird exceptional cases to the general // rules above. -const TerminalInput::_TermKeyMap TerminalInput::s_rgSimpleModifedKeyMapping[]{ - // HEY YOU. UPDATE THE MAX LENGTH DEF WHEN YOU MAKE CHANGES HERE. - { VK_BACK, CTRL_PRESSED, L"\x8" }, - { VK_BACK, ALT_PRESSED, L"\x1b\x7f" }, - { VK_BACK, CTRL_PRESSED | ALT_PRESSED, L"\x1b\x8" }, - { VK_TAB, CTRL_PRESSED, L"\t" }, - { VK_TAB, SHIFT_PRESSED, L"\x1b[Z" }, - { VK_DIVIDE, CTRL_PRESSED, L"\x1F" }, +static constexpr std::array s_simpleModifedKeyMapping{ + TermKeyMap{ VK_BACK, CTRL_PRESSED, L"\x8" }, + TermKeyMap{ VK_BACK, ALT_PRESSED, L"\x1b\x7f" }, + TermKeyMap{ VK_BACK, CTRL_PRESSED | ALT_PRESSED, L"\x1b\x8" }, + TermKeyMap{ VK_TAB, CTRL_PRESSED, L"\t" }, + TermKeyMap{ VK_TAB, SHIFT_PRESSED, L"\x1b[Z" }, + TermKeyMap{ VK_DIVIDE, CTRL_PRESSED, L"\x1F" }, // These two are not implemented here, because they are system keys. - // { VK_TAB, ALT_PRESSED, L""}, This is the Windows system shortcut for switching windows. - // { VK_ESCAPE, ALT_PRESSED, L""}, This is another Windows system shortcut for switching windows. + // TermKeyMap{ VK_TAB, ALT_PRESSED, L""}, This is the Windows system shortcut for switching windows. + // TermKeyMap{ VK_ESCAPE, ALT_PRESSED, L""}, This is another Windows system shortcut for switching windows. }; const wchar_t* const CTRL_SLASH_SEQUENCE = L"\x1f"; -// Do NOT include the null terminator in the count. -const size_t TerminalInput::_TermKeyMap::s_cchMaxSequenceLength = 7; // UPDATE THIS DEF WHEN THE LONGEST MAPPED STRING CHANGES - -const size_t TerminalInput::s_cCursorKeysNormalMapping = ARRAYSIZE(s_rgCursorKeysNormalMapping); -const size_t TerminalInput::s_cCursorKeysApplicationMapping = ARRAYSIZE(s_rgCursorKeysApplicationMapping); -const size_t TerminalInput::s_cKeypadNumericMapping = ARRAYSIZE(s_rgKeypadNumericMapping); -const size_t TerminalInput::s_cKeypadApplicationMapping = ARRAYSIZE(s_rgKeypadApplicationMapping); -const size_t TerminalInput::s_cModifierKeyMapping = ARRAYSIZE(s_rgModifierKeyMapping); -const size_t TerminalInput::s_cSimpleModifedKeyMapping = ARRAYSIZE(s_rgSimpleModifedKeyMapping); - -void TerminalInput::ChangeKeypadMode(const bool fApplicationMode) +void TerminalInput::ChangeKeypadMode(const bool applicationMode) noexcept { - _fKeypadApplicationMode = fApplicationMode; + _keypadApplicationMode = applicationMode; } -void TerminalInput::ChangeCursorKeysMode(const bool fApplicationMode) +void TerminalInput::ChangeCursorKeysMode(const bool applicationMode) noexcept { - _fCursorApplicationMode = fApplicationMode; + _cursorApplicationMode = applicationMode; } -const size_t TerminalInput::GetKeyMappingLength(const KeyEvent& keyEvent) const +static const std::basic_string_view _getKeyMapping(const KeyEvent& keyEvent, + const bool cursorApplicationMode, + const bool keypadApplicationMode) noexcept { if (keyEvent.IsCursorKey()) { - return (_fCursorApplicationMode) ? s_cCursorKeysApplicationMapping : s_cCursorKeysNormalMapping; + if (cursorApplicationMode) + { + return { s_cursorKeysApplicationMapping.data(), s_cursorKeysApplicationMapping.size() }; + } + else + { + return { s_cursorKeysNormalMapping.data(), s_cursorKeysNormalMapping.size() }; + } + } + else + { + if (keypadApplicationMode) + { + return { s_keypadApplicationMapping.data(), s_keypadApplicationMapping.size() }; + } + else + { + return { s_keypadNumericMapping.data(), s_keypadNumericMapping.size() }; + } } - - return (_fKeypadApplicationMode) ? s_cKeypadApplicationMapping : s_cKeypadNumericMapping; } -const TerminalInput::_TermKeyMap* TerminalInput::GetKeyMapping(const KeyEvent& keyEvent) const +// Routine Description: +// - Searches the keyMapping for a entry corresponding to this key event, and returns it. +// Arguments: +// - keyEvent - Key event to translate +// - keyMapping - Array of key mappings to search +// Return Value: +// - Has value if there was a match to a key translation. +static std::optional _searchKeyMapping(const KeyEvent& keyEvent, + std::basic_string_view keyMapping) noexcept { - if (keyEvent.IsCursorKey()) + for (auto& map : keyMapping) { - return (_fCursorApplicationMode) ? s_rgCursorKeysApplicationMapping : s_rgCursorKeysNormalMapping; - } + if (map.vkey == keyEvent.GetVirtualKeyCode()) + { + // If the mapping has no modifiers set, then it doesn't really care + // what the modifiers are on the key. The caller will likely do + // something with them. + // However, if there are modifiers set, then we only want to match + // if the key's modifiers are the same as the modifiers in the + // mapping. + bool modifiersMatch = WI_AreAllFlagsClear(map.modifiers, MOD_PRESSED); + if (!modifiersMatch) + { + // The modifier mapping expects certain modifier keys to be + // pressed. Check those as well. + modifiersMatch = + (WI_IsFlagSet(map.modifiers, SHIFT_PRESSED) == keyEvent.IsShiftPressed()) && + (WI_IsAnyFlagSet(map.modifiers, ALT_PRESSED) == keyEvent.IsAltPressed()) && + (WI_IsAnyFlagSet(map.modifiers, CTRL_PRESSED) == keyEvent.IsCtrlPressed()); + } - return (_fKeypadApplicationMode) ? s_rgKeypadApplicationMapping : s_rgKeypadNumericMapping; + if (modifiersMatch) + { + return map; + } + } + } + return std::nullopt; } +typedef std::function InputSender; + // Routine Description: -// - Searches the s_ModifierKeyMapping for a entry corresponding to this key event. +// - Searches the s_modifierKeyMapping for a entry corresponding to this key event. // Changes the second to last byte to correspond to the currently pressed modifier keys // before sending to the input. // Arguments: // - keyEvent - Key event to translate +// - sender - Function to use to dispatch translated event // Return Value: // - True if there was a match to a key translation, and we successfully modified and sent it to the input -bool TerminalInput::_SearchWithModifier(const KeyEvent& keyEvent) const +static bool _searchWithModifier(const KeyEvent& keyEvent, InputSender sender) { - const TerminalInput::_TermKeyMap* pMatchingMapping; - bool fSuccess = _SearchKeyMapping(keyEvent, - s_rgModifierKeyMapping, - s_cModifierKeyMapping, - &pMatchingMapping); - if (fSuccess) + bool success = false; + + const auto match = _searchKeyMapping(keyEvent, + { s_modifierKeyMapping.data(), s_modifierKeyMapping.size() }); + if (match) { - size_t cch = 0; - if (SUCCEEDED(StringCchLengthW(pMatchingMapping->pwszSequence, _TermKeyMap::s_cchMaxSequenceLength + 1, &cch)) && - cch > 0) + const auto v = match.value(); + if (!v.sequence.empty()) { - wchar_t* rwchModifiedSequence = new (std::nothrow) wchar_t[cch + 1]; - if (rwchModifiedSequence != nullptr) - { - memcpy(rwchModifiedSequence, pMatchingMapping->pwszSequence, cch * sizeof(wchar_t)); - const bool fShift = keyEvent.IsShiftPressed(); - const bool fAlt = keyEvent.IsAltPressed(); - const bool fCtrl = keyEvent.IsCtrlPressed(); - rwchModifiedSequence[cch - 2] = L'1' + (fShift ? 1 : 0) + (fAlt ? 2 : 0) + (fCtrl ? 4 : 0); - rwchModifiedSequence[cch] = 0; - _SendInputSequence(rwchModifiedSequence); - fSuccess = true; - delete[] rwchModifiedSequence; - } + std::wstring modified{ v.sequence }; // Make a copy so we can modify it. + const bool shift = keyEvent.IsShiftPressed(); + const bool alt = keyEvent.IsAltPressed(); + const bool ctrl = keyEvent.IsCtrlPressed(); + modified.at(modified.size() - 2) = L'1' + (shift ? 1 : 0) + (alt ? 2 : 0) + (ctrl ? 4 : 0); + sender(modified); + success = true; } } else @@ -265,15 +313,13 @@ bool TerminalInput::_SearchWithModifier(const KeyEvent& keyEvent) const // We didn't find the key in the map of modified keys that need editing, // maybe it's in the other map of modified keys with sequences that // don't need editing before sending. - fSuccess = _SearchKeyMapping(keyEvent, - s_rgSimpleModifedKeyMapping, - s_cSimpleModifedKeyMapping, - &pMatchingMapping); - if (fSuccess) + const auto match2 = _searchKeyMapping(keyEvent, + { s_simpleModifedKeyMapping.data(), s_simpleModifedKeyMapping.size() }); + if (match2) { // This mapping doesn't need to be changed at all. - _SendInputSequence(pMatchingMapping->pwszSequence); - fSuccess = true; + sender(match2.value().sequence); + success = true; } else { @@ -284,62 +330,13 @@ bool TerminalInput::_SearchWithModifier(const KeyEvent& keyEvent) const if (keyEvent.GetVirtualKeyCode() == slashVkey && keyEvent.IsCtrlPressed()) { // This mapping doesn't need to be changed at all. - _SendInputSequence(CTRL_SLASH_SEQUENCE); - fSuccess = true; + sender(CTRL_SLASH_SEQUENCE); + success = true; } } } - return fSuccess; -} - -// Routine Description: -// - Searches the keyMapping for a entry corresponding to this key event, and returns it. -// Arguments: -// - keyEvent - Key event to translate -// - keyMapping - Array of key mappings to search -// - cKeyMapping - number of entries in keyMapping -// - pMatchingMapping - Where to put the pointer to the found match -// Return Value: -// - True if there was a match to a key translation -bool TerminalInput::_SearchKeyMapping(const KeyEvent& keyEvent, - _In_reads_(cKeyMapping) const TerminalInput::_TermKeyMap* keyMapping, - const size_t cKeyMapping, - _Out_ const TerminalInput::_TermKeyMap** pMatchingMapping) const -{ - bool fKeyTranslated = false; - for (size_t i = 0; i < cKeyMapping; i++) - { - const _TermKeyMap* const pMap = &(keyMapping[i]); - - if (pMap->wVirtualKey == keyEvent.GetVirtualKeyCode()) - { - // If the mapping has no modifiers set, then it doesn't really care - // what the modifiers are on the key. The caller will likely do - // something with them. - // However, if there are modifiers set, then we only want to match - // if the key's modifiers are the same as the modifiers in the - // mapping. - bool modifiersMatch = WI_AreAllFlagsClear(pMap->dwModifiers, MOD_PRESSED); - if (!modifiersMatch) - { - // The modifier mapping expects certain modifier keys to be - // pressed. Check those as well. - modifiersMatch = - (WI_IsFlagSet(pMap->dwModifiers, SHIFT_PRESSED) == keyEvent.IsShiftPressed()) && - (WI_IsAnyFlagSet(pMap->dwModifiers, ALT_PRESSED) == keyEvent.IsAltPressed()) && - (WI_IsAnyFlagSet(pMap->dwModifiers, CTRL_PRESSED) == keyEvent.IsCtrlPressed()); - } - - if (modifiersMatch) - { - fKeyTranslated = true; - *pMatchingMapping = pMap; - break; - } - } - } - return fKeyTranslated; + return success; } // Routine Description: @@ -347,30 +344,31 @@ bool TerminalInput::_SearchKeyMapping(const KeyEvent& keyEvent, // Arguments: // - keyEvent - Key event to translate // - keyMapping - Array of key mappings to search -// - cKeyMapping - number of entries in keyMapping +// - sender - Function to use to dispatch translated event // Return Value: // - True if there was a match to a key translation, and we successfully sent it to the input -bool TerminalInput::_TranslateDefaultMapping(const KeyEvent& keyEvent, - _In_reads_(cKeyMapping) const TerminalInput::_TermKeyMap* keyMapping, - const size_t cKeyMapping) const +static bool _translateDefaultMapping(const KeyEvent& keyEvent, + const std::basic_string_view keyMapping, + InputSender sender) { - const TerminalInput::_TermKeyMap* pMatchingMapping; - const bool fSuccess = _SearchKeyMapping(keyEvent, keyMapping, cKeyMapping, &pMatchingMapping); - if (fSuccess) + const auto match = _searchKeyMapping(keyEvent, keyMapping); + if (match) { - _SendInputSequence(pMatchingMapping->pwszSequence); + sender(match->sequence); } - return fSuccess; + return match.has_value(); } bool TerminalInput::HandleKey(const IInputEvent* const pInEvent) const { // By default, we fail to handle the key - bool fKeyHandled = false; + bool keyHandled = false; // On key presses, prepare to translate to VT compatible sequences if (pInEvent->EventType() == InputEventType::KeyEvent) { + const auto senderFunc = [this](const std::wstring_view seq) { _SendInputSequence(seq); }; + auto keyEvent = *static_cast(pInEvent); // Only need to handle key down. See raw key handler (see RawReadWaitRoutine in stream.cpp) @@ -406,7 +404,7 @@ bool TerminalInput::HandleKey(const IInputEvent* const pInEvent) const // For Alt+Ctrl+Key messages, the UnicodeChar is NOT the Ctrl+key char, it's null. // So we need to get the char from the vKey. // EXCEPT for Alt+Ctrl+Space. Then the UnicodeChar is space, not NUL. - auto wchPressedChar = static_cast(MapVirtualKeyW(keyEvent.GetVirtualKeyCode(), MAPVK_VK_TO_CHAR)); + auto wchPressedChar = gsl::narrow_cast(MapVirtualKeyW(keyEvent.GetVirtualKeyCode(), MAPVK_VK_TO_CHAR)); // This is a trick - C-Spc is supposed to send NUL. So quick change space -> @ (0x40) wchPressedChar = (wchPressedChar == UNICODE_SPACE) ? 0x40 : wchPressedChar; if (wchPressedChar >= 0x40 && wchPressedChar < 0x7F) @@ -414,23 +412,23 @@ bool TerminalInput::HandleKey(const IInputEvent* const pInEvent) const //shift the char to the ctrl range wchPressedChar -= 0x40; _SendEscapedInputSequence(wchPressedChar); - fKeyHandled = true; + keyHandled = true; } } // If a modifier key was pressed, then we need to try and send the modified sequence. - if (!fKeyHandled && keyEvent.IsModifierPressed()) + if (!keyHandled && keyEvent.IsModifierPressed()) { // Translate the key using the modifier table - fKeyHandled = _SearchWithModifier(keyEvent); + keyHandled = _searchWithModifier(keyEvent, senderFunc); } // ALT is a sequence of ESC + KEY. - if (!fKeyHandled && keyEvent.GetCharData() != 0 && keyEvent.IsAltPressed()) + if (!keyHandled && keyEvent.GetCharData() != 0 && keyEvent.IsAltPressed()) { _SendEscapedInputSequence(keyEvent.GetCharData()); - fKeyHandled = true; + keyHandled = true; } - if (!fKeyHandled && keyEvent.IsCtrlPressed()) + if (!keyHandled && keyEvent.IsCtrlPressed()) { if ((keyEvent.GetCharData() == UNICODE_SPACE) || // Ctrl+Space // when Ctrl+@ comes through, the unicodechar @@ -439,11 +437,11 @@ bool TerminalInput::HandleKey(const IInputEvent* const pInEvent) const (keyEvent.GetCharData() == UNICODE_NULL && keyEvent.GetVirtualKeyCode() == LOBYTE(VkKeyScanW(0)))) { _SendNullInputSequence(keyEvent.GetActiveModifierKeys()); - fKeyHandled = true; + keyHandled = true; } } - if (!fKeyHandled) + if (!keyHandled) { // For perf optimization, filter out any typically printable Virtual Keys (e.g. A-Z) // This is in lieu of an O(1) sparse table or other such less-maintanable methods. @@ -451,7 +449,7 @@ bool TerminalInput::HandleKey(const IInputEvent* const pInEvent) const if ((keyEvent.GetVirtualKeyCode() < '0' || keyEvent.GetVirtualKeyCode() > 'Z') && keyEvent.GetVirtualKeyCode() != VK_CANCEL) { - fKeyHandled = _TranslateDefaultMapping(keyEvent, GetKeyMapping(keyEvent), GetKeyMappingLength(keyEvent)); + keyHandled = _translateDefaultMapping(keyEvent, _getKeyMapping(keyEvent, _cursorApplicationMode, _keypadApplicationMode), senderFunc); } else { @@ -459,13 +457,13 @@ bool TerminalInput::HandleKey(const IInputEvent* const pInEvent) const rgwchSequence[0] = keyEvent.GetCharData(); rgwchSequence[1] = UNICODE_NULL; _SendInputSequence(rgwchSequence); - fKeyHandled = true; + keyHandled = true; } } } } - return fKeyHandled; + return keyHandled; } bool TerminalInput::HandleChar(const wchar_t ch) @@ -480,9 +478,8 @@ bool TerminalInput::HandleChar(const wchar_t ch) { // we already were storing a leading surrogate but we got another one. Go ahead and send the // saved surrogate piece and save the new one - wchar_t buffer[32]; - swprintf_s(buffer, L"%I32u", _leadingSurrogate.value()); - _SendInputSequence(buffer); + const auto formatted = wil::str_printf(L"%I32u", _leadingSurrogate.value()); + _SendInputSequence(formatted); } // save the leading portion of a surrogate pair so that they can be sent at the same time _leadingSurrogate.emplace(ch); @@ -499,9 +496,7 @@ bool TerminalInput::HandleChar(const wchar_t ch) } else { - wchar_t buffer[2] = { ch, 0 }; - std::wstring_view buffer_view(buffer, 1); - _SendInputSequence(buffer_view); + _SendInputSequence({ &ch, 1 }); } return true; @@ -529,7 +524,7 @@ void TerminalInput::_SendEscapedInputSequence(const wchar_t wch) const } } -void TerminalInput::_SendNullInputSequence(const DWORD dwControlKeyState) const +void TerminalInput::_SendNullInputSequence(const DWORD controlKeyState) const { try { @@ -539,7 +534,7 @@ void TerminalInput::_SendNullInputSequence(const DWORD dwControlKeyState) const LOBYTE(VkKeyScanW(0)), 0ui16, L'\x0', - dwControlKeyState)); + controlKeyState)); _pfnWriteEvents(inputEvents); } catch (...) @@ -548,17 +543,16 @@ void TerminalInput::_SendNullInputSequence(const DWORD dwControlKeyState) const } } -void TerminalInput::_SendInputSequence(_In_ const std::wstring_view sequence) const +void TerminalInput::_SendInputSequence(const std::wstring_view sequence) const { - const auto length = sequence.length(); - if (length <= _TermKeyMap::s_cchMaxSequenceLength && length > 0) + if (!sequence.empty()) { try { std::deque> inputEvents; - for (size_t i = 0; i < length; i++) + for (const auto& wch : sequence) { - inputEvents.push_back(std::make_unique(true, 1ui16, 0ui16, 0ui16, sequence[i], 0)); + inputEvents.push_back(std::make_unique(true, 1ui16, 0ui16, 0ui16, wch, 0)); } _pfnWriteEvents(inputEvents); } diff --git a/src/terminal/input/terminalInput.hpp b/src/terminal/input/terminalInput.hpp index 56a06871779..7992531e596 100644 --- a/src/terminal/input/terminalInput.hpp +++ b/src/terminal/input/terminalInput.hpp @@ -35,8 +35,8 @@ namespace Microsoft::Console::VirtualTerminal bool HandleKey(const IInputEvent* const pInEvent) const; bool HandleChar(const wchar_t ch); - void ChangeKeypadMode(const bool fApplicationMode); - void ChangeCursorKeysMode(const bool fApplicationMode); + void ChangeKeypadMode(const bool applicationMode) noexcept; + void ChangeCursorKeysMode(const bool applicationMode) noexcept; private: std::function>&)> _pfnWriteEvents; @@ -44,70 +44,11 @@ namespace Microsoft::Console::VirtualTerminal // storage location for the leading surrogate of a utf-16 surrogate pair std::optional _leadingSurrogate; - bool _fKeypadApplicationMode = false; - bool _fCursorApplicationMode = false; + bool _keypadApplicationMode = false; + bool _cursorApplicationMode = false; void _SendNullInputSequence(const DWORD dwControlKeyState) const; - void _SendInputSequence(_In_ const std::wstring_view sequence) const; + void _SendInputSequence(const std::wstring_view sequence) const; void _SendEscapedInputSequence(const wchar_t wch) const; - - struct _TermKeyMap - { - WORD const wVirtualKey; - PCWSTR const pwszSequence; - DWORD const dwModifiers; - - static const size_t s_cchMaxSequenceLength; - - _TermKeyMap(const WORD wVirtualKey, _In_ PCWSTR const pwszSequence) noexcept : - wVirtualKey(wVirtualKey), - pwszSequence(pwszSequence), - dwModifiers(0){}; - - _TermKeyMap(const WORD wVirtualKey, const DWORD dwModifiers, _In_ PCWSTR const pwszSequence) noexcept : - wVirtualKey(wVirtualKey), - pwszSequence(pwszSequence), - dwModifiers(dwModifiers){}; - - // C++11 syntax for prohibiting assignment - // We can't assign, everything here is const. - // We also shouldn't need to, this is only for a specific table. - _TermKeyMap(const _TermKeyMap&) = delete; - _TermKeyMap& operator=(const _TermKeyMap&) = delete; - - _TermKeyMap(_TermKeyMap&&) = delete; - _TermKeyMap& operator=(_TermKeyMap&&) = delete; - - _TermKeyMap() = delete; - ~_TermKeyMap() = default; - }; - - static const _TermKeyMap s_rgCursorKeysNormalMapping[]; - static const _TermKeyMap s_rgCursorKeysApplicationMapping[]; - static const _TermKeyMap s_rgKeypadNumericMapping[]; - static const _TermKeyMap s_rgKeypadApplicationMapping[]; - static const _TermKeyMap s_rgModifierKeyMapping[]; - static const _TermKeyMap s_rgSimpleModifedKeyMapping[]; - - static const size_t s_cCursorKeysNormalMapping; - static const size_t s_cCursorKeysApplicationMapping; - static const size_t s_cKeypadNumericMapping; - static const size_t s_cKeypadApplicationMapping; - static const size_t s_cModifierKeyMapping; - static const size_t s_cSimpleModifedKeyMapping; - - bool _SearchKeyMapping(const KeyEvent& keyEvent, - _In_reads_(cKeyMapping) const TerminalInput::_TermKeyMap* keyMapping, - const size_t cKeyMapping, - _Out_ const TerminalInput::_TermKeyMap** pMatchingMapping) const; - - bool _TranslateDefaultMapping(const KeyEvent& keyEvent, - _In_reads_(cKeyMapping) const TerminalInput::_TermKeyMap* keyMapping, - const size_t cKeyMapping) const; - - bool _SearchWithModifier(const KeyEvent& keyEvent) const; - - const size_t GetKeyMappingLength(const KeyEvent& keyEvent) const; - const _TermKeyMap* GetKeyMapping(const KeyEvent& keyEvent) const; }; } diff --git a/src/terminal/parser/InputStateMachineEngine.cpp b/src/terminal/parser/InputStateMachineEngine.cpp index 88e948517ea..a780f08d7f2 100644 --- a/src/terminal/parser/InputStateMachineEngine.cpp +++ b/src/terminal/parser/InputStateMachineEngine.cpp @@ -204,7 +204,7 @@ bool InputStateMachineEngine::_DoControlCharacter(const wchar_t wch, const bool { // This is a C0 Control Character. // This should be translated as Ctrl+(wch+x40) - wchar_t actualChar = wch; + const wchar_t actualChar = wch; bool writeCtrl = true; short vkey = 0; @@ -393,7 +393,7 @@ bool InputStateMachineEngine::ActionCsiDispatch(const wchar_t wch, const auto remainingArgs = parameters.size() > 1 ? parameters.substr(1) : std::basic_string_view{}; bool success = false; - switch ((CsiActionCodes)wch) + switch (static_cast(wch)) { case CsiActionCodes::Generic: modifierState = _GetGenericKeysModifierState(parameters); @@ -437,7 +437,7 @@ bool InputStateMachineEngine::ActionCsiDispatch(const wchar_t wch, if (success) { - switch ((CsiActionCodes)wch) + switch (static_cast(wch)) { // case CsiActionCodes::DSR_DeviceStatusReportResponse: case CsiActionCodes::CSI_F3: @@ -493,14 +493,14 @@ bool InputStateMachineEngine::ActionSs3Dispatch(const wchar_t wch, { // Ss3 sequence keys aren't modified. // When F1-F4 *are* modified, they're sent as CSI sequences, not SS3's. - DWORD dwModifierState = 0; + const DWORD modifierState = 0; short vkey = 0; bool success = _GetSs3KeysVkey(wch, vkey); if (success) { - success = _WriteSingleKey(vkey, dwModifierState); + success = _WriteSingleKey(vkey, modifierState); } return success; @@ -513,7 +513,7 @@ bool InputStateMachineEngine::ActionSs3Dispatch(const wchar_t wch, // - // Return Value: // - true iff we successfully dispatched the sequence. -bool InputStateMachineEngine::ActionClear() +bool InputStateMachineEngine::ActionClear() noexcept { return true; } @@ -525,7 +525,7 @@ bool InputStateMachineEngine::ActionClear() // - // Return Value: // - true iff we successfully dispatched the sequence. -bool InputStateMachineEngine::ActionIgnore() +bool InputStateMachineEngine::ActionIgnore() noexcept { return true; } @@ -541,7 +541,7 @@ bool InputStateMachineEngine::ActionIgnore() // - true if we handled the dsipatch. bool InputStateMachineEngine::ActionOscDispatch(const wchar_t /*wch*/, const size_t /*parameter*/, - const std::wstring_view /*string*/) + const std::wstring_view /*string*/) noexcept { return false; } @@ -575,7 +575,7 @@ void InputStateMachineEngine::_GenerateWrappedSequence(const wchar_t wch, const bool ctrl = WI_IsFlagSet(modifierState, LEFT_CTRL_PRESSED); const bool alt = WI_IsFlagSet(modifierState, LEFT_ALT_PRESSED); - INPUT_RECORD next; + INPUT_RECORD next{ 0 }; DWORD currentModifiers = 0; @@ -587,7 +587,7 @@ void InputStateMachineEngine::_GenerateWrappedSequence(const wchar_t wch, next.Event.KeyEvent.dwControlKeyState = currentModifiers; next.Event.KeyEvent.wRepeatCount = 1; next.Event.KeyEvent.wVirtualKeyCode = VK_SHIFT; - next.Event.KeyEvent.wVirtualScanCode = static_cast(MapVirtualKey(VK_SHIFT, MAPVK_VK_TO_VSC)); + next.Event.KeyEvent.wVirtualScanCode = gsl::narrow_cast(MapVirtualKey(VK_SHIFT, MAPVK_VK_TO_VSC)); next.Event.KeyEvent.uChar.UnicodeChar = 0x0; input.push_back(next); } @@ -599,7 +599,7 @@ void InputStateMachineEngine::_GenerateWrappedSequence(const wchar_t wch, next.Event.KeyEvent.dwControlKeyState = currentModifiers; next.Event.KeyEvent.wRepeatCount = 1; next.Event.KeyEvent.wVirtualKeyCode = VK_MENU; - next.Event.KeyEvent.wVirtualScanCode = static_cast(MapVirtualKey(VK_MENU, MAPVK_VK_TO_VSC)); + next.Event.KeyEvent.wVirtualScanCode = gsl::narrow_cast(MapVirtualKey(VK_MENU, MAPVK_VK_TO_VSC)); next.Event.KeyEvent.uChar.UnicodeChar = 0x0; input.push_back(next); } @@ -611,7 +611,7 @@ void InputStateMachineEngine::_GenerateWrappedSequence(const wchar_t wch, next.Event.KeyEvent.dwControlKeyState = currentModifiers; next.Event.KeyEvent.wRepeatCount = 1; next.Event.KeyEvent.wVirtualKeyCode = VK_CONTROL; - next.Event.KeyEvent.wVirtualScanCode = static_cast(MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC)); + next.Event.KeyEvent.wVirtualScanCode = gsl::narrow_cast(MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC)); next.Event.KeyEvent.uChar.UnicodeChar = 0x0; input.push_back(next); } @@ -626,7 +626,7 @@ void InputStateMachineEngine::_GenerateWrappedSequence(const wchar_t wch, next.Event.KeyEvent.dwControlKeyState = currentModifiers; next.Event.KeyEvent.wRepeatCount = 1; next.Event.KeyEvent.wVirtualKeyCode = VK_CONTROL; - next.Event.KeyEvent.wVirtualScanCode = static_cast(MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC)); + next.Event.KeyEvent.wVirtualScanCode = gsl::narrow_cast(MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC)); next.Event.KeyEvent.uChar.UnicodeChar = 0x0; input.push_back(next); } @@ -638,7 +638,7 @@ void InputStateMachineEngine::_GenerateWrappedSequence(const wchar_t wch, next.Event.KeyEvent.dwControlKeyState = currentModifiers; next.Event.KeyEvent.wRepeatCount = 1; next.Event.KeyEvent.wVirtualKeyCode = VK_MENU; - next.Event.KeyEvent.wVirtualScanCode = static_cast(MapVirtualKey(VK_MENU, MAPVK_VK_TO_VSC)); + next.Event.KeyEvent.wVirtualScanCode = gsl::narrow_cast(MapVirtualKey(VK_MENU, MAPVK_VK_TO_VSC)); next.Event.KeyEvent.uChar.UnicodeChar = 0x0; input.push_back(next); } @@ -650,7 +650,7 @@ void InputStateMachineEngine::_GenerateWrappedSequence(const wchar_t wch, next.Event.KeyEvent.dwControlKeyState = currentModifiers; next.Event.KeyEvent.wRepeatCount = 1; next.Event.KeyEvent.wVirtualKeyCode = VK_SHIFT; - next.Event.KeyEvent.wVirtualScanCode = static_cast(MapVirtualKey(VK_SHIFT, MAPVK_VK_TO_VSC)); + next.Event.KeyEvent.wVirtualScanCode = gsl::narrow_cast(MapVirtualKey(VK_SHIFT, MAPVK_VK_TO_VSC)); next.Event.KeyEvent.uChar.UnicodeChar = 0x0; input.push_back(next); } @@ -681,7 +681,7 @@ void InputStateMachineEngine::_GetSingleKeypress(const wchar_t wch, rec.Event.KeyEvent.dwControlKeyState = modifierState; rec.Event.KeyEvent.wRepeatCount = 1; rec.Event.KeyEvent.wVirtualKeyCode = vkey; - rec.Event.KeyEvent.wVirtualScanCode = (WORD)MapVirtualKey(vkey, MAPVK_VK_TO_VSC); + rec.Event.KeyEvent.wVirtualScanCode = gsl::narrow_cast(MapVirtualKey(vkey, MAPVK_VK_TO_VSC)); rec.Event.KeyEvent.uChar.UnicodeChar = wch; input.push_back(rec); @@ -715,12 +715,12 @@ bool InputStateMachineEngine::_WriteSingleKey(const wchar_t wch, const short vke // Will automatically get the wchar_t associated with that vkey. // Arguments: // - vkey - the VKEY of the key to write to the input callback. -// - dwModifierState - the modifier state to write with the key. +// - modifierState - the modifier state to write with the key. // Return Value: // - true iff we successfully wrote the keypress to the input callback. bool InputStateMachineEngine::_WriteSingleKey(const short vkey, const DWORD dwModifierState) { - wchar_t wch = (wchar_t)MapVirtualKey(vkey, MAPVK_VK_TO_CHAR); + const wchar_t wch = gsl::narrow_cast(MapVirtualKey(vkey, MAPVK_VK_TO_CHAR)); return _WriteSingleKey(wch, vkey, dwModifierState); } @@ -732,7 +732,7 @@ bool InputStateMachineEngine::_WriteSingleKey(const short vkey, const DWORD dwMo // - cParams - the number of elements in rgusParams // Return Value: // - the INPUT_RECORD comaptible modifier state. -DWORD InputStateMachineEngine::_GetCursorKeysModifierState(const std::basic_string_view parameters) +DWORD InputStateMachineEngine::_GetCursorKeysModifierState(const std::basic_string_view parameters) noexcept { // Both Cursor keys and generic keys keep their modifiers in the same index. return _GetGenericKeysModifierState(parameters); @@ -746,7 +746,7 @@ DWORD InputStateMachineEngine::_GetCursorKeysModifierState(const std::basic_stri // - cParams - the number of elements in rgusParams // Return Value: // - the INPUT_RECORD compatible modifier state. -DWORD InputStateMachineEngine::_GetGenericKeysModifierState(const std::basic_string_view parameters) +DWORD InputStateMachineEngine::_GetGenericKeysModifierState(const std::basic_string_view parameters) noexcept { DWORD modifiers = 0; if (_IsModified(parameters.size()) && parameters.size() >= 2) @@ -762,7 +762,7 @@ DWORD InputStateMachineEngine::_GetGenericKeysModifierState(const std::basic_str // - paramCount - the nummber of parameters we've collected in this sequence // Return Value: // - true iff the sequence is a modified sequence. -bool InputStateMachineEngine::_IsModified(const size_t paramCount) +bool InputStateMachineEngine::_IsModified(const size_t paramCount) noexcept { // modified input either looks like // \x1b[1;mA or \x1b[17;m~ @@ -776,7 +776,7 @@ bool InputStateMachineEngine::_IsModified(const size_t paramCount) // - modifierParam - the VT modifier value to convert // Return Value: // - The equivalent INPUT_RECORD modifier value. -DWORD InputStateMachineEngine::_GetModifier(const size_t modifierParam) +DWORD InputStateMachineEngine::_GetModifier(const size_t modifierParam) noexcept { // VT Modifiers are 1+(modifier flags) const auto vtParam = modifierParam - 1; @@ -805,7 +805,7 @@ bool InputStateMachineEngine::_GetGenericVkey(const std::basic_string_view bool InputStateMachineEngine::_GenerateKeyFromChar(const wchar_t wch, short& vkey, - DWORD& modifierState) + DWORD& modifierState) noexcept { // Low order byte is key, high order is modifiers - short keyscan = VkKeyScanW(wch); + const short keyscan = VkKeyScanW(wch); short key = LOBYTE(keyscan); - short keyscanModifiers = HIBYTE(keyscan); + const short keyscanModifiers = HIBYTE(keyscan); if (key == -1 && keyscanModifiers == -1) { @@ -902,7 +902,7 @@ bool InputStateMachineEngine::_GenerateKeyFromChar(const wchar_t wch, // ProcessString, and dispatch only at the end of the sequence. // Return Value: // - True iff we should manually dispatch on the last character of a string. -bool InputStateMachineEngine::FlushAtEndOfString() const +bool InputStateMachineEngine::FlushAtEndOfString() const noexcept { return true; } @@ -917,7 +917,7 @@ bool InputStateMachineEngine::FlushAtEndOfString() const // Return Value: // - True iff we should return to the Ground state when the state machine // encounters a Control (C0) character in the Escape state. -bool InputStateMachineEngine::DispatchControlCharsFromEscape() const +bool InputStateMachineEngine::DispatchControlCharsFromEscape() const noexcept { return true; } @@ -930,7 +930,7 @@ bool InputStateMachineEngine::DispatchControlCharsFromEscape() const // Return Value: // - True iff we should dispatch in the Escape state when we encounter a // Intermediate character. -bool InputStateMachineEngine::DispatchIntermediatesFromEscape() const +bool InputStateMachineEngine::DispatchIntermediatesFromEscape() const noexcept { return true; } @@ -946,14 +946,14 @@ bool InputStateMachineEngine::DispatchIntermediatesFromEscape() const // Return Value: // - True iff we successfully pulled the function type from the parameters bool InputStateMachineEngine::_GetWindowManipulationType(const std::basic_string_view parameters, - unsigned int& function) const + unsigned int& function) const noexcept { bool success = false; function = DispatchTypes::WindowManipulationType::Invalid; if (!parameters.empty()) { - switch (parameters[0]) + switch (til::at(parameters, 0)) { case DispatchTypes::WindowManipulationType::RefreshWindow: function = DispatchTypes::WindowManipulationType::RefreshWindow; @@ -981,7 +981,7 @@ bool InputStateMachineEngine::_GetWindowManipulationType(const std::basic_string // - True if we successfully pulled the cursor coordinates from the parameters we've stored. False otherwise. bool InputStateMachineEngine::_GetXYPosition(const std::basic_string_view parameters, size_t& line, - size_t& column) const + size_t& column) const noexcept { bool success = true; line = DefaultLine; @@ -994,13 +994,13 @@ bool InputStateMachineEngine::_GetXYPosition(const std::basic_string_view intermediates, const std::basic_string_view parameters) override; - bool ActionClear() override; + bool ActionClear() noexcept override; - bool ActionIgnore() override; + bool ActionIgnore() noexcept override; bool ActionOscDispatch(const wchar_t wch, const size_t parameter, - const std::wstring_view string) override; + const std::wstring_view string) noexcept override; bool ActionSs3Dispatch(const wchar_t wch, const std::basic_string_view parameters) override; - bool FlushAtEndOfString() const override; - bool DispatchControlCharsFromEscape() const override; - bool DispatchIntermediatesFromEscape() const override; + bool FlushAtEndOfString() const noexcept override; + bool DispatchControlCharsFromEscape() const noexcept override; + bool DispatchIntermediatesFromEscape() const noexcept override; private: const std::unique_ptr _pDispatch; bool _lookingForDSR; - DWORD _GetCursorKeysModifierState(const std::basic_string_view parameters); - DWORD _GetGenericKeysModifierState(const std::basic_string_view parameters); - bool _GenerateKeyFromChar(const wchar_t wch, short& vkey, DWORD& modifierState); + DWORD _GetCursorKeysModifierState(const std::basic_string_view parameters) noexcept; + DWORD _GetGenericKeysModifierState(const std::basic_string_view parameters) noexcept; + bool _GenerateKeyFromChar(const wchar_t wch, short& vkey, DWORD& modifierState) noexcept; - bool _IsModified(const size_t paramCount); - DWORD _GetModifier(const size_t parameter); + bool _IsModified(const size_t paramCount) noexcept; + DWORD _GetModifier(const size_t parameter) noexcept; bool _GetGenericVkey(const std::basic_string_view parameters, short& vkey) const; @@ -91,13 +91,13 @@ namespace Microsoft::Console::VirtualTerminal std::vector& input); bool _GetWindowManipulationType(const std::basic_string_view parameters, - unsigned int& function) const; + unsigned int& function) const noexcept; static constexpr size_t DefaultLine = 1; static constexpr size_t DefaultColumn = 1; bool _GetXYPosition(const std::basic_string_view parameters, size_t& line, - size_t& column) const; + size_t& column) const noexcept; bool _DoControlCharacter(const wchar_t wch, const bool writeAlt); }; diff --git a/src/terminal/parser/OutputStateMachineEngine.cpp b/src/terminal/parser/OutputStateMachineEngine.cpp index 89aefd4de77..76b4c4e3b59 100644 --- a/src/terminal/parser/OutputStateMachineEngine.cpp +++ b/src/terminal/parser/OutputStateMachineEngine.cpp @@ -17,10 +17,7 @@ OutputStateMachineEngine::OutputStateMachineEngine(std::unique_ptr graphicsOptions; - DispatchTypes::AnsiStatusType deviceStatusType = (DispatchTypes::AnsiStatusType)-1; // there is no default status type. + DispatchTypes::AnsiStatusType deviceStatusType = static_cast(0); // there is no default status type. size_t repeatCount = 0; // This is all the args after the first arg, and the count of args not including the first one. const auto remainingParams = parameters.size() > 1 ? parameters.substr(1) : std::basic_string_view{}; @@ -500,7 +497,7 @@ bool OutputStateMachineEngine::ActionCsiDispatch(const wchar_t wch, } else if (intermediates.size() == 1) { - const auto value = intermediates[0]; + const auto value = til::at(intermediates, 0); switch (value) { case L'?': @@ -653,7 +650,7 @@ bool OutputStateMachineEngine::_IntermediateSpaceDispatch(const wchar_t wchActio // - // Return Value: // - -bool OutputStateMachineEngine::ActionClear() +bool OutputStateMachineEngine::ActionClear() noexcept { // do nothing. return true; @@ -666,7 +663,7 @@ bool OutputStateMachineEngine::ActionClear() // - // Return Value: // - -bool OutputStateMachineEngine::ActionIgnore() +bool OutputStateMachineEngine::ActionIgnore() noexcept { // do nothing. return true; @@ -774,7 +771,7 @@ bool OutputStateMachineEngine::ActionOscDispatch(const wchar_t /*wch*/, // Return Value: // - true iff we successfully dispatched the sequence. bool OutputStateMachineEngine::ActionSs3Dispatch(const wchar_t /*wch*/, - const std::basic_string_view /*parameters*/) + const std::basic_string_view /*parameters*/) noexcept { // The output engine doesn't handle any SS3 sequences. _ClearLastChar(); @@ -825,7 +822,7 @@ bool OutputStateMachineEngine::_GetGraphicsOptions(const std::basic_string_view< // Return Value: // - True if we successfully pulled an erase type from the parameters we've stored. False otherwise. bool OutputStateMachineEngine::_GetEraseOperation(const std::basic_string_view parameters, - DispatchTypes::EraseType& eraseType) const + DispatchTypes::EraseType& eraseType) const noexcept { bool success = false; // If we have too many parameters or don't know what to do with the given value, return false. eraseType = DefaultEraseType; // if we fail, just put the default type in. @@ -839,7 +836,7 @@ bool OutputStateMachineEngine::_GetEraseOperation(const std::basic_string_view(parameters[0]); + const auto param = static_cast(til::at(parameters, 0)); switch (param) { @@ -864,7 +861,7 @@ bool OutputStateMachineEngine::_GetEraseOperation(const std::basic_string_view parameters, - size_t& distance) const + size_t& distance) const noexcept { bool success = false; distance = DefaultCursorDistance; @@ -877,7 +874,7 @@ bool OutputStateMachineEngine::_GetCursorDistance(const std::basic_string_view parameters, - size_t& distance) const + size_t& distance) const noexcept { bool success = false; distance = DefaultScrollDistance; @@ -911,7 +908,7 @@ bool OutputStateMachineEngine::_GetScrollDistance(const std::basic_string_view parameters, - size_t& consoleWidth) const + size_t& consoleWidth) const noexcept { bool success = false; consoleWidth = DefaultConsoleWidth; @@ -945,7 +942,7 @@ bool OutputStateMachineEngine::_GetConsoleWidth(const std::basic_string_view parameters, size_t& line, - size_t& column) const + size_t& column) const noexcept { bool success = false; line = DefaultLine; @@ -982,14 +979,14 @@ bool OutputStateMachineEngine::_GetXYPosition(const std::basic_string_view parameters, size_t& topMargin, - size_t& bottomMargin) const + size_t& bottomMargin) const noexcept { // Notes: (input -> state machine out) // having only a top param is legal ([3;r -> 3,0) @@ -1036,14 +1033,14 @@ bool OutputStateMachineEngine::_GetTopBottomMargins(const std::basic_string_view } else if (parameters.size() == 1) { - topMargin = parameters[0]; + topMargin = til::at(parameters, 0); success = true; } else if (parameters.size() == 2) { // If there are exactly two parameters, use them. - topMargin = parameters[0]; - bottomMargin = parameters[1]; + topMargin = til::at(parameters, 0); + bottomMargin = til::at(parameters, 1); success = true; } @@ -1061,15 +1058,15 @@ bool OutputStateMachineEngine::_GetTopBottomMargins(const std::basic_string_view // Return Value: // - True if we successfully found a device operation in the parameters stored. False otherwise. bool OutputStateMachineEngine::_GetDeviceStatusOperation(const std::basic_string_view parameters, - DispatchTypes::AnsiStatusType& statusType) const + DispatchTypes::AnsiStatusType& statusType) const noexcept { bool success = false; - statusType = (DispatchTypes::AnsiStatusType)0; + statusType = static_cast(0); if (parameters.size() == 1) { // If there's one parameter, attempt to match it to the values we accept. - const auto param = parameters[0]; + const auto param = til::at(parameters, 0); switch (param) { @@ -1112,7 +1109,7 @@ bool OutputStateMachineEngine::_GetPrivateModeParams(const std::basic_string_vie // - parameters - The parameters to parse // Return Value: // - True if there were no parameters. False otherwise. -bool OutputStateMachineEngine::_VerifyHasNoParameters(const std::basic_string_view parameters) const +bool OutputStateMachineEngine::_VerifyHasNoParameters(const std::basic_string_view parameters) const noexcept { return parameters.empty(); } @@ -1124,7 +1121,7 @@ bool OutputStateMachineEngine::_VerifyHasNoParameters(const std::basic_string_vi // - parameters - The parameters to parse // Return Value: // - True if the DA params were valid. False otherwise. -bool OutputStateMachineEngine::_VerifyDeviceAttributesParams(const std::basic_string_view parameters) const +bool OutputStateMachineEngine::_VerifyDeviceAttributesParams(const std::basic_string_view parameters) const noexcept { bool success = false; @@ -1134,7 +1131,7 @@ bool OutputStateMachineEngine::_VerifyDeviceAttributesParams(const std::basic_st } else if (parameters.size() == 1) { - if (parameters[0] == 0) + if (til::at(parameters, 0) == 0) { success = true; } @@ -1166,7 +1163,7 @@ bool OutputStateMachineEngine::_GetOscTitle(const std::wstring_view string, // Return Value: // - True if we successfully pulled the tab distance from the parameters we've stored. False otherwise. bool OutputStateMachineEngine::_GetTabDistance(const std::basic_string_view parameters, - size_t& distance) const + size_t& distance) const noexcept { bool success = false; distance = DefaultTabDistance; @@ -1179,7 +1176,7 @@ bool OutputStateMachineEngine::_GetTabDistance(const std::basic_string_view parameters, - size_t& clearType) const + size_t& clearType) const noexcept { bool success = false; clearType = DefaultTabClearType; @@ -1213,7 +1210,7 @@ bool OutputStateMachineEngine::_GetTabClearType(const std::basic_string_view= L'0' && wch <= L'9'; // 0x30 - 0x39 } @@ -1344,7 +1341,7 @@ bool OutputStateMachineEngine::s_IsNumber(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool OutputStateMachineEngine::s_IsHexNumber(const wchar_t wch) +static constexpr bool _isHexNumber(const wchar_t wch) noexcept { return (wch >= L'0' && wch <= L'9') || // 0x30 - 0x39 (wch >= L'A' && wch <= L'F') || @@ -1363,11 +1360,11 @@ bool OutputStateMachineEngine::s_IsHexNumber(const wchar_t wch) // Return Value: // - True if a color was successfully parsed bool OutputStateMachineEngine::s_ParseColorSpec(const std::wstring_view string, - DWORD& rgb) + DWORD& rgb) noexcept { bool foundRGB = false; bool foundValidColorSpec = false; - unsigned int rguiColorValues[3] = { 0 }; + std::array colorValues = { 0 }; bool success = false; // We can have anywhere between [11,15] characters // 9 "rgb:h/h/h" @@ -1398,18 +1395,18 @@ bool OutputStateMachineEngine::s_ParseColorSpec(const std::wstring_view string, for (size_t component = 0; component < 3; component++) { bool foundColor = false; - unsigned int* const pValue = &(rguiColorValues[component]); + auto& value = colorValues.at(component); for (size_t i = 0; i < 3; i++) { const wchar_t wch = *curr++; - if (s_IsHexNumber(wch)) + if (_isHexNumber(wch)) { - *pValue *= 16; + value *= 16; unsigned int intVal = 0; if (s_HexToUint(wch, intVal)) { - *pValue += intVal; + value += intVal; } else { @@ -1449,9 +1446,9 @@ bool OutputStateMachineEngine::s_ParseColorSpec(const std::wstring_view string, // Only if we find a valid colorspec can we pass it out successfully. if (foundValidColorSpec) { - DWORD color = RGB(LOBYTE(rguiColorValues[0]), - LOBYTE(rguiColorValues[1]), - LOBYTE(rguiColorValues[2])); + DWORD color = RGB(LOBYTE(colorValues.at(0)), + LOBYTE(colorValues.at(1)), + LOBYTE(colorValues.at(2))); rgb = color; success = true; @@ -1473,7 +1470,7 @@ bool OutputStateMachineEngine::s_ParseColorSpec(const std::wstring_view string, // - True if a table index and color was parsed successfully. False otherwise. bool OutputStateMachineEngine::_GetOscSetColorTable(const std::wstring_view string, size_t& tableIndex, - DWORD& rgb) const + DWORD& rgb) const noexcept { tableIndex = 0; rgb = 0; @@ -1497,7 +1494,7 @@ bool OutputStateMachineEngine::_GetOscSetColorTable(const std::wstring_view stri for (size_t i = 0; i < 4; i++) { const wchar_t wch = string.at(current); - if (s_IsNumber(wch)) + if (_isNumber(wch)) { _TableIndex *= 10; _TableIndex += wch - L'0'; @@ -1546,7 +1543,7 @@ bool OutputStateMachineEngine::_GetOscSetColorTable(const std::wstring_view stri // Return Value: // - True if a table index and color was parsed successfully. False otherwise. bool OutputStateMachineEngine::_GetOscSetColor(const std::wstring_view string, - DWORD& rgb) const + DWORD& rgb) const noexcept { rgb = 0; @@ -1574,14 +1571,14 @@ bool OutputStateMachineEngine::_GetOscSetColor(const std::wstring_view string, // Return Value: // - True iff we successfully pulled the function type from the parameters bool OutputStateMachineEngine::_GetWindowManipulationType(const std::basic_string_view parameters, - unsigned int& function) const + unsigned int& function) const noexcept { bool success = false; function = DefaultWindowManipulationType; if (parameters.size() > 0) { - switch (parameters[0]) + switch (til::at(parameters, 0)) { case DispatchTypes::WindowManipulationType::RefreshWindow: function = DispatchTypes::WindowManipulationType::RefreshWindow; @@ -1608,7 +1605,7 @@ bool OutputStateMachineEngine::_GetWindowManipulationType(const std::basic_strin // Return Value: // - True if we successfully pulled the cursor style from the parameters we've stored. False otherwise. bool OutputStateMachineEngine::_GetCursorStyle(const std::basic_string_view parameters, - DispatchTypes::CursorStyle& cursorStyle) const + DispatchTypes::CursorStyle& cursorStyle) const noexcept { bool success = false; cursorStyle = DefaultCursorStyle; @@ -1621,7 +1618,7 @@ bool OutputStateMachineEngine::_GetCursorStyle(const std::basic_string_view pa else if (parameters.size() == 1) { // If there's one parameter, use it. - repeatCount = parameters[0]; + repeatCount = til::at(parameters, 0); success = true; } diff --git a/src/terminal/parser/OutputStateMachineEngine.hpp b/src/terminal/parser/OutputStateMachineEngine.hpp index ab3df051045..0498b2d43d3 100644 --- a/src/terminal/parser/OutputStateMachineEngine.hpp +++ b/src/terminal/parser/OutputStateMachineEngine.hpp @@ -23,7 +23,6 @@ namespace Microsoft::Console::VirtualTerminal { public: OutputStateMachineEngine(std::unique_ptr pDispatch); - ~OutputStateMachineEngine(); bool ActionExecute(const wchar_t wch) override; bool ActionExecuteFromEscape(const wchar_t wch) override; @@ -41,20 +40,20 @@ namespace Microsoft::Console::VirtualTerminal const std::basic_string_view intermediates, const std::basic_string_view parameters) override; - bool ActionClear() override; + bool ActionClear() noexcept override; - bool ActionIgnore() override; + bool ActionIgnore() noexcept override; bool ActionOscDispatch(const wchar_t wch, const size_t parameter, const std::wstring_view string) override; bool ActionSs3Dispatch(const wchar_t wch, - const std::basic_string_view parameters) override; + const std::basic_string_view parameters) noexcept override; - bool FlushAtEndOfString() const override; - bool DispatchControlCharsFromEscape() const override; - bool DispatchIntermediatesFromEscape() const override; + bool FlushAtEndOfString() const noexcept override; + bool DispatchControlCharsFromEscape() const noexcept override; + bool DispatchIntermediatesFromEscape() const noexcept override; void SetTerminalConnection(Microsoft::Console::ITerminalOutputConnection* const pTtyConnection, std::function pfnFlushToTerminal); @@ -152,32 +151,32 @@ namespace Microsoft::Console::VirtualTerminal static constexpr DispatchTypes::EraseType DefaultEraseType = DispatchTypes::EraseType::ToEnd; bool _GetEraseOperation(const std::basic_string_view parameters, - DispatchTypes::EraseType& eraseType) const; + DispatchTypes::EraseType& eraseType) const noexcept; static constexpr size_t DefaultCursorDistance = 1; bool _GetCursorDistance(const std::basic_string_view parameters, - size_t& distance) const; + size_t& distance) const noexcept; static constexpr size_t DefaultScrollDistance = 1; bool _GetScrollDistance(const std::basic_string_view parameters, - size_t& distance) const; + size_t& distance) const noexcept; static constexpr size_t DefaultConsoleWidth = 80; bool _GetConsoleWidth(const std::basic_string_view parameters, - size_t& consoleWidth) const; + size_t& consoleWidth) const noexcept; static constexpr size_t DefaultLine = 1; static constexpr size_t DefaultColumn = 1; bool _GetXYPosition(const std::basic_string_view parameters, size_t& line, - size_t& column) const; + size_t& column) const noexcept; bool _GetDeviceStatusOperation(const std::basic_string_view parameters, - DispatchTypes::AnsiStatusType& statusType) const; + DispatchTypes::AnsiStatusType& statusType) const noexcept; - bool _VerifyHasNoParameters(const std::basic_string_view parameters) const; + bool _VerifyHasNoParameters(const std::basic_string_view parameters) const noexcept; - bool _VerifyDeviceAttributesParams(const std::basic_string_view parameters) const; + bool _VerifyDeviceAttributesParams(const std::basic_string_view parameters) const noexcept; bool _GetPrivateModeParams(const std::basic_string_view parameters, std::vector& privateModes) const; @@ -186,44 +185,42 @@ namespace Microsoft::Console::VirtualTerminal static constexpr size_t DefaultBottomMargin = 0; bool _GetTopBottomMargins(const std::basic_string_view parameters, size_t& topMargin, - size_t& bottomMargin) const; + size_t& bottomMargin) const noexcept; bool _GetOscTitle(const std::wstring_view string, std::wstring& title) const; static constexpr size_t DefaultTabDistance = 1; bool _GetTabDistance(const std::basic_string_view parameters, - size_t& distance) const; + size_t& distance) const noexcept; static constexpr size_t DefaultTabClearType = 0; bool _GetTabClearType(const std::basic_string_view parameters, - size_t& clearType) const; + size_t& clearType) const noexcept; static constexpr DesignateCharsetTypes DefaultDesignateCharsetType = DesignateCharsetTypes::G0; bool _GetDesignateType(const wchar_t intermediate, - DesignateCharsetTypes& designateType) const; + DesignateCharsetTypes& designateType) const noexcept; static constexpr DispatchTypes::WindowManipulationType DefaultWindowManipulationType = DispatchTypes::WindowManipulationType::Invalid; bool _GetWindowManipulationType(const std::basic_string_view parameters, - unsigned int& function) const; + unsigned int& function) const noexcept; static bool s_HexToUint(const wchar_t wch, - unsigned int& value); - static bool s_IsNumber(const wchar_t wch); - static bool s_IsHexNumber(const wchar_t wch); + unsigned int& value) noexcept; bool _GetOscSetColorTable(const std::wstring_view string, size_t& tableIndex, - DWORD& rgb) const; + DWORD& rgb) const noexcept; static bool s_ParseColorSpec(const std::wstring_view string, - DWORD& rgb); + DWORD& rgb) noexcept; bool _GetOscSetColor(const std::wstring_view string, - DWORD& rgb) const; + DWORD& rgb) const noexcept; static constexpr DispatchTypes::CursorStyle DefaultCursorStyle = DispatchTypes::CursorStyle::BlinkingBlockDefault; bool _GetCursorStyle(const std::basic_string_view parameters, - DispatchTypes::CursorStyle& cursorStyle) const; + DispatchTypes::CursorStyle& cursorStyle) const noexcept; static constexpr size_t DefaultRepeatCount = 1; bool _GetRepeatCount(const std::basic_string_view parameters, diff --git a/src/terminal/parser/stateMachine.cpp b/src/terminal/parser/stateMachine.cpp index 681996d0491..77cc20e56f9 100644 --- a/src/terminal/parser/stateMachine.cpp +++ b/src/terminal/parser/stateMachine.cpp @@ -33,15 +33,14 @@ IStateMachineEngine& StateMachine::Engine() noexcept } // Routine Description: -// - Determines if a character indicates an action that should be taken in the ground state - -// These are C0 characters and the C1 [single-character] CSI. +// - Determines if a character is a valid number character, 0-9. // Arguments: // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsActionableFromGround(const wchar_t wch) +static constexpr bool _isNumber(const wchar_t wch) noexcept { - return (wch <= AsciiChars::US) || s_IsC1Csi(wch) || s_IsDelete(wch); + return wch >= L'0' && wch <= L'9'; // 0x30 - 0x39 } // Routine Description: @@ -52,7 +51,7 @@ bool StateMachine::s_IsActionableFromGround(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsC0Code(const wchar_t wch) +static constexpr bool _isC0Code(const wchar_t wch) noexcept { return (wch >= AsciiChars::NUL && wch <= AsciiChars::ETB) || wch == AsciiChars::EM || @@ -78,7 +77,7 @@ bool StateMachine::s_IsC0Code(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsC1Csi(const wchar_t wch) +static constexpr bool _isC1Csi(const wchar_t wch) noexcept { return wch == L'\x9b'; } @@ -92,7 +91,7 @@ bool StateMachine::s_IsC1Csi(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsIntermediate(const wchar_t wch) +static constexpr bool _isIntermediate(const wchar_t wch) noexcept { return wch >= L' ' && wch <= L'/'; // 0x20 - 0x2F } @@ -103,7 +102,7 @@ bool StateMachine::s_IsIntermediate(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsDelete(const wchar_t wch) +static constexpr bool _isDelete(const wchar_t wch) noexcept { return wch == AsciiChars::DEL; } @@ -115,7 +114,7 @@ bool StateMachine::s_IsDelete(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsEscape(const wchar_t wch) +static constexpr bool _isEscape(const wchar_t wch) noexcept { return wch == AsciiChars::ESC; } @@ -127,7 +126,7 @@ bool StateMachine::s_IsEscape(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsCsiIndicator(const wchar_t wch) +static constexpr bool _isCsiIndicator(const wchar_t wch) noexcept { return wch == L'['; // 0x5B } @@ -140,7 +139,7 @@ bool StateMachine::s_IsCsiIndicator(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsCsiDelimiter(const wchar_t wch) +static constexpr bool _isCsiDelimiter(const wchar_t wch) noexcept { return wch == L';'; // 0x3B } @@ -152,7 +151,7 @@ bool StateMachine::s_IsCsiDelimiter(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsCsiParamValue(const wchar_t wch) +static constexpr bool _isCsiParamValue(const wchar_t wch) noexcept { return wch >= L'0' && wch <= L'9'; // 0x30 - 0x39 } @@ -164,7 +163,7 @@ bool StateMachine::s_IsCsiParamValue(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsCsiPrivateMarker(const wchar_t wch) +static constexpr bool _isCsiPrivateMarker(const wchar_t wch) noexcept { return wch == L'<' || wch == L'=' || wch == L'>' || wch == L'?'; // 0x3C - 0x3F } @@ -175,7 +174,7 @@ bool StateMachine::s_IsCsiPrivateMarker(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsCsiInvalid(const wchar_t wch) +static constexpr bool _isCsiInvalid(const wchar_t wch) noexcept { return wch == L':'; // 0x3A } @@ -189,7 +188,7 @@ bool StateMachine::s_IsCsiInvalid(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsSs3Indicator(const wchar_t wch) +static constexpr bool _isSs3Indicator(const wchar_t wch) noexcept { return wch == L'O'; // 0x4F } @@ -201,7 +200,7 @@ bool StateMachine::s_IsSs3Indicator(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsOscIndicator(const wchar_t wch) +static constexpr bool _isOscIndicator(const wchar_t wch) noexcept { return wch == L']'; // 0x5D } @@ -214,7 +213,7 @@ bool StateMachine::s_IsOscIndicator(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsOscDelimiter(const wchar_t wch) +static constexpr bool _isOscDelimiter(const wchar_t wch) noexcept { return wch == L';'; // 0x3B } @@ -227,9 +226,9 @@ bool StateMachine::s_IsOscDelimiter(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsOscParamValue(const wchar_t wch) +static constexpr bool _isOscParamValue(const wchar_t wch) noexcept { - return s_IsNumber(wch); // 0x30 - 0x39 + return _isNumber(wch); // 0x30 - 0x39 } // Routine Description: @@ -238,7 +237,7 @@ bool StateMachine::s_IsOscParamValue(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsOscTerminationInitiator(const wchar_t wch) +static constexpr bool _isOscTerminationInitiator(const wchar_t wch) noexcept { return wch == AsciiChars::ESC; } @@ -249,7 +248,7 @@ bool StateMachine::s_IsOscTerminationInitiator(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsOscInvalid(const wchar_t wch) +static constexpr bool _isOscInvalid(const wchar_t wch) noexcept { return wch <= L'\x17' || wch == L'\x19' || @@ -263,20 +262,21 @@ bool StateMachine::s_IsOscInvalid(const wchar_t wch) // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsOscTerminator(const wchar_t wch) +static constexpr bool _isOscTerminator(const wchar_t wch) noexcept { return wch == L'\x7' || wch == L'\x9C'; // Bell character or C1 terminator } // Routine Description: -// - Determines if a character is a valid number character, 0-9. +// - Determines if a character indicates an action that should be taken in the ground state - +// These are C0 characters and the C1 [single-character] CSI. // Arguments: // - wch - Character to check. // Return Value: // - True if it is. False if it isn't. -bool StateMachine::s_IsNumber(const wchar_t wch) +static constexpr bool _isActionableFromGround(const wchar_t wch) noexcept { - return wch >= L'0' && wch <= L'9'; // 0x30 - 0x39 + return (wch <= AsciiChars::US) || _isC1Csi(wch) || _isDelete(wch); } // Routine Description: @@ -328,7 +328,7 @@ void StateMachine::_ActionEscDispatch(const wchar_t wch) { _trace.TraceOnAction(L"EscDispatch"); - bool success = _engine->ActionEscDispatch(wch, { _intermediates.data(), _intermediates.size() }); + const bool success = _engine->ActionEscDispatch(wch, { _intermediates.data(), _intermediates.size() }); // Trace the result. _trace.DispatchSequenceTrace(success); @@ -351,9 +351,9 @@ void StateMachine::_ActionCsiDispatch(const wchar_t wch) { _trace.TraceOnAction(L"CsiDispatch"); - bool success = _engine->ActionCsiDispatch(wch, - { _intermediates.data(), _intermediates.size() }, - { _parameters.data(), _parameters.size() }); + const bool success = _engine->ActionCsiDispatch(wch, + { _intermediates.data(), _intermediates.size() }, + { _parameters.data(), _parameters.size() }); // Trace the result. _trace.DispatchSequenceTrace(success); @@ -438,7 +438,7 @@ void StateMachine::_ActionClear() // - wch - Character to dispatch. // Return Value: // - -void StateMachine::_ActionIgnore() +void StateMachine::_ActionIgnore() noexcept { // do nothing. _trace.TraceOnAction(L"Ignore"); @@ -481,7 +481,7 @@ void StateMachine::_ActionOscDispatch(const wchar_t wch) { _trace.TraceOnAction(L"OscDispatch"); - bool success = _engine->ActionOscDispatch(wch, _oscParameter, _oscString); + const bool success = _engine->ActionOscDispatch(wch, _oscParameter, _oscString); // Trace the result. _trace.DispatchSequenceTrace(success); @@ -504,7 +504,7 @@ void StateMachine::_ActionSs3Dispatch(const wchar_t wch) { _trace.TraceOnAction(L"Ss3Dispatch"); - bool success = _engine->ActionSs3Dispatch(wch, { _parameters.data(), _parameters.size() }); + const bool success = _engine->ActionSs3Dispatch(wch, { _parameters.data(), _parameters.size() }); // Trace the result. _trace.DispatchSequenceTrace(success); @@ -525,7 +525,7 @@ void StateMachine::_ActionSs3Dispatch(const wchar_t wch) // - // Return Value: // - -void StateMachine::_EnterGround() +void StateMachine::_EnterGround() noexcept { _state = VTStates::Ground; _trace.TraceStateChange(L"Ground"); @@ -555,7 +555,7 @@ void StateMachine::_EnterEscape() // - // Return Value: // - -void StateMachine::_EnterEscapeIntermediate() +void StateMachine::_EnterEscapeIntermediate() noexcept { _state = VTStates::EscapeIntermediate; _trace.TraceStateChange(L"EscapeIntermediate"); @@ -584,7 +584,7 @@ void StateMachine::_EnterCsiEntry() // - // Return Value: // - -void StateMachine::_EnterCsiParam() +void StateMachine::_EnterCsiParam() noexcept { _state = VTStates::CsiParam; _trace.TraceStateChange(L"CsiParam"); @@ -599,7 +599,7 @@ void StateMachine::_EnterCsiParam() // - // Return Value: // - -void StateMachine::_EnterCsiIgnore() +void StateMachine::_EnterCsiIgnore() noexcept { _state = VTStates::CsiIgnore; _trace.TraceStateChange(L"CsiIgnore"); @@ -614,7 +614,7 @@ void StateMachine::_EnterCsiIgnore() // - // Return Value: // - -void StateMachine::_EnterCsiIntermediate() +void StateMachine::_EnterCsiIntermediate() noexcept { _state = VTStates::CsiIntermediate; _trace.TraceStateChange(L"CsiIntermediate"); @@ -628,7 +628,7 @@ void StateMachine::_EnterCsiIntermediate() // - // Return Value: // - -void StateMachine::_EnterOscParam() +void StateMachine::_EnterOscParam() noexcept { _state = VTStates::OscParam; _trace.TraceStateChange(L"OscParam"); @@ -642,7 +642,7 @@ void StateMachine::_EnterOscParam() // - // Return Value: // - -void StateMachine::_EnterOscString() +void StateMachine::_EnterOscString() noexcept { _state = VTStates::OscString; _trace.TraceStateChange(L"OscString"); @@ -657,7 +657,7 @@ void StateMachine::_EnterOscString() // - // Return Value: // - -void StateMachine::_EnterOscTermination() +void StateMachine::_EnterOscTermination() noexcept { _state = VTStates::OscTermination; _trace.TraceStateChange(L"OscTermination"); @@ -686,7 +686,7 @@ void StateMachine::_EnterSs3Entry() // - // Return Value: // - -void StateMachine::_EnterSs3Param() +void StateMachine::_EnterSs3Param() noexcept { _state = VTStates::Ss3Param; _trace.TraceStateChange(L"Ss3Param"); @@ -705,11 +705,11 @@ void StateMachine::_EnterSs3Param() void StateMachine::_EventGround(const wchar_t wch) { _trace.TraceOnEvent(L"Ground"); - if (s_IsC0Code(wch) || s_IsDelete(wch)) + if (_isC0Code(wch) || _isDelete(wch)) { _ActionExecute(wch); } - else if (s_IsC1Csi(wch)) + else if (_isC1Csi(wch)) { _EnterCsiEntry(); } @@ -734,7 +734,7 @@ void StateMachine::_EventGround(const wchar_t wch) void StateMachine::_EventEscape(const wchar_t wch) { _trace.TraceOnEvent(L"Escape"); - if (s_IsC0Code(wch)) + if (_isC0Code(wch)) { if (_engine->DispatchControlCharsFromEscape()) { @@ -746,11 +746,11 @@ void StateMachine::_EventEscape(const wchar_t wch) _ActionExecute(wch); } } - else if (s_IsDelete(wch)) + else if (_isDelete(wch)) { _ActionIgnore(); } - else if (s_IsIntermediate(wch)) + else if (_isIntermediate(wch)) { if (_engine->DispatchIntermediatesFromEscape()) { @@ -763,15 +763,15 @@ void StateMachine::_EventEscape(const wchar_t wch) _EnterEscapeIntermediate(); } } - else if (s_IsCsiIndicator(wch)) + else if (_isCsiIndicator(wch)) { _EnterCsiEntry(); } - else if (s_IsOscIndicator(wch)) + else if (_isOscIndicator(wch)) { _EnterOscParam(); } - else if (s_IsSs3Indicator(wch)) + else if (_isSs3Indicator(wch)) { _EnterSs3Entry(); } @@ -796,15 +796,15 @@ void StateMachine::_EventEscape(const wchar_t wch) void StateMachine::_EventEscapeIntermediate(const wchar_t wch) { _trace.TraceOnEvent(L"EscapeIntermediate"); - if (s_IsC0Code(wch)) + if (_isC0Code(wch)) { _ActionExecute(wch); } - else if (s_IsIntermediate(wch)) + else if (_isIntermediate(wch)) { _ActionCollect(wch); } - else if (s_IsDelete(wch)) + else if (_isDelete(wch)) { _ActionIgnore(); } @@ -832,29 +832,29 @@ void StateMachine::_EventEscapeIntermediate(const wchar_t wch) void StateMachine::_EventCsiEntry(const wchar_t wch) { _trace.TraceOnEvent(L"CsiEntry"); - if (s_IsC0Code(wch)) + if (_isC0Code(wch)) { _ActionExecute(wch); } - else if (s_IsDelete(wch)) + else if (_isDelete(wch)) { _ActionIgnore(); } - else if (s_IsIntermediate(wch)) + else if (_isIntermediate(wch)) { _ActionCollect(wch); _EnterCsiIntermediate(); } - else if (s_IsCsiInvalid(wch)) + else if (_isCsiInvalid(wch)) { _EnterCsiIgnore(); } - else if (s_IsCsiParamValue(wch) || s_IsCsiDelimiter(wch)) + else if (_isCsiParamValue(wch) || _isCsiDelimiter(wch)) { _ActionParam(wch); _EnterCsiParam(); } - else if (s_IsCsiPrivateMarker(wch)) + else if (_isCsiPrivateMarker(wch)) { _ActionCollect(wch); _EnterCsiParam(); @@ -881,19 +881,19 @@ void StateMachine::_EventCsiEntry(const wchar_t wch) void StateMachine::_EventCsiIntermediate(const wchar_t wch) { _trace.TraceOnEvent(L"CsiIntermediate"); - if (s_IsC0Code(wch)) + if (_isC0Code(wch)) { _ActionExecute(wch); } - else if (s_IsIntermediate(wch)) + else if (_isIntermediate(wch)) { _ActionCollect(wch); } - else if (s_IsDelete(wch)) + else if (_isDelete(wch)) { _ActionIgnore(); } - else if (s_IsCsiParamValue(wch) || s_IsCsiInvalid(wch) || s_IsCsiDelimiter(wch) || s_IsCsiPrivateMarker(wch)) + else if (_isCsiParamValue(wch) || _isCsiInvalid(wch) || _isCsiDelimiter(wch) || _isCsiPrivateMarker(wch)) { _EnterCsiIgnore(); } @@ -919,19 +919,19 @@ void StateMachine::_EventCsiIntermediate(const wchar_t wch) void StateMachine::_EventCsiIgnore(const wchar_t wch) { _trace.TraceOnEvent(L"CsiIgnore"); - if (s_IsC0Code(wch)) + if (_isC0Code(wch)) { _ActionExecute(wch); } - else if (s_IsDelete(wch)) + else if (_isDelete(wch)) { _ActionIgnore(); } - else if (s_IsIntermediate(wch)) + else if (_isIntermediate(wch)) { _ActionIgnore(); } - else if (s_IsCsiParamValue(wch) || s_IsCsiInvalid(wch) || s_IsCsiDelimiter(wch) || s_IsCsiPrivateMarker(wch)) + else if (_isCsiParamValue(wch) || _isCsiInvalid(wch) || _isCsiDelimiter(wch) || _isCsiPrivateMarker(wch)) { _ActionIgnore(); } @@ -957,24 +957,24 @@ void StateMachine::_EventCsiIgnore(const wchar_t wch) void StateMachine::_EventCsiParam(const wchar_t wch) { _trace.TraceOnEvent(L"CsiParam"); - if (s_IsC0Code(wch)) + if (_isC0Code(wch)) { _ActionExecute(wch); } - else if (s_IsDelete(wch)) + else if (_isDelete(wch)) { _ActionIgnore(); } - else if (s_IsCsiParamValue(wch) || s_IsCsiDelimiter(wch)) + else if (_isCsiParamValue(wch) || _isCsiDelimiter(wch)) { _ActionParam(wch); } - else if (s_IsIntermediate(wch)) + else if (_isIntermediate(wch)) { _ActionCollect(wch); _EnterCsiIntermediate(); } - else if (s_IsCsiInvalid(wch) || s_IsCsiPrivateMarker(wch)) + else if (_isCsiInvalid(wch) || _isCsiPrivateMarker(wch)) { _EnterCsiIgnore(); } @@ -998,15 +998,15 @@ void StateMachine::_EventCsiParam(const wchar_t wch) void StateMachine::_EventOscParam(const wchar_t wch) { _trace.TraceOnEvent(L"OscParam"); - if (s_IsOscTerminator(wch)) + if (_isOscTerminator(wch)) { _EnterGround(); } - else if (s_IsOscParamValue(wch)) + else if (_isOscParamValue(wch)) { _ActionOscParam(wch); } - else if (s_IsOscDelimiter(wch)) + else if (_isOscDelimiter(wch)) { _EnterOscString(); } @@ -1031,16 +1031,16 @@ void StateMachine::_EventOscParam(const wchar_t wch) void StateMachine::_EventOscString(const wchar_t wch) { _trace.TraceOnEvent(L"OscString"); - if (s_IsOscTerminator(wch)) + if (_isOscTerminator(wch)) { _ActionOscDispatch(wch); _EnterGround(); } - else if (s_IsOscTerminationInitiator(wch)) + else if (_isOscTerminationInitiator(wch)) { _EnterOscTermination(); } - else if (s_IsOscInvalid(wch)) + else if (_isOscInvalid(wch)) { _ActionIgnore(); } @@ -1085,21 +1085,21 @@ void StateMachine::_EventOscTermination(const wchar_t wch) void StateMachine::_EventSs3Entry(const wchar_t wch) { _trace.TraceOnEvent(L"Ss3Entry"); - if (s_IsC0Code(wch)) + if (_isC0Code(wch)) { _ActionExecute(wch); } - else if (s_IsDelete(wch)) + else if (_isDelete(wch)) { _ActionIgnore(); } - else if (s_IsCsiInvalid(wch)) + else if (_isCsiInvalid(wch)) { // It's safe for us to go into the CSI ignore here, because both SS3 and // CSI sequences ignore characters the same way. _EnterCsiIgnore(); } - else if (s_IsCsiParamValue(wch) || s_IsCsiDelimiter(wch)) + else if (_isCsiParamValue(wch) || _isCsiDelimiter(wch)) { _ActionParam(wch); _EnterSs3Param(); @@ -1126,19 +1126,19 @@ void StateMachine::_EventSs3Entry(const wchar_t wch) void StateMachine::_EventSs3Param(const wchar_t wch) { _trace.TraceOnEvent(L"Ss3Param"); - if (s_IsC0Code(wch)) + if (_isC0Code(wch)) { _ActionExecute(wch); } - else if (s_IsDelete(wch)) + else if (_isDelete(wch)) { _ActionIgnore(); } - else if (s_IsCsiParamValue(wch) || s_IsCsiDelimiter(wch)) + else if (_isCsiParamValue(wch) || _isCsiDelimiter(wch)) { _ActionParam(wch); } - else if (s_IsCsiInvalid(wch) || s_IsCsiPrivateMarker(wch)) + else if (_isCsiInvalid(wch) || _isCsiPrivateMarker(wch)) { _EnterCsiIgnore(); } @@ -1166,7 +1166,7 @@ void StateMachine::ProcessCharacter(const wchar_t wch) _ActionExecute(wch); _EnterGround(); } - else if (s_IsEscape(wch) && _state != VTStates::OscString) + else if (_isEscape(wch) && _state != VTStates::OscString) { // Don't go to escape from the OSC string state - ESC can be used to // terminate OSC strings. @@ -1259,7 +1259,7 @@ void StateMachine::ProcessString(const std::wstring_view string) } else { - if (s_IsActionableFromGround(string.at(current))) // If the current char is the start of an escape sequence, or should be executed in ground state... + if (_isActionableFromGround(string.at(current))) // If the current char is the start of an escape sequence, or should be executed in ground state... { _engine->ActionPrintString(_run); // ... print all the chars leading up to it as part of the run... _trace.DispatchPrintRunTrace(_run); @@ -1356,7 +1356,7 @@ void StateMachine::ProcessString(const std::wstring_view string) // - // Return Value: // - -void StateMachine::ResetState() +void StateMachine::ResetState() noexcept { _EnterGround(); } diff --git a/src/terminal/parser/stateMachine.hpp b/src/terminal/parser/stateMachine.hpp index e6c9a34daaf..e2b521f2c80 100644 --- a/src/terminal/parser/stateMachine.hpp +++ b/src/terminal/parser/stateMachine.hpp @@ -34,7 +34,7 @@ namespace Microsoft::Console::VirtualTerminal void ProcessCharacter(const wchar_t wch); void ProcessString(const std::wstring_view string); - void ResetState(); + void ResetState() noexcept; bool FlushToTerminal(); @@ -42,26 +42,6 @@ namespace Microsoft::Console::VirtualTerminal IStateMachineEngine& Engine() noexcept; private: - static bool s_IsActionableFromGround(const wchar_t wch); - static bool s_IsC0Code(const wchar_t wch); - static bool s_IsC1Csi(const wchar_t wch); - static bool s_IsIntermediate(const wchar_t wch); - static bool s_IsDelete(const wchar_t wch); - static bool s_IsEscape(const wchar_t wch); - static bool s_IsCsiIndicator(const wchar_t wch); - static bool s_IsCsiDelimiter(const wchar_t wch); - static bool s_IsCsiParamValue(const wchar_t wch); - static bool s_IsCsiPrivateMarker(const wchar_t wch); - static bool s_IsCsiInvalid(const wchar_t wch); - static bool s_IsOscIndicator(const wchar_t wch); - static bool s_IsOscDelimiter(const wchar_t wch); - static bool s_IsOscParamValue(const wchar_t wch); - static bool s_IsOscInvalid(const wchar_t wch); - static bool s_IsOscTerminator(const wchar_t wch); - static bool s_IsOscTerminationInitiator(const wchar_t wch); - static bool s_IsNumber(const wchar_t wch); - static bool s_IsSs3Indicator(const wchar_t wch); - void _ActionExecute(const wchar_t wch); void _ActionExecuteFromEscape(const wchar_t wch); void _ActionPrint(const wchar_t wch); @@ -75,20 +55,20 @@ namespace Microsoft::Console::VirtualTerminal void _ActionSs3Dispatch(const wchar_t wch); void _ActionClear(); - void _ActionIgnore(); + void _ActionIgnore() noexcept; - void _EnterGround(); + void _EnterGround() noexcept; void _EnterEscape(); - void _EnterEscapeIntermediate(); + void _EnterEscapeIntermediate() noexcept; void _EnterCsiEntry(); - void _EnterCsiParam(); - void _EnterCsiIgnore(); - void _EnterCsiIntermediate(); - void _EnterOscParam(); - void _EnterOscString(); - void _EnterOscTermination(); + void _EnterCsiParam() noexcept; + void _EnterCsiIgnore() noexcept; + void _EnterCsiIntermediate() noexcept; + void _EnterOscParam() noexcept; + void _EnterOscString() noexcept; + void _EnterOscTermination() noexcept; void _EnterSs3Entry(); - void _EnterSs3Param(); + void _EnterSs3Param() noexcept; void _EventGround(const wchar_t wch); void _EventEscape(const wchar_t wch); diff --git a/src/terminal/parser/telemetry.cpp b/src/terminal/parser/telemetry.cpp index fbb84fce901..670ced82461 100644 --- a/src/terminal/parser/telemetry.cpp +++ b/src/terminal/parser/telemetry.cpp @@ -5,6 +5,13 @@ #include "telemetry.hpp" +#pragma warning(push) +#pragma warning(disable : 26494) // _Tlgdata uninitialized from TraceLoggingWrite +#pragma warning(disable : 26477) // Use nullptr instead of NULL or 0 from TraceLoggingWrite +#pragma warning(disable : 26485) // _Tlgdata, no array to pointer decay from TraceLoggingWrite +#pragma warning(disable : 26446) // Prefer gsl::at over unchecked subscript from TraceLoggingLevel +#pragma warning(disable : 26482) // Only index to arrays with constant expressions from TraceLoggingLevel + TRACELOGGING_DEFINE_PROVIDER(g_hConsoleVirtTermParserEventTraceProvider, "Microsoft.Windows.Console.VirtualTerminal.Parser", // {c9ba2a84-d3ca-5e19-2bd6-776a0910cb9d} @@ -15,7 +22,7 @@ using namespace Microsoft::Console::VirtualTerminal; #pragma warning(push) // Disable 4351 so we can initialize the arrays to 0 without a warning. #pragma warning(disable : 4351) -TermTelemetry::TermTelemetry() : +TermTelemetry::TermTelemetry() noexcept : _uiTimesUsedCurrent(0), _uiTimesFailedCurrent(0), _uiTimesFailedOutsideRangeCurrent(0), @@ -34,8 +41,12 @@ TermTelemetry::TermTelemetry() : TermTelemetry::~TermTelemetry() { - WriteFinalTraceLog(); - TraceLoggingUnregister(g_hConsoleVirtTermParserEventTraceProvider); + try + { + WriteFinalTraceLog(); + TraceLoggingUnregister(g_hConsoleVirtTermParserEventTraceProvider); + } + CATCH_LOG() } // Routine Description: @@ -45,7 +56,7 @@ TermTelemetry::~TermTelemetry() // - code - VT100 code. // Return Value: // - -void TermTelemetry::Log(const Codes code) +void TermTelemetry::Log(const Codes code) noexcept { // Initially we wanted to pass over a string (ex. "CUU") and use a dictionary data type to hold the counts. // However we would have to search through the dictionary every time we called this method, so we decided @@ -63,7 +74,7 @@ void TermTelemetry::Log(const Codes code) // - code - VT100 code. // Return Value: // - -void TermTelemetry::LogFailed(const wchar_t wch) +void TermTelemetry::LogFailed(const wchar_t wch) noexcept { if (wch > CHAR_MAX) { @@ -85,11 +96,11 @@ void TermTelemetry::LogFailed(const wchar_t wch) // - // Return Value: // - total number. -unsigned int TermTelemetry::GetAndResetTimesUsedCurrent() +unsigned int TermTelemetry::GetAndResetTimesUsedCurrent() noexcept { - unsigned int uiTemp = _uiTimesUsedCurrent; + const auto temp = _uiTimesUsedCurrent; _uiTimesUsedCurrent = 0; - return uiTemp; + return temp; } // Routine Description: @@ -99,11 +110,11 @@ unsigned int TermTelemetry::GetAndResetTimesUsedCurrent() // - // Return Value: // - total number. -unsigned int TermTelemetry::GetAndResetTimesFailedCurrent() +unsigned int TermTelemetry::GetAndResetTimesFailedCurrent() noexcept { - unsigned int uiTemp = _uiTimesFailedCurrent; + const auto temp = _uiTimesFailedCurrent; _uiTimesFailedCurrent = 0; - return uiTemp; + return temp; } // Routine Description: @@ -113,11 +124,11 @@ unsigned int TermTelemetry::GetAndResetTimesFailedCurrent() // - // Return Value: // - total number. -unsigned int TermTelemetry::GetAndResetTimesFailedOutsideRangeCurrent() +unsigned int TermTelemetry::GetAndResetTimesFailedOutsideRangeCurrent() noexcept { - unsigned int uiTemp = _uiTimesFailedOutsideRangeCurrent; + const auto temp = _uiTimesFailedOutsideRangeCurrent; _uiTimesFailedOutsideRangeCurrent = 0; - return uiTemp; + return temp; } // Routine Description: @@ -128,7 +139,7 @@ unsigned int TermTelemetry::GetAndResetTimesFailedOutsideRangeCurrent() // - writeLog - true if we should write the log. // Return Value: // - -void TermTelemetry::SetShouldWriteFinalLog(const bool writeLog) +void TermTelemetry::SetShouldWriteFinalLog(const bool writeLog) noexcept { _fShouldWriteFinalLog = writeLog; } @@ -140,7 +151,7 @@ void TermTelemetry::SetShouldWriteFinalLog(const bool writeLog) // - activityId - Pointer to Guid to set our activity Id to. // Return Value: // - -void TermTelemetry::SetActivityId(const GUID* activityId) +void TermTelemetry::SetActivityId(const GUID* activityId) noexcept { _activityId = *activityId; } @@ -252,3 +263,5 @@ void TermTelemetry::WriteFinalTraceLog() const } } } + +#pragma warning(pop) diff --git a/src/terminal/parser/telemetry.hpp b/src/terminal/parser/telemetry.hpp index e26cb8c9a07..91343f81f15 100644 --- a/src/terminal/parser/telemetry.hpp +++ b/src/terminal/parser/telemetry.hpp @@ -24,7 +24,7 @@ namespace Microsoft::Console::VirtualTerminal { public: // Implement this as a singleton class. - static TermTelemetry& Instance() + static TermTelemetry& Instance() noexcept { static TermTelemetry s_Instance; return s_Instance; @@ -88,20 +88,22 @@ namespace Microsoft::Console::VirtualTerminal // Only use this last enum as a count of the number of codes. NUMBER_OF_CODES }; - void Log(const Codes code); - void LogFailed(const wchar_t wch); - void SetShouldWriteFinalLog(const bool writeLog); - void SetActivityId(const GUID* activityId); - unsigned int GetAndResetTimesUsedCurrent(); - unsigned int GetAndResetTimesFailedCurrent(); - unsigned int GetAndResetTimesFailedOutsideRangeCurrent(); + void Log(const Codes code) noexcept; + void LogFailed(const wchar_t wch) noexcept; + void SetShouldWriteFinalLog(const bool writeLog) noexcept; + void SetActivityId(const GUID* activityId) noexcept; + unsigned int GetAndResetTimesUsedCurrent() noexcept; + unsigned int GetAndResetTimesFailedCurrent() noexcept; + unsigned int GetAndResetTimesFailedOutsideRangeCurrent() noexcept; private: // Used to prevent multiple instances - TermTelemetry(); + TermTelemetry() noexcept; ~TermTelemetry(); - TermTelemetry(TermTelemetry const&); - void operator=(TermTelemetry const&); + TermTelemetry(TermTelemetry const&) = delete; + TermTelemetry(TermTelemetry&&) = delete; + TermTelemetry& operator=(const TermTelemetry&) = delete; + TermTelemetry& operator=(TermTelemetry&&) = delete; void WriteFinalTraceLog() const; diff --git a/src/terminal/parser/tracing.cpp b/src/terminal/parser/tracing.cpp index cbdbf8cee06..54f689017ea 100644 --- a/src/terminal/parser/tracing.cpp +++ b/src/terminal/parser/tracing.cpp @@ -6,16 +6,19 @@ using namespace Microsoft::Console::VirtualTerminal; -ParserTracing::ParserTracing() +#pragma warning(push) +#pragma warning(disable : 26494) // _Tlgdata uninitialized from TraceLoggingWrite +#pragma warning(disable : 26477) // Use nullptr instead of NULL or 0 from TraceLoggingWrite +#pragma warning(disable : 26485) // _Tlgdata, no array to pointer decay from TraceLoggingWrite +#pragma warning(disable : 26446) // Prefer gsl::at over unchecked subscript from TraceLoggingLevel +#pragma warning(disable : 26482) // Only index to arrays with constant expressions from TraceLoggingLevel + +ParserTracing::ParserTracing() noexcept { ClearSequenceTrace(); } -ParserTracing::~ParserTracing() -{ -} - -void ParserTracing::TraceStateChange(const std::wstring_view name) const +void ParserTracing::TraceStateChange(const std::wstring_view name) const noexcept { TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider, "StateMachine_EnterState", @@ -23,7 +26,7 @@ void ParserTracing::TraceStateChange(const std::wstring_view name) const TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE)); } -void ParserTracing::TraceOnAction(const std::wstring_view name) const +void ParserTracing::TraceOnAction(const std::wstring_view name) const noexcept { TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider, "StateMachine_Action", @@ -33,7 +36,7 @@ void ParserTracing::TraceOnAction(const std::wstring_view name) const void ParserTracing::TraceOnExecute(const wchar_t wch) const { - INT16 sch = (INT16)wch; + const auto sch = gsl::narrow_cast(wch); TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider, "StateMachine_Execute", TraceLoggingWChar(wch), @@ -43,7 +46,7 @@ void ParserTracing::TraceOnExecute(const wchar_t wch) const void ParserTracing::TraceOnExecuteFromEscape(const wchar_t wch) const { - INT16 sch = (INT16)wch; + const auto sch = gsl::narrow_cast(wch); TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider, "StateMachine_ExecuteFromEscape", TraceLoggingWChar(wch), @@ -51,7 +54,7 @@ void ParserTracing::TraceOnExecuteFromEscape(const wchar_t wch) const TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE)); } -void ParserTracing::TraceOnEvent(const std::wstring_view name) const +void ParserTracing::TraceOnEvent(const std::wstring_view name) const noexcept { TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider, "StateMachine_Event", @@ -62,7 +65,7 @@ void ParserTracing::TraceOnEvent(const std::wstring_view name) const void ParserTracing::TraceCharInput(const wchar_t wch) { AddSequenceTrace(wch); - INT16 sch = (INT16)wch; + const auto sch = gsl::narrow_cast(wch); TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider, "StateMachine_NewChar", @@ -76,7 +79,7 @@ void ParserTracing::AddSequenceTrace(const wchar_t wch) _sequenceTrace.push_back(wch); } -void ParserTracing::DispatchSequenceTrace(const bool fSuccess) +void ParserTracing::DispatchSequenceTrace(const bool fSuccess) noexcept { if (fSuccess) { @@ -96,7 +99,7 @@ void ParserTracing::DispatchSequenceTrace(const bool fSuccess) ClearSequenceTrace(); } -void ParserTracing::ClearSequenceTrace() +void ParserTracing::ClearSequenceTrace() noexcept { _sequenceTrace.clear(); } @@ -106,8 +109,8 @@ void ParserTracing::DispatchPrintRunTrace(const std::wstring_view string) const { if (string.size() == 1) { - wchar_t wch = string.front(); - INT16 sch = (INT16)wch; + const auto wch = til::at(string, 0); + const auto sch = gsl::narrow_cast(wch); TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider, "StateMachine_PrintRun", TraceLoggingWChar(wch), @@ -125,3 +128,5 @@ void ParserTracing::DispatchPrintRunTrace(const std::wstring_view string) const TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE)); } } + +#pragma warning(pop) diff --git a/src/terminal/parser/tracing.hpp b/src/terminal/parser/tracing.hpp index 2547d047ad4..05e71267459 100644 --- a/src/terminal/parser/tracing.hpp +++ b/src/terminal/parser/tracing.hpp @@ -21,19 +21,18 @@ namespace Microsoft::Console::VirtualTerminal class ParserTracing sealed { public: - ParserTracing(); - ~ParserTracing(); + ParserTracing() noexcept; - void TraceStateChange(const std::wstring_view name) const; - void TraceOnAction(const std::wstring_view name) const; + void TraceStateChange(const std::wstring_view name) const noexcept; + void TraceOnAction(const std::wstring_view name) const noexcept; void TraceOnExecute(const wchar_t wch) const; void TraceOnExecuteFromEscape(const wchar_t wch) const; - void TraceOnEvent(const std::wstring_view name) const; + void TraceOnEvent(const std::wstring_view name) const noexcept; void TraceCharInput(const wchar_t wch); void AddSequenceTrace(const wchar_t wch); - void DispatchSequenceTrace(const bool fSuccess); - void ClearSequenceTrace(); + void DispatchSequenceTrace(const bool fSuccess) noexcept; + void ClearSequenceTrace() noexcept; void DispatchPrintRunTrace(const std::wstring_view string) const; private: diff --git a/src/terminal/parser/ut_parser/OutputEngineTest.cpp b/src/terminal/parser/ut_parser/OutputEngineTest.cpp index 719c4efcc7c..79426542806 100644 --- a/src/terminal/parser/ut_parser/OutputEngineTest.cpp +++ b/src/terminal/parser/ut_parser/OutputEngineTest.cpp @@ -689,63 +689,63 @@ class StatefulDispatch final : public TermDispatch *this = dispatch; } - bool CursorUp(_In_ size_t const uiDistance) override + bool CursorUp(_In_ size_t const uiDistance) noexcept override { _cursorUp = true; _cursorDistance = uiDistance; return true; } - bool CursorDown(_In_ size_t const uiDistance) override + bool CursorDown(_In_ size_t const uiDistance) noexcept override { _cursorDown = true; _cursorDistance = uiDistance; return true; } - bool CursorBackward(_In_ size_t const uiDistance) override + bool CursorBackward(_In_ size_t const uiDistance) noexcept override { _cursorBackward = true; _cursorDistance = uiDistance; return true; } - bool CursorForward(_In_ size_t const uiDistance) override + bool CursorForward(_In_ size_t const uiDistance) noexcept override { _cursorForward = true; _cursorDistance = uiDistance; return true; } - bool CursorNextLine(_In_ size_t const uiDistance) override + bool CursorNextLine(_In_ size_t const uiDistance) noexcept override { _cursorNextLine = true; _cursorDistance = uiDistance; return true; } - bool CursorPrevLine(_In_ size_t const uiDistance) override + bool CursorPrevLine(_In_ size_t const uiDistance) noexcept override { _cursorPreviousLine = true; _cursorDistance = uiDistance; return true; } - bool CursorHorizontalPositionAbsolute(_In_ size_t const uiPosition) override + bool CursorHorizontalPositionAbsolute(_In_ size_t const uiPosition) noexcept override { _cursorHorizontalPositionAbsolute = true; _cursorDistance = uiPosition; return true; } - bool VerticalLinePositionAbsolute(_In_ size_t const uiPosition) override + bool VerticalLinePositionAbsolute(_In_ size_t const uiPosition) noexcept override { _verticalLinePositionAbsolute = true; _cursorDistance = uiPosition; return true; } - bool CursorPosition(_In_ size_t const uiLine, _In_ size_t const uiColumn) override + bool CursorPosition(_In_ size_t const uiLine, _In_ size_t const uiColumn) noexcept override { _cursorPosition = true; _line = uiLine; @@ -753,61 +753,62 @@ class StatefulDispatch final : public TermDispatch return true; } - bool CursorSaveState() override + bool CursorSaveState() noexcept override { _cursorSave = true; return true; } - bool CursorRestoreState() override + bool CursorRestoreState() noexcept override { _cursorLoad = true; return true; } - bool EraseInDisplay(const DispatchTypes::EraseType eraseType) override + bool EraseInDisplay(const DispatchTypes::EraseType eraseType) noexcept override { _eraseDisplay = true; _eraseType = eraseType; return true; } - bool EraseInLine(const DispatchTypes::EraseType eraseType) override + bool EraseInLine(const DispatchTypes::EraseType eraseType) noexcept override { _eraseLine = true; _eraseType = eraseType; return true; } - bool InsertCharacter(_In_ size_t const uiCount) override + bool InsertCharacter(_In_ size_t const uiCount) noexcept override { _insertCharacter = true; _cursorDistance = uiCount; return true; } - bool DeleteCharacter(_In_ size_t const uiCount) override + bool DeleteCharacter(_In_ size_t const uiCount) noexcept override { _deleteCharacter = true; _cursorDistance = uiCount; return true; } - bool CursorVisibility(const bool fIsVisible) override + bool CursorVisibility(const bool fIsVisible) noexcept override { _cursorVisible = fIsVisible; return true; } - bool SetGraphicsRendition(const std::basic_string_view options) override + bool SetGraphicsRendition(const std::basic_string_view options) noexcept override + try { _options.assign(options.cbegin(), options.cend()); _setGraphics = true; - return true; } + CATCH_LOG_RETURN_FALSE() - bool DeviceStatusReport(const DispatchTypes::AnsiStatusType statusType) override + bool DeviceStatusReport(const DispatchTypes::AnsiStatusType statusType) noexcept override { _deviceStatusReport = true; _statusReportType = statusType; @@ -815,7 +816,7 @@ class StatefulDispatch final : public TermDispatch return true; } - bool DeviceAttributes() override + bool DeviceAttributes() noexcept override { _deviceAttributes = true; @@ -869,53 +870,53 @@ class StatefulDispatch final : public TermDispatch return cFailures == 0; } - bool SetPrivateModes(const std::basic_string_view params) override + bool SetPrivateModes(const std::basic_string_view params) noexcept override { return _SetResetPrivateModesHelper(params, true); } - bool ResetPrivateModes(const std::basic_string_view params) override + bool ResetPrivateModes(const std::basic_string_view params) noexcept override { return _SetResetPrivateModesHelper(params, false); } - bool SetColumns(_In_ size_t const uiColumns) override + bool SetColumns(_In_ size_t const uiColumns) noexcept override { _windowWidth = uiColumns; return true; } - bool SetVirtualTerminalInputMode(const bool fApplicationMode) + bool SetVirtualTerminalInputMode(const bool fApplicationMode) noexcept { _cursorKeysMode = fApplicationMode; return true; } - bool EnableCursorBlinking(const bool bEnable) override + bool EnableCursorBlinking(const bool bEnable) noexcept override { _cursorBlinking = bEnable; return true; } - bool SetOriginMode(const bool fRelativeMode) override + bool SetOriginMode(const bool fRelativeMode) noexcept override { _isOriginModeRelative = fRelativeMode; return true; } - bool EnableDECCOLMSupport(const bool fEnabled) override + bool EnableDECCOLMSupport(const bool fEnabled) noexcept override { _isDECCOLMAllowed = fEnabled; return true; } - bool UseAlternateScreenBuffer() override + bool UseAlternateScreenBuffer() noexcept override { _isAltBuffer = true; return true; } - bool UseMainScreenBuffer() override + bool UseMainScreenBuffer() noexcept override { _isAltBuffer = false; return true; diff --git a/src/types/inc/utils.hpp b/src/types/inc/utils.hpp index 6dfa216ab4d..ff1c8dd1781 100644 --- a/src/types/inc/utils.hpp +++ b/src/types/inc/utils.hpp @@ -11,19 +11,6 @@ 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;