Apply audit mode to TerminalInput/Adapter/Parser libraries (#4005)

<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
- Enables auditing of Virtual Terminal libraries (input, adapter, parser)

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Rolls audit out to more things
* [x] I work here
* [x] Tests should still pass
* [x] Am core contributor
* [x] Closes #3957

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
This is turning on the auditing of these projects (as enabled by the heavier lifting in the other refactor) and then cleaning up the remaining warnings.

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
- [x] Built it
- [x] Ran the tests
This commit is contained in:
Michael Niksa 2020-01-03 06:25:21 -08:00 committed by msftbot[bot]
parent f467422912
commit 322989d017
36 changed files with 1162 additions and 1271 deletions

View file

@ -353,8 +353,8 @@ Global
{2FD12FBB-1DDB-46D8-B818-1023C624CACA}.Release|x86.Build.0 = Release|Win32 {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|Any CPU.ActiveCfg = AuditMode|Win32
{3AE13314-1939-4DFA-9C14-38CA0834050C}.AuditMode|ARM64.ActiveCfg = Release|ARM64 {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.ActiveCfg = AuditMode|x64
{3AE13314-1939-4DFA-9C14-38CA0834050C}.AuditMode|x64.Build.0 = Release|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}.AuditMode|x86.ActiveCfg = Release|Win32
{3AE13314-1939-4DFA-9C14-38CA0834050C}.Debug|Any CPU.ActiveCfg = Debug|Win32 {3AE13314-1939-4DFA-9C14-38CA0834050C}.Debug|Any CPU.ActiveCfg = Debug|Win32
{3AE13314-1939-4DFA-9C14-38CA0834050C}.Debug|ARM64.ActiveCfg = Debug|ARM64 {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 {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|Any CPU.ActiveCfg = AuditMode|Win32
{DCF55140-EF6A-4736-A403-957E4F7430BB}.AuditMode|ARM64.ActiveCfg = Release|ARM64 {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}.AuditMode|x86.ActiveCfg = Release|Win32
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|Any CPU.ActiveCfg = Debug|Win32 {DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|Any CPU.ActiveCfg = Debug|Win32
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|ARM64.ActiveCfg = Debug|ARM64 {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 {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|Any CPU.ActiveCfg = AuditMode|Win32
{1CF55140-EF6A-4736-A403-957E4F7430BB}.AuditMode|ARM64.ActiveCfg = Release|ARM64 {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.ActiveCfg = AuditMode|x64
{1CF55140-EF6A-4736-A403-957E4F7430BB}.AuditMode|x64.Build.0 = Release|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}.AuditMode|x86.ActiveCfg = Release|Win32
{1CF55140-EF6A-4736-A403-957E4F7430BB}.Debug|Any CPU.ActiveCfg = Debug|Win32 {1CF55140-EF6A-4736-A403-957E4F7430BB}.Debug|Any CPU.ActiveCfg = Debug|Win32
{1CF55140-EF6A-4736-A403-957E4F7430BB}.Debug|ARM64.ActiveCfg = Debug|ARM64 {1CF55140-EF6A-4736-A403-957E4F7430BB}.Debug|ARM64.ActiveCfg = Debug|ARM64

View file

@ -31,7 +31,7 @@ void TerminalDispatch::PrintString(const std::wstring_view string)
} }
bool TerminalDispatch::CursorPosition(const size_t line, bool TerminalDispatch::CursorPosition(const size_t line,
const size_t column) const size_t column) noexcept
{ {
const auto columnInBufferSpace = column - 1; const auto columnInBufferSpace = column - 1;
const auto lineInBufferSpace = line - 1; const auto lineInBufferSpace = line - 1;
@ -40,33 +40,33 @@ bool TerminalDispatch::CursorPosition(const size_t line,
return _terminalApi.SetCursorPosition(x, y); 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 auto cursorPos = _terminalApi.GetCursorPosition();
const COORD newCursorPos{ cursorPos.X + gsl::narrow<short>(distance), cursorPos.Y }; const COORD newCursorPos{ cursorPos.X + gsl::narrow<short>(distance), cursorPos.Y };
return _terminalApi.SetCursorPosition(newCursorPos.X, newCursorPos.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 auto cursorPos = _terminalApi.GetCursorPosition();
const COORD newCursorPos{ cursorPos.X - gsl::narrow<short>(distance), cursorPos.Y }; const COORD newCursorPos{ cursorPos.X - gsl::narrow<short>(distance), cursorPos.Y };
return _terminalApi.SetCursorPosition(newCursorPos.X, newCursorPos.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 auto cursorPos = _terminalApi.GetCursorPosition();
const COORD newCursorPos{ cursorPos.X, cursorPos.Y + gsl::narrow<short>(distance) }; const COORD newCursorPos{ cursorPos.X, cursorPos.Y + gsl::narrow<short>(distance) };
return _terminalApi.SetCursorPosition(newCursorPos.X, newCursorPos.Y); 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); return _terminalApi.EraseCharacters(numChars);
} }
bool TerminalDispatch::SetWindowTitle(std::wstring_view title) bool TerminalDispatch::SetWindowTitle(std::wstring_view title) noexcept
{ {
return _terminalApi.SetWindowTitle(title); return _terminalApi.SetWindowTitle(title);
} }
@ -79,12 +79,12 @@ bool TerminalDispatch::SetWindowTitle(std::wstring_view title)
// Return Value: // Return Value:
// True if handled successfully. False otherwise. // True if handled successfully. False otherwise.
bool TerminalDispatch::SetColorTableEntry(const size_t tableIndex, bool TerminalDispatch::SetColorTableEntry(const size_t tableIndex,
const DWORD color) const DWORD color) noexcept
{ {
return _terminalApi.SetColorTableEntry(tableIndex, color); return _terminalApi.SetColorTableEntry(tableIndex, color);
} }
bool TerminalDispatch::SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle) bool TerminalDispatch::SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle) noexcept
{ {
return _terminalApi.SetCursorStyle(cursorStyle); 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 // - color: The new RGB color value to use, in 0x00BBGGRR form
// Return Value: // Return Value:
// True if handled successfully. False otherwise. // True if handled successfully. False otherwise.
bool TerminalDispatch::SetDefaultForeground(const DWORD color) bool TerminalDispatch::SetDefaultForeground(const DWORD color) noexcept
{ {
return _terminalApi.SetDefaultForeground(color); 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 // - color: The new RGB color value to use, in 0x00BBGGRR form
// Return Value: // Return Value:
// True if handled successfully. False otherwise. // True if handled successfully. False otherwise.
bool TerminalDispatch::SetDefaultBackground(const DWORD color) bool TerminalDispatch::SetDefaultBackground(const DWORD color) noexcept
{ {
return _terminalApi.SetDefaultBackground(color); return _terminalApi.SetDefaultBackground(color);
} }
@ -117,7 +117,7 @@ bool TerminalDispatch::SetDefaultBackground(const DWORD color)
// - eraseType: the erase type (from beginning, to end, or all) // - eraseType: the erase type (from beginning, to end, or all)
// Return Value: // Return Value:
// True if handled successfully. False otherwise. // 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); return _terminalApi.EraseInLine(eraseType);
} }
@ -128,7 +128,7 @@ bool TerminalDispatch::EraseInLine(const DispatchTypes::EraseType eraseType)
// - count, the number of characters to delete // - count, the number of characters to delete
// Return Value: // Return Value:
// True if handled successfully. False otherwise. // 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); return _terminalApi.DeleteCharacter(count);
} }
@ -139,7 +139,7 @@ bool TerminalDispatch::DeleteCharacter(const size_t count)
// - count, the number of spaces to add // - count, the number of spaces to add
// Return Value: // Return Value:
// True if handled successfully, false otherwise // 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); return _terminalApi.InsertCharacter(count);
} }
@ -150,7 +150,7 @@ bool TerminalDispatch::InsertCharacter(const size_t count)
// - eraseType: the desired erase type // - eraseType: the desired erase type
// Return Value: // Return Value:
// True if handled successfully. False otherwise // 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); return _terminalApi.EraseInDisplay(eraseType);
} }

View file

@ -13,27 +13,27 @@ public:
virtual void Print(const wchar_t wchPrintable) override; virtual void Print(const wchar_t wchPrintable) override;
virtual void PrintString(const std::wstring_view string) 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, 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 CursorForward(const size_t distance) noexcept override;
bool CursorBackward(const size_t distance) override; bool CursorBackward(const size_t distance) noexcept override;
bool CursorUp(const size_t distance) override; bool CursorUp(const size_t distance) noexcept override;
bool EraseCharacters(const size_t numChars) override; bool EraseCharacters(const size_t numChars) noexcept override;
bool SetWindowTitle(std::wstring_view title) override; bool SetWindowTitle(std::wstring_view title) noexcept override;
bool SetColorTableEntry(const size_t tableIndex, const DWORD color) override; bool SetColorTableEntry(const size_t tableIndex, const DWORD color) noexcept override;
bool SetCursorStyle(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::CursorStyle cursorStyle) override; bool SetCursorStyle(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::CursorStyle cursorStyle) noexcept override;
bool SetDefaultForeground(const DWORD color) override; bool SetDefaultForeground(const DWORD color) noexcept override;
bool SetDefaultBackground(const DWORD color) override; bool SetDefaultBackground(const DWORD color) noexcept override;
bool EraseInLine(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) override; // ED bool EraseInLine(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) noexcept override; // ED
bool DeleteCharacter(const size_t count) override; bool DeleteCharacter(const size_t count) noexcept override;
bool InsertCharacter(const size_t count) override; bool InsertCharacter(const size_t count) noexcept override;
bool EraseInDisplay(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) override; bool EraseInDisplay(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) noexcept override;
private: private:
::Microsoft::Terminal::Core::ITerminalApi& _terminalApi; ::Microsoft::Terminal::Core::ITerminalApi& _terminalApi;

View file

@ -287,7 +287,7 @@ void TerminalDispatch::_SetGraphicsOptionHelper(const DispatchTypes::GraphicsOpt
} }
} }
bool TerminalDispatch::SetGraphicsRendition(const std::basic_string_view<DispatchTypes::GraphicsOptions> options) bool TerminalDispatch::SetGraphicsRendition(const std::basic_string_view<DispatchTypes::GraphicsOptions> options) noexcept
{ {
bool success = false; bool success = false;
// Run through the graphics options and apply them // Run through the graphics options and apply them

View file

@ -19,6 +19,8 @@ namespace Microsoft::Console
class ITerminalOutputConnection class ITerminalOutputConnection
{ {
public: 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; virtual ~ITerminalOutputConnection() = 0;
[[nodiscard]] virtual HRESULT WriteTerminalUtf8(const std::string_view str) = 0; [[nodiscard]] virtual HRESULT WriteTerminalUtf8(const std::string_view str) = 0;
@ -26,4 +28,5 @@ namespace Microsoft::Console
}; };
inline Microsoft::Console::ITerminalOutputConnection::~ITerminalOutputConnection() {} inline Microsoft::Console::ITerminalOutputConnection::~ITerminalOutputConnection() {}
#pragma warning(pop)
} }

View file

@ -78,6 +78,9 @@
// WRL // WRL
#include <wrl.h> #include <wrl.h>
// TIL - Terminal Implementation Library
#include "til.h"
#pragma warning(pop) #pragma warning(pop)
// clang-format on // clang-format on

45
src/inc/til.h Normal file
View file

@ -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<class T>
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; \
}

View file

@ -25,17 +25,17 @@ bool DispatchCommon::s_ResizeWindow(ConGetSet& conApi,
SHORT sRows = 0; SHORT sRows = 0;
// We should do nothing if 0 is passed in for a size. // We should do nothing if 0 is passed in for a size.
bool fSuccess = SUCCEEDED(SizeTToShort(width, &sColumns)) && bool success = SUCCEEDED(SizeTToShort(width, &sColumns)) &&
SUCCEEDED(SizeTToShort(height, &sRows)) && SUCCEEDED(SizeTToShort(height, &sRows)) &&
(width > 0 && height > 0); (width > 0 && height > 0);
if (fSuccess) if (success)
{ {
CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 };
csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); 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 oldViewport = Viewport::FromInclusive(csbiex.srWindow);
const Viewport newViewport = Viewport::FromDimensions(oldViewport.Origin(), const Viewport newViewport = Viewport::FromDimensions(oldViewport.Origin(),
@ -51,20 +51,20 @@ bool DispatchCommon::s_ResizeWindow(ConGetSet& conApi,
} }
// SetConsoleWindowInfo expect inclusive rects // SetConsoleWindowInfo expect inclusive rects
SMALL_RECT sri = newViewport.ToInclusive(); const auto sri = newViewport.ToInclusive();
// SetConsoleScreenBufferInfoEx however expects exclusive rects // SetConsoleScreenBufferInfoEx however expects exclusive rects
SMALL_RECT sre = newViewport.ToExclusive(); const auto sre = newViewport.ToExclusive();
csbiex.srWindow = sre; csbiex.srWindow = sre;
fSuccess = conApi.SetConsoleScreenBufferInfoEx(csbiex); success = conApi.SetConsoleScreenBufferInfoEx(csbiex);
if (fSuccess) if (success)
{ {
fSuccess = conApi.SetConsoleWindowInfo(true, sri); success = conApi.SetConsoleWindowInfo(true, sri);
} }
} }
} }
return fSuccess; return success;
} }
// Routine Description: // Routine Description:

View file

@ -23,7 +23,10 @@ namespace Microsoft::Console::VirtualTerminal
class IInteractDispatch class IInteractDispatch
{ {
public: 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; virtual ~IInteractDispatch() = default;
#pragma warning(pop)
virtual bool WriteInput(std::deque<std::unique_ptr<IInputEvent>>& inputEvents) = 0; virtual bool WriteInput(std::deque<std::unique_ptr<IInputEvent>>& inputEvents) = 0;

View file

@ -22,7 +22,10 @@ namespace Microsoft::Console::VirtualTerminal
class Microsoft::Console::VirtualTerminal::ITermDispatch class Microsoft::Console::VirtualTerminal::ITermDispatch
{ {
public: 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 ~ITermDispatch() = 0;
virtual void Execute(const wchar_t wchControl) = 0; virtual void Execute(const wchar_t wchControl) = 0;
virtual void Print(const wchar_t wchPrintable) = 0; virtual void Print(const wchar_t wchPrintable) = 0;
virtual void PrintString(const std::wstring_view string) = 0; virtual void PrintString(const std::wstring_view string) = 0;
@ -97,3 +100,4 @@ public:
const std::basic_string_view<size_t> parameters) = 0; const std::basic_string_view<size_t> parameters) = 0;
}; };
inline Microsoft::Console::VirtualTerminal::ITermDispatch::~ITermDispatch() {} inline Microsoft::Console::VirtualTerminal::ITermDispatch::~ITermDispatch() {}
#pragma warning(pop)

View file

@ -115,7 +115,7 @@ bool InteractDispatch::WindowManipulation(const DispatchTypes::WindowManipulatio
// the ConGetSet interface, that specifically handles a conpty resize. // the ConGetSet interface, that specifically handles a conpty resize.
if (parameters.size() == 2) 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) if (success)
{ {
DispatchCommon::s_SuppressResizeRepaint(*_pConApi); DispatchCommon::s_SuppressResizeRepaint(*_pConApi);

View file

@ -25,8 +25,6 @@ namespace Microsoft::Console::VirtualTerminal
public: public:
InteractDispatch(std::unique_ptr<ConGetSet> pConApi); InteractDispatch(std::unique_ptr<ConGetSet> pConApi);
~InteractDispatch() = default;
bool WriteInput(std::deque<std::unique_ptr<IInputEvent>>& inputEvents) override; bool WriteInput(std::deque<std::unique_ptr<IInputEvent>>& inputEvents) override;
bool WriteCtrlC() override; bool WriteCtrlC() override;
bool WriteString(const std::wstring_view string) override; bool WriteString(const std::wstring_view string) override;

View file

@ -5,50 +5,39 @@
#include <windows.h> #include <windows.h>
#include "MouseInput.hpp" #include "MouseInput.hpp"
#include "strsafe.h"
#include <stdio.h>
#include <stdlib.h>
using namespace Microsoft::Console::VirtualTerminal; using namespace Microsoft::Console::VirtualTerminal;
#define WIL_SUPPORT_BITOPERATION_PASCAL_NAMES
#include <wil\Common.h>
#ifdef BUILD_ONECORE_INTERACTIVITY #ifdef BUILD_ONECORE_INTERACTIVITY
#include "..\..\interactivity\inc\VtApiRedirection.hpp" #include "..\..\interactivity\inc\VtApiRedirection.hpp"
#endif #endif
// This magic flag is "documented" at https://msdn.microsoft.com/en-us/library/windows/desktop/ms646301(v=vs.85).aspx // 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." // "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<short>(0x8000) };
// Alternate scroll sequences // Alternate scroll sequences
#define CURSOR_UP_SEQUENCE (L"\x1b[A") static constexpr std::wstring_view CursorUpSequence{ L"\x1b[A" };
#define CURSOR_DOWN_SEQUENCE (L"\x1b[B") static constexpr std::wstring_view CursorDownSequence{ L"\x1b[B" };
#define CCH_CURSOR_SEQUENCES (3)
MouseInput::MouseInput(const WriteInputEvents pfnWriteEvents) : MouseInput::MouseInput(const WriteInputEvents pfnWriteEvents) noexcept :
_pfnWriteEvents(pfnWriteEvents), _pfnWriteEvents(pfnWriteEvents),
_coordLastPos{ -1, -1 }, _lastPos{ -1, -1 },
_lastButton{ 0 } _lastButton{ 0 }
{ {
} }
MouseInput::~MouseInput()
{
}
// Routine Description: // Routine Description:
// - Determines if the input windows message code describes a button event // - Determines if the input windows message code describes a button event
// (left, middle, right button and any of up, down or double click) // (left, middle, right button and any of up, down or double click)
// Also returns true for wheel events, which are buttons in *nix terminals // Also returns true for wheel events, which are buttons in *nix terminals
// Parameters: // Parameters:
// - uiButton - the message to decode. // - button - the message to decode.
// Return value: // Return value:
// - true iff uiButton is a button message to translate // - true iff button is a button message to translate
bool MouseInput::s_IsButtonMsg(const unsigned int uiButton) static constexpr bool _isButtonMsg(const unsigned int button) noexcept
{ {
bool fIsButton = false; bool isButton = false;
switch (uiButton) switch (button)
{ {
case WM_LBUTTONDBLCLK: case WM_LBUTTONDBLCLK:
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
@ -61,34 +50,34 @@ bool MouseInput::s_IsButtonMsg(const unsigned int uiButton)
case WM_MBUTTONDBLCLK: case WM_MBUTTONDBLCLK:
case WM_MOUSEWHEEL: case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL: case WM_MOUSEHWHEEL:
fIsButton = true; isButton = true;
break; break;
} }
return fIsButton; return isButton;
} }
// Routine Description: // Routine Description:
// - Determines if the input windows message code describes a hover event // - Determines if the input windows message code describes a hover event
// Parameters: // Parameters:
// - uiButtonCode - the message to decode. // - buttonCode - the message to decode.
// Return value: // Return value:
// - true iff uiButtonCode is a hover enent to translate // - true iff buttonCode is a hover enent to translate
bool MouseInput::s_IsHoverMsg(const unsigned int uiButtonCode) static constexpr bool _isHoverMsg(const unsigned int buttonCode) noexcept
{ {
return uiButtonCode == WM_MOUSEMOVE; return buttonCode == WM_MOUSEMOVE;
} }
// Routine Description: // Routine Description:
// - Determines if the input windows message code describes a button press // - Determines if the input windows message code describes a button press
// (either down or doubleclick) // (either down or doubleclick)
// Parameters: // Parameters:
// - uiButton - the message to decode. // - button - the message to decode.
// Return value: // Return value:
// - true iff uiButton is a button down event // - true iff button is a button down event
bool MouseInput::s_IsButtonDown(const unsigned int uiButton) static constexpr bool _isButtonDown(const unsigned int button) noexcept
{ {
bool fIsButtonDown = false; bool isButtonDown = false;
switch (uiButton) switch (button)
{ {
case WM_LBUTTONDBLCLK: case WM_LBUTTONDBLCLK:
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
@ -98,10 +87,10 @@ bool MouseInput::s_IsButtonDown(const unsigned int uiButton)
case WM_MBUTTONDBLCLK: case WM_MBUTTONDBLCLK:
case WM_MOUSEWHEEL: case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL: case WM_MOUSEHWHEEL:
fIsButtonDown = true; isButtonDown = true;
break; break;
} }
return fIsButtonDown; return isButtonDown;
} }
// Routine Description: // Routine Description:
@ -127,51 +116,54 @@ bool MouseInput::s_IsButtonDown(const unsigned int uiButton)
// so wheel up? is 64, and wheel down? is 65. // so wheel up? is 64, and wheel down? is 65.
// //
// Parameters: // 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: // Return value:
// - the int representing the equivalent X button encoding. // - the int representing the equivalent X button encoding.
int MouseInput::s_WindowsButtonToXEncoding(const unsigned int uiButton, static constexpr int _windowsButtonToXEncoding(const unsigned int button,
const bool fIsHover, const bool isHover,
const short sModifierKeystate, const short modifierKeyState,
const short sWheelDelta) const short delta) noexcept
{ {
int iXValue = 0; int xvalue = 0;
switch (uiButton) switch (button)
{ {
case WM_LBUTTONDBLCLK: case WM_LBUTTONDBLCLK:
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
iXValue = 0; xvalue = 0;
break; break;
case WM_LBUTTONUP: case WM_LBUTTONUP:
case WM_MBUTTONUP: case WM_MBUTTONUP:
case WM_RBUTTONUP: case WM_RBUTTONUP:
iXValue = 3; xvalue = 3;
break; break;
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK: case WM_RBUTTONDBLCLK:
iXValue = 2; xvalue = 2;
break; break;
case WM_MBUTTONDOWN: case WM_MBUTTONDOWN:
case WM_MBUTTONDBLCLK: case WM_MBUTTONDBLCLK:
iXValue = 1; xvalue = 1;
break; break;
case WM_MOUSEWHEEL: case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL: 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. // 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 // TODO: MSFT:8804719 Add an option to disable/remap shift as a bypass for VT mousemode handling
// iXValue += (sModifierKeystate & MK_SHIFT) ? 0x04 : 0x00; // xvalue += (modifierKeyState & MK_SHIFT) ? 0x04 : 0x00;
iXValue += (sModifierKeystate & MK_CONTROL) ? 0x08 : 0x00; xvalue += (modifierKeyState & MK_CONTROL) ? 0x08 : 0x00;
// Unfortunately, we don't get meta/alt as a part of mouse events. Only Ctrl and Shift. // 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: // Routine Description:
@ -181,52 +173,75 @@ int MouseInput::s_WindowsButtonToXEncoding(const unsigned int uiButton,
// 3 is reserved for mouse hovers with _no_ buttons pressed. // 3 is reserved for mouse hovers with _no_ buttons pressed.
// See MSFT:19461988 and https://github.com/Microsoft/console/issues/296 // See MSFT:19461988 and https://github.com/Microsoft/console/issues/296
// Parameters: // Parameters:
// - uiButton - the message to decode. // - button - the message to decode.
// Return value: // Return value:
// - the int representing the equivalent X button encoding. // - the int representing the equivalent X button encoding.
int MouseInput::s_WindowsButtonToSGREncoding(const unsigned int uiButton, static constexpr int _windowsButtonToSGREncoding(const unsigned int button,
const bool fIsHover, const bool isHover,
const short sModifierKeystate, const short modifierKeyState,
const short sWheelDelta) const short delta) noexcept
{ {
int iXValue = 0; int xvalue = 0;
switch (uiButton) switch (button)
{ {
case WM_LBUTTONDBLCLK: case WM_LBUTTONDBLCLK:
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
case WM_LBUTTONUP: case WM_LBUTTONUP:
iXValue = 0; xvalue = 0;
break; break;
case WM_RBUTTONUP: case WM_RBUTTONUP:
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK: case WM_RBUTTONDBLCLK:
iXValue = 2; xvalue = 2;
break; break;
case WM_MBUTTONUP: case WM_MBUTTONUP:
case WM_MBUTTONDOWN: case WM_MBUTTONDOWN:
case WM_MBUTTONDBLCLK: case WM_MBUTTONDBLCLK:
iXValue = 1; xvalue = 1;
break; break;
case WM_MOUSEMOVE: case WM_MOUSEMOVE:
iXValue = 3; xvalue = 3;
break; break;
case WM_MOUSEWHEEL: case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL: 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. // 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 // TODO: MSFT:8804719 Add an option to disable/remap shift as a bypass for VT mousemode handling
// iXValue += (sModifierKeystate & MK_SHIFT) ? 0x04 : 0x00; // xvalue += (modifierKeyState & MK_SHIFT) ? 0x04 : 0x00;
iXValue += (sModifierKeystate & MK_CONTROL) ? 0x08 : 0x00; xvalue += (modifierKeyState & MK_CONTROL) ? 0x08 : 0x00;
// Unfortunately, we don't get meta/alt as a part of mouse events. Only Ctrl and Shift. // 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:
// - 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: // 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 // 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. // encode the event according to the rules of the selected ExtendedMode, and insert those characters into the input buffer.
// Parameters: // Parameters:
// - coordMousePosition - The windows coordinates (top,left = 0,0) of the mouse event // - position - The windows coordinates (top,left = 0,0) of the mouse event
// - uiButton - the message to decode. // - button - the message to decode.
// - sModifierKeystate - the modifier keys pressed with this button // - modifierKeyState - 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) // - delta - the amount that the scroll wheel changed (should be 0 unless button is a WM_MOUSE*WHEEL)
// Return value: // Return value:
// - true if the event was handled and we should stop event propagation to the default window handler. // - true if the event was handled and we should stop event propagation to the default window handler.
bool MouseInput::HandleMouse(const COORD coordMousePosition, bool MouseInput::HandleMouse(const COORD position,
const unsigned int uiButton, const unsigned int button,
const short sModifierKeystate, const short modifierKeyState,
const short sWheelDelta) const short delta)
{ {
bool fSuccess = false; bool success = false;
if (_ShouldSendAlternateScroll(uiButton, sWheelDelta)) if (_ShouldSendAlternateScroll(button, delta))
{ {
fSuccess = _SendAlternateScroll(sWheelDelta); success = _SendAlternateScroll(delta);
} }
else else
{ {
fSuccess = (_TrackingMode != TrackingMode::None); success = (_trackingMode != TrackingMode::None);
if (fSuccess) if (success)
{ {
// fIsHover is only true for WM_MOUSEMOVE events // isHover is only true for WM_MOUSEMOVE events
const bool fIsHover = s_IsHoverMsg(uiButton); const bool isHover = _isHoverMsg(button);
const bool fIsButton = s_IsButtonMsg(uiButton); const bool isButton = _isButtonMsg(button);
const bool fSameCoord = (coordMousePosition.X == _coordLastPos.X) && const bool sameCoord = (position.X == _lastPos.X) &&
(coordMousePosition.Y == _coordLastPos.Y) && (position.Y == _lastPos.Y) &&
(_lastButton == uiButton); (_lastButton == button);
// If we have a WM_MOUSEMOVE, we need to know if any of the mouse // If we have a WM_MOUSEMOVE, we need to know if any of the mouse
// buttons are actually pressed. If they are, // buttons are actually pressed. If they are,
// s_GetPressedButton will return the first pressed mouse button. // s_GetPressedButton will return the first pressed mouse button.
// If it returns WM_LBUTTONUP, then we can assume that the mouse // If it returns WM_LBUTTONUP, then we can assume that the mouse
// moved without a button being pressed. // 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 default mode, only button presses/releases are sent
// In ButtonEvent mode, changing coord hovers WITH A BUTTON PRESSED // In ButtonEvent mode, changing coord hovers WITH A BUTTON PRESSED
// (WM_LBUTTONUP is our sentinel that no button was pressed) are also sent. // (WM_LBUTTONUP is our sentinel that no button was pressed) are also sent.
// In AnyEvent, all coord change hovers are 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) || success = (isButton && _trackingMode != TrackingMode::None) ||
(fIsHover && _TrackingMode == TrackingMode::ButtonEvent && ((!fSameCoord) && (physicalButtonPressed))) || (isHover && _trackingMode == TrackingMode::ButtonEvent && ((!sameCoord) && (physicalButtonPressed))) ||
(fIsHover && _TrackingMode == TrackingMode::AnyEvent && !fSameCoord); (isHover && _trackingMode == TrackingMode::AnyEvent && !sameCoord);
if (fSuccess) if (success)
{ {
wchar_t* pwchSequence = nullptr; std::wstring sequence;
size_t cchSequenceLength = 0; switch (_extendedMode)
switch (_ExtendedMode)
{ {
case ExtendedMode::None: case ExtendedMode::None:
fSuccess = _GenerateDefaultSequence(coordMousePosition, sequence = _GenerateDefaultSequence(position,
uiRealButton, realButton,
fIsHover, isHover,
sModifierKeystate, modifierKeyState,
sWheelDelta, delta);
&pwchSequence,
&cchSequenceLength);
break; break;
case ExtendedMode::Utf8: case ExtendedMode::Utf8:
fSuccess = _GenerateUtf8Sequence(coordMousePosition, sequence = _GenerateUtf8Sequence(position,
uiRealButton, realButton,
fIsHover, isHover,
sModifierKeystate, modifierKeyState,
sWheelDelta, delta);
&pwchSequence,
&cchSequenceLength);
break; break;
case ExtendedMode::Sgr: case ExtendedMode::Sgr:
// For SGR encoding, if no physical buttons were pressed, // For SGR encoding, if no physical buttons were pressed,
// then we want to handle hovers with WM_MOUSEMOVE. // then we want to handle hovers with WM_MOUSEMOVE.
// However, if we're dragging (WM_MOUSEMOVE with a button pressed), // However, if we're dragging (WM_MOUSEMOVE with a button pressed),
// then use that pressed button instead. // then use that pressed button instead.
fSuccess = _GenerateSGRSequence(coordMousePosition, sequence = _GenerateSGRSequence(position,
physicalButtonPressed ? uiRealButton : uiButton, physicalButtonPressed ? realButton : button,
s_IsButtonDown(uiRealButton), // Use uiRealButton here, to properly get the up/down state _isButtonDown(realButton), // Use realButton here, to properly get the up/down state
fIsHover, isHover,
sModifierKeystate, modifierKeyState,
sWheelDelta, delta);
&pwchSequence,
&cchSequenceLength);
break; break;
case ExtendedMode::Urxvt: case ExtendedMode::Urxvt:
default: default:
fSuccess = false; success = false;
break; break;
} }
if (fSuccess)
success = !sequence.empty();
if (success)
{ {
_SendInputSequence(pwchSequence, cchSequenceLength); _SendInputSequence(sequence);
delete[] pwchSequence; success = true;
fSuccess = true;
} }
if (_TrackingMode == TrackingMode::ButtonEvent || _TrackingMode == TrackingMode::AnyEvent) if (_trackingMode == TrackingMode::ButtonEvent || _trackingMode == TrackingMode::AnyEvent)
{ {
_coordLastPos.X = coordMousePosition.X; _lastPos.X = position.X;
_coordLastPos.Y = coordMousePosition.Y; _lastPos.Y = position.Y;
_lastButton = uiButton; _lastButton = button;
} }
} }
} }
} }
return fSuccess; return success;
} }
// Routine Description: // Routine Description:
// - Generates a sequence encoding the mouse event according to the default scheme. // - Generates a sequence encoding the mouse event according to the default scheme.
// see http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking // see http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
// Parameters: // Parameters:
// - coordMousePosition - The windows coordinates (top,left = 0,0) of the mouse event // - position - The windows coordinates (top,left = 0,0) of the mouse event
// - uiButton - the message to decode. // - button - the message to decode.
// - fIsHover - true if the sequence is generated in response to a mouse hover // - isHover - true if the sequence is generated in response to a mouse hover
// - sModifierKeystate - the modifier keys pressed with this button // - modifierKeyState - 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) // - 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: // Return value:
// - true if we were able to successfully generate a sequence. // - The generated sequence. Will be empty if we couldn't generate.
// On success, caller is responsible for delete[]ing *ppwchSequence. std::wstring MouseInput::_GenerateDefaultSequence(const COORD position,
bool MouseInput::_GenerateDefaultSequence(const COORD coordMousePosition, const unsigned int button,
const unsigned int uiButton, const bool isHover,
const bool fIsHover, const short modifierKeyState,
const short sModifierKeystate, const short delta)
const short sWheelDelta,
_Outptr_result_buffer_(*pcchLength) wchar_t** const ppwchSequence,
_Out_ size_t* const pcchLength) const
{ {
bool fSuccess = false;
// In the default, non-extended encoding scheme, coordinates above 94 shouldn't be supported, // 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. // 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 // 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. // 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 COORD vtCoords = _winToVTCoord(position);
const short sEncodedX = s_EncodeDefaultCoordinate(coordVTCoords.X); const short encodedX = _encodeDefaultCoordinate(vtCoords.X);
const short sEncodedY = s_EncodeDefaultCoordinate(coordVTCoords.Y); const short encodedY = _encodeDefaultCoordinate(vtCoords.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; std::wstring format{ L"\x1b[Mbxy" };
*pcchLength = 7; format.at(3) = ' ' + gsl::narrow_cast<short>(_windowsButtonToXEncoding(button, isHover, modifierKeyState, delta));
fSuccess = true; format.at(4) = encodedX;
} format.at(5) = encodedY;
return format;
} }
return fSuccess; return {};
} }
// Routine Description: // Routine Description:
// - Generates a sequence encoding the mouse event according to the UTF8 Extended scheme. // - 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 // see http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Extended-coordinates
// Parameters: // Parameters:
// - coordMousePosition - The windows coordinates (top,left = 0,0) of the mouse event // - position - The windows coordinates (top,left = 0,0) of the mouse event
// - uiButton - the message to decode. // - button - the message to decode.
// - fIsHover - true if the sequence is generated in response to a mouse hover // - isHover - true if the sequence is generated in response to a mouse hover
// - sModifierKeystate - the modifier keys pressed with this button // - modifierKeyState - 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) // - 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: // Return value:
// - true if we were able to successfully generate a sequence. // - The generated sequence. Will be empty if we couldn't generate.
// On success, caller is responsible for delete[]ing *ppwchSequence. std::wstring MouseInput::_GenerateUtf8Sequence(const COORD position,
bool MouseInput::_GenerateUtf8Sequence(const COORD coordMousePosition, const unsigned int button,
const unsigned int uiButton, const bool isHover,
const bool fIsHover, const short modifierKeyState,
const short sModifierKeystate, const short delta)
const short sWheelDelta,
_Outptr_result_buffer_(*pcchLength) wchar_t** const ppwchSequence,
_Out_ size_t* const pcchLength) const
{ {
bool fSuccess = false;
// So we have some complications here. // So we have some complications here.
// The windows input stream is typically encoded as UTF16. // 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. // 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. // 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. // 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 // 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 COORD vtCoords = _winToVTCoord(position);
const short sEncodedX = s_EncodeDefaultCoordinate(coordVTCoords.X); const short encodedX = _encodeDefaultCoordinate(vtCoords.X);
const short sEncodedY = s_EncodeDefaultCoordinate(coordVTCoords.Y); const short encodedY = _encodeDefaultCoordinate(vtCoords.Y);
wchar_t* pwchFormat = new (std::nothrow) wchar_t[7]{ L"\x1b[Mbxy" }; std::wstring format{ L"\x1b[Mbxy" };
if (pwchFormat != nullptr) // The short cast is safe because we know s_WindowsButtonToXEncoding never returns more than xff
{ format.at(3) = ' ' + gsl::narrow_cast<short>(_windowsButtonToXEncoding(button, isHover, modifierKeyState, delta));
// The short cast is safe because we know s_WindowsButtonToXEncoding never returns more than xff format.at(4) = encodedX;
pwchFormat[3] = ' ' + (short)s_WindowsButtonToXEncoding(uiButton, fIsHover, sModifierKeystate, sWheelDelta); format.at(5) = encodedY;
pwchFormat[4] = sEncodedX; return format;
pwchFormat[5] = sEncodedY;
*ppwchSequence = pwchFormat;
*pcchLength = 7;
fSuccess = true;
}
} }
return fSuccess; return {};
} }
// Routine Description: // Routine Description:
// - Generates a sequence encoding the mouse event according to the SGR Extended scheme. // - 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 // see http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Extended-coordinates
// Parameters: // Parameters:
// - coordMousePosition - The windows coordinates (top,left = 0,0) of the mouse event // - position - 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. // - button - the message to decode. WM_MOUSERMOVE is used for mouse hovers with no buttons pressed.
// - isDown - true iff a mouse button was pressed. // - isDown - true iff a mouse button was pressed.
// - fIsHover - true if the sequence is generated in response to a mouse hover // - isHover - true if the sequence is generated in response to a mouse hover
// - sModifierKeystate - the modifier keys pressed with this button // - modifierKeyState - 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) // - 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 // - ppwchSequence - On success, where to put the pointer to the generated sequence
// - pcchLength - On success, where to put the length of the generated sequence // - pcchLength - On success, where to put the length of the generated sequence
// Return value: // Return value:
// - true if we were able to successfully generate a sequence. // - true if we were able to successfully generate a sequence.
// On success, caller is responsible for delete[]ing *ppwchSequence. // On success, caller is responsible for delete[]ing *ppwchSequence.
bool MouseInput::_GenerateSGRSequence(const COORD coordMousePosition, std::wstring MouseInput::_GenerateSGRSequence(const COORD position,
const unsigned int uiButton, const unsigned int button,
const bool isDown, const bool isDown,
const bool fIsHover, const bool isHover,
const short sModifierKeystate, const short modifierKeyState,
const short sWheelDelta, const short delta)
_Outptr_result_buffer_(*pcchLength) wchar_t** const ppwchSequence,
_Out_ size_t* const pcchLength) const
{ {
// Format for SGR events is: // Format for SGR events is:
// "\x1b[<%d;%d;%d;%c", xButton, x+1, y+1, fButtonDown? 'M' : 'm' // "\x1b[<%d;%d;%d;%c", xButton, x+1, y+1, fButtonDown? 'M' : 'm'
bool fSuccess = false; const int xbutton = _windowsButtonToSGREncoding(button, isHover, modifierKeyState, delta);
const int iXButton = s_WindowsButtonToSGREncoding(uiButton, fIsHover, sModifierKeystate, sWheelDelta);
#pragma warning(push) auto format = wil::str_printf<std::wstring>(L"\x1b[<%d;%d;%d%c", xbutton, position.X + 1, position.Y + 1, isDown ? L'M' : L'm');
#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) return format;
iNeededChars += 1; // for null
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;
} }
// Routine Description: // Routine Description:
@ -519,12 +471,12 @@ bool MouseInput::_GenerateSGRSequence(const COORD coordMousePosition,
// typically UTF-16 encoded, it emits a UTF-16 stream. // 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. // Does NOT enable or disable mouse mode by itself. This matches the behavior I found in Ubuntu terminals.
// Parameters: // Parameters:
// - fEnable - either enable or disable. // - enable - either enable or disable.
// Return value: // Return value:
// <none> // <none>
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: // Routine Description:
@ -533,25 +485,25 @@ void MouseInput::SetUtf8ExtendedMode(const bool fEnable)
// eg, x,y=203,504 -> "^[[<B;203;504M". This way, applications don't need to worry about character encoding. // eg, x,y=203,504 -> "^[[<B;203;504M". This way, applications don't need to worry about character encoding.
// Does NOT enable or disable mouse mode by itself. This matches the behavior I found in Ubuntu terminals. // Does NOT enable or disable mouse mode by itself. This matches the behavior I found in Ubuntu terminals.
// Parameters: // Parameters:
// - fEnable - either enable or disable. // - enable - either enable or disable.
// Return value: // Return value:
// <none> // <none>
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: // Routine Description:
// - Either enables or disables mouse mode handling. Leaves the extended mode alone, // - 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. // so if we disable then re-enable mouse mode without toggling an extended mode, the mode will persist.
// Parameters: // Parameters:
// - fEnable - either enable or disable. // - enable - either enable or disable.
// Return value: // Return value:
// <none> // <none>
void MouseInput::EnableDefaultTracking(const bool fEnable) void MouseInput::EnableDefaultTracking(const bool enable) noexcept
{ {
_TrackingMode = fEnable ? TrackingMode::Default : TrackingMode::None; _trackingMode = enable ? TrackingMode::Default : TrackingMode::None;
_coordLastPos = { -1, -1 }; // Clear out the last saved mouse position & button. _lastPos = { -1, -1 }; // Clear out the last saved mouse position & button.
_lastButton = 0; _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 // Leaves the extended mode alone, so if we disable then re-enable mouse mode
// without toggling an extended mode, the mode will persist. // without toggling an extended mode, the mode will persist.
// Parameters: // Parameters:
// - fEnable - either enable or disable. // - enable - either enable or disable.
// Return value: // Return value:
// <none> // <none>
void MouseInput::EnableButtonEventTracking(const bool fEnable) void MouseInput::EnableButtonEventTracking(const bool enable) noexcept
{ {
_TrackingMode = fEnable ? TrackingMode::ButtonEvent : TrackingMode::None; _trackingMode = enable ? TrackingMode::ButtonEvent : TrackingMode::None;
_coordLastPos = { -1, -1 }; // Clear out the last saved mouse position & button. _lastPos = { -1, -1 }; // Clear out the last saved mouse position & button.
_lastButton = 0; _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 // Leaves the extended mode alone, so if we disable then re-enable mouse mode
// without toggling an extended mode, the mode will persist. // without toggling an extended mode, the mode will persist.
// Parameters: // Parameters:
// - fEnable - either enable or disable. // - enable - either enable or disable.
// Return value: // Return value:
// <none> // <none>
void MouseInput::EnableAnyEventTracking(const bool fEnable) void MouseInput::EnableAnyEventTracking(const bool enable) noexcept
{ {
_TrackingMode = fEnable ? TrackingMode::AnyEvent : TrackingMode::None; _trackingMode = enable ? TrackingMode::AnyEvent : TrackingMode::None;
_coordLastPos = { -1, -1 }; // Clear out the last saved mouse position & button. _lastPos = { -1, -1 }; // Clear out the last saved mouse position & button.
_lastButton = 0; _lastButton = 0;
} }
@ -591,23 +543,19 @@ void MouseInput::EnableAnyEventTracking(const bool fEnable)
// - Sends the given sequence into the input callback specified by _pfnWriteEvents. // - Sends the given sequence into the input callback specified by _pfnWriteEvents.
// Typically, this inserts the characters into the input buffer as KeyDown KEY_EVENTs. // Typically, this inserts the characters into the input buffer as KeyDown KEY_EVENTs.
// Parameters: // Parameters:
// - pwszSequence - sequence to send to _pfnWriteEvents // - sequence - sequence to send to _pfnWriteEvents
// - cchLength - the length of pwszSequence
// Return value: // Return value:
// <none> // <none>
void MouseInput::_SendInputSequence(_In_reads_(cchLength) const wchar_t* const pwszSequence, void MouseInput::_SendInputSequence(const std::wstring_view sequence) const noexcept
const size_t cchLength) const
{ {
size_t cch = 0; if (!sequence.empty())
// + 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)
{ {
std::deque<std::unique_ptr<IInputEvent>> events; std::deque<std::unique_ptr<IInputEvent>> events;
try try
{ {
for (size_t i = 0; i < cch; ++i) for (const auto& wch : sequence)
{ {
events.push_back(std::make_unique<KeyEvent>(true, 1ui16, 0ui16, 0ui16, pwszSequence[i], 0)); events.push_back(std::make_unique<KeyEvent>(true, 1ui16, 0ui16, 0ui16, wch, 0));
} }
_pfnWriteEvents(events); _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: // Routine Description:
// - Retrieves which mouse button is currently pressed. This is needed because // - 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. // MOUSEMOVE events do not also tell us if any mouse buttons are pressed during the move.
// Parameters: // Parameters:
// <none> // <none>
// Return value: // Return value:
// - a uiButton corresponding to any pressed mouse buttons, else WM_LBUTTONUP if none are pressed. // - a button corresponding to any pressed mouse buttons, else WM_LBUTTONUP if none are pressed.
unsigned int MouseInput::s_GetPressedButton() unsigned int MouseInput::s_GetPressedButton() noexcept
{ {
unsigned int uiButton = WM_LBUTTONUP; // Will be treated as a release, or no button pressed. unsigned int button = WM_LBUTTONUP; // Will be treated as a release, or no button pressed.
if (WI_IsFlagSet(GetKeyState(VK_LBUTTON), KEY_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: // Routine Description:
// - Enables alternate scroll mode. This sends Cursor Up/down sequences when in the alternate buffer // - Enables alternate scroll mode. This sends Cursor Up/down sequences when in the alternate buffer
// Parameters: // Parameters:
// - fEnable - either enable or disable. // - enable - either enable or disable.
// Return value: // Return value:
// <none> // <none>
void MouseInput::EnableAlternateScroll(const bool fEnable) void MouseInput::EnableAlternateScroll(const bool enable) noexcept
{ {
_fAlternateScroll = fEnable; _alternateScroll = enable;
} }
// Routine Description: // Routine Description:
@ -684,9 +609,9 @@ void MouseInput::EnableAlternateScroll(const bool fEnable)
// <none> // <none>
// Return value: // Return value:
// <none> // <none>
void MouseInput::UseAlternateScreenBuffer() void MouseInput::UseAlternateScreenBuffer() noexcept
{ {
_fInAlternateBuffer = true; _inAlternateBuffer = true;
} }
// Routine Description: // Routine Description:
@ -695,37 +620,42 @@ void MouseInput::UseAlternateScreenBuffer()
// <none> // <none>
// Return value: // Return value:
// <none> // <none>
void MouseInput::UseMainScreenBuffer() void MouseInput::UseMainScreenBuffer() noexcept
{ {
_fInAlternateBuffer = false; _inAlternateBuffer = false;
} }
// Routine Description: // 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, // 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. // dependiong on if alternate scroll mode is enabled and we're in the alternate buffer.
// Parameters: // Parameters:
// - uiButton: The mouse event code of the input event // - button: The mouse event code of the input event
// - sScrollDelta: The scroll wheel delta of the input event // - delta: The scroll wheel delta of the input event
// Return value: // Return value:
// True iff the alternate buffer is active and alternate scroll mode is enabled and the event is a mouse wheel event. // 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 && return _inAlternateBuffer &&
_fAlternateScroll && _alternateScroll &&
(uiButton == WM_MOUSEWHEEL || uiButton == WM_MOUSEHWHEEL) && sScrollDelta != 0; (button == WM_MOUSEWHEEL || button == WM_MOUSEHWHEEL) && delta != 0;
} }
// Routine Description: // Routine Description:
// - Sends a sequence to the input coresponding to cursor up / down depending on the sScrollDelta. // - Sends a sequence to the input coresponding to cursor up / down depending on the sScrollDelta.
// Parameters: // Parameters:
// - sScrollDelta: The scroll wheel delta of the input event // - delta: The scroll wheel delta of the input event
// Return value: // Return value:
// True iff the input sequence was sent successfully. // 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; if (delta > 0)
_SendInputSequence(pwchSequence, CCH_CURSOR_SEQUENCES); {
_SendInputSequence(CursorUpSequence);
}
else
{
_SendInputSequence(CursorDownSequence);
}
return true; return true;
} }

View file

@ -26,24 +26,23 @@ namespace Microsoft::Console::VirtualTerminal
class MouseInput sealed class MouseInput sealed
{ {
public: public:
MouseInput(const WriteInputEvents pfnWriteEvents); MouseInput(const WriteInputEvents pfnWriteEvents) noexcept;
~MouseInput();
bool HandleMouse(const COORD coordMousePosition, bool HandleMouse(const COORD position,
const unsigned int uiButton, const unsigned int button,
const short sModifierKeystate, const short modifierKeyState,
const short sWheelDelta); const short delta);
void SetUtf8ExtendedMode(const bool fEnable); void SetUtf8ExtendedMode(const bool enable) noexcept;
void SetSGRExtendedMode(const bool fEnable); void SetSGRExtendedMode(const bool enable) noexcept;
void EnableDefaultTracking(const bool fEnable); void EnableDefaultTracking(const bool enable) noexcept;
void EnableButtonEventTracking(const bool fEnable); void EnableButtonEventTracking(const bool enable) noexcept;
void EnableAnyEventTracking(const bool fEnable); void EnableAnyEventTracking(const bool enable) noexcept;
void EnableAlternateScroll(const bool fEnable); void EnableAlternateScroll(const bool enable) noexcept;
void UseAlternateScreenBuffer(); void UseAlternateScreenBuffer() noexcept;
void UseMainScreenBuffer(); void UseMainScreenBuffer() noexcept;
enum class ExtendedMode : unsigned int enum class ExtendedMode : unsigned int
{ {
@ -66,57 +65,36 @@ namespace Microsoft::Console::VirtualTerminal
WriteInputEvents _pfnWriteEvents; WriteInputEvents _pfnWriteEvents;
ExtendedMode _ExtendedMode = ExtendedMode::None; ExtendedMode _extendedMode = ExtendedMode::None;
TrackingMode _TrackingMode = TrackingMode::None; TrackingMode _trackingMode = TrackingMode::None;
bool _fAlternateScroll = false; bool _alternateScroll = false;
bool _fInAlternateBuffer = false; bool _inAlternateBuffer = false;
COORD _coordLastPos; COORD _lastPos;
unsigned int _lastButton; unsigned int _lastButton;
void _SendInputSequence(_In_reads_(cchLength) const wchar_t* const pwszSequence, const size_t cchLength) const; void _SendInputSequence(const std::wstring_view sequence) const noexcept;
bool _GenerateDefaultSequence(const COORD coordMousePosition, static std::wstring _GenerateDefaultSequence(const COORD position,
const unsigned int uiButton, const unsigned int button,
const bool fIsHover, const bool isHover,
const short sModifierKeystate, const short modifierKeyState,
const short sWheelDelta, const short delta);
_Outptr_result_buffer_(*pcchLength) wchar_t** const ppwchSequence, static std::wstring _GenerateUtf8Sequence(const COORD position,
_Out_ size_t* const pcchLength) const; const unsigned int button,
bool _GenerateUtf8Sequence(const COORD coordMousePosition, const bool isHover,
const unsigned int uiButton, const short modifierKeyState,
const bool fIsHover, const short delta);
const short sModifierKeystate, static std::wstring _GenerateSGRSequence(const COORD position,
const short sWheelDelta, const unsigned int button,
_Outptr_result_buffer_(*pcchLength) wchar_t** const ppwchSequence, const bool isDown,
_Out_ size_t* const pcchLength) const; const bool isHover,
bool _GenerateSGRSequence(const COORD coordMousePosition, const short modifierKeyState,
const unsigned int uiButton, const short delta);
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 _ShouldSendAlternateScroll(const unsigned int button, const short delta) const noexcept;
bool _SendAlternateScroll(_In_ short sScrollDelta) const; bool _SendAlternateScroll(const short delta) const noexcept;
static int s_WindowsButtonToXEncoding(const unsigned int uiButton, static unsigned int s_GetPressedButton() noexcept;
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();
}; };
} }

View file

@ -7,6 +7,7 @@
#include "conGetSet.hpp" #include "conGetSet.hpp"
#include "../../types/inc/Viewport.hpp" #include "../../types/inc/Viewport.hpp"
#include "../../types/inc/utils.hpp" #include "../../types/inc/utils.hpp"
#include "../../inc/unicode.hpp"
using namespace Microsoft::Console::Types; using namespace Microsoft::Console::Types;
using namespace Microsoft::Console::VirtualTerminal; using namespace Microsoft::Console::VirtualTerminal;
@ -17,7 +18,7 @@ using namespace Microsoft::Console::VirtualTerminal;
// - <none> // - <none>
// Return Value: // Return Value:
// - Always false to signify we didn't handle it. // - Always false to signify we didn't handle it.
bool NoOp() bool NoOp() noexcept
{ {
return false; return false;
} }
@ -159,7 +160,7 @@ bool AdaptDispatch::_CursorMovement(const CursorDirection dir, const size_t dist
break; 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. // 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. // Use safe short subtraction to prevent under/overflow.
@ -345,24 +346,31 @@ bool AdaptDispatch::_CursorMovePosition(const std::optional<size_t> row, const s
} }
else 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 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) if (success)
{ {
@ -672,8 +680,8 @@ bool AdaptDispatch::EraseCharacters(const size_t numChars)
{ {
const COORD startPosition = csbiex.dwCursorPosition; const COORD startPosition = csbiex.dwCursorPosition;
const size_t remainingSpaces = csbiex.dwSize.X - startPosition.X; const SHORT remainingSpaces = csbiex.dwSize.X - startPosition.X;
const auto actualRemaining = (remainingSpaces < 0) ? 0 : remainingSpaces; const size_t actualRemaining = gsl::narrow_cast<size_t>((remainingSpaces < 0) ? 0 : remainingSpaces);
// erase at max the number of characters remaining in the line from the current position. // erase at max the number of characters remaining in the line from the current position.
const auto eraseLength = (numChars <= actualRemaining) ? numChars : actualRemaining; 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. // - relativeMode - set to true to use relative addressing, false for absolute addressing.
// Return Value: // Return Value:
// - True if handled successfully. False otherwise. // - True if handled successfully. False otherwise.
bool AdaptDispatch::SetOriginMode(const bool relativeMode) bool AdaptDispatch::SetOriginMode(const bool relativeMode) noexcept
{ {
_isOriginModeRelative = relativeMode; _isOriginModeRelative = relativeMode;
return true; return true;
@ -1249,7 +1257,7 @@ bool AdaptDispatch::_DoSetTopBottomScrollingMargins(const size_t topMargin,
success = SUCCEEDED(SizeTToShort(topMargin, &actualTop)) && SUCCEEDED(SizeTToShort(bottomMargin, &actualBottom)); success = SUCCEEDED(SizeTToShort(topMargin, &actualTop)) && SUCCEEDED(SizeTToShort(bottomMargin, &actualBottom));
if (success) 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 // The default top margin is line 1
if (actualTop == 0) if (actualTop == 0)
{ {
@ -1442,7 +1450,7 @@ bool AdaptDispatch::TabClear(const size_t clearType)
// - wchCharset - The character indicating the charset we should switch to. // - wchCharset - The character indicating the charset we should switch to.
// Return value: // Return value:
// True if handled successfully. False otherwise. // 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); return _termOutput.DesignateCharset(wchCharset);
} }
@ -1504,7 +1512,7 @@ bool AdaptDispatch::SoftReset()
} }
if (success) if (success)
{ {
DispatchTypes::GraphicsOptions opt = DispatchTypes::GraphicsOptions::Off; const auto opt = DispatchTypes::GraphicsOptions::Off;
success = SetGraphicsRendition({ &opt, 1 }); // Normal rendition. success = SetGraphicsRendition({ &opt, 1 }); // Normal rendition.
} }
if (success) if (success)
@ -1586,7 +1594,7 @@ bool AdaptDispatch::ScreenAlignmentPattern()
{ {
// Fill the screen with the letter E using the default attributes. // Fill the screen with the letter E using the default attributes.
auto fillPosition = COORD{ 0, csbiex.srWindow.Top }; 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); success = _pConApi->PrivateFillRegion(fillPosition, fillLength, L'E', false);
// Reset the meta/extended attributes (but leave the colors unchanged). // Reset the meta/extended attributes (but leave the colors unchanged).
success = success && _pConApi->PrivateSetLegacyAttributes(0, false, false, true); success = success && _pConApi->PrivateSetLegacyAttributes(0, false, false, true);
@ -1691,83 +1699,83 @@ bool AdaptDispatch::_EraseAll()
// Routine Description: // Routine Description:
// - Enables or disables support for the DECCOLM escape sequence. // - Enables or disables support for the DECCOLM escape sequence.
// Arguments: // 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: // Return Value:
// - True if handled successfully. False otherwise. // - 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; return true;
} }
//Routine Description: //Routine Description:
// Enable VT200 Mouse Mode - Enables/disables the mouse input handler in default tracking mode. // Enable VT200 Mouse Mode - Enables/disables the mouse input handler in default tracking mode.
//Arguments: //Arguments:
// - fEnabled - true to enable, false to disable. // - enabled - true to enable, false to disable.
// Return value: // Return value:
// True if handled successfully. False otherwise. // 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: //Routine Description:
// Enable UTF-8 Extended Encoding - this changes the encoding scheme for sequences // 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. // emitted by the mouse input handler. Does not enable/disable mouse mode on its own.
//Arguments: //Arguments:
// - fEnabled - true to enable, false to disable. // - enabled - true to enable, false to disable.
// Return value: // Return value:
// True if handled successfully. False otherwise. // 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: //Routine Description:
// Enable SGR Extended Encoding - this changes the encoding scheme for sequences // 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. // emitted by the mouse input handler. Does not enable/disable mouse mode on its own.
//Arguments: //Arguments:
// - fEnabled - true to enable, false to disable. // - enabled - true to enable, false to disable.
// Return value: // Return value:
// True if handled successfully. False otherwise. // 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: //Routine Description:
// Enable Button Event mode - send mouse move events WITH A BUTTON PRESSED to the input. // Enable Button Event mode - send mouse move events WITH A BUTTON PRESSED to the input.
//Arguments: //Arguments:
// - fEnabled - true to enable, false to disable. // - enabled - true to enable, false to disable.
// Return value: // Return value:
// True if handled successfully. False otherwise. // 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: //Routine Description:
// Enable Any Event mode - send all mouse events to the input. // Enable Any Event mode - send all mouse events to the input.
//Arguments: //Arguments:
// - fEnabled - true to enable, false to disable. // - enabled - true to enable, false to disable.
// Return value: // Return value:
// True if handled successfully. False otherwise. // 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: //Routine Description:
// Enable Alternate Scroll Mode - When in the Alt Buffer, send CUP and CUD on // Enable Alternate Scroll Mode - When in the Alt Buffer, send CUP and CUD on
// scroll up/down events instead of the usual sequences // scroll up/down events instead of the usual sequences
//Arguments: //Arguments:
// - fEnabled - true to enable, false to disable. // - enabled - true to enable, false to disable.
// Return value: // Return value:
// True if handled successfully. False otherwise. // 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: //Routine Description:
@ -1957,7 +1965,7 @@ bool AdaptDispatch::WindowManipulation(const DispatchTypes::WindowManipulationTy
case DispatchTypes::WindowManipulationType::ResizeWindowInCharacters: case DispatchTypes::WindowManipulationType::ResizeWindowInCharacters:
if (parameters.size() == 2) 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; break;
default: default:

View file

@ -66,7 +66,7 @@ namespace Microsoft::Console::VirtualTerminal
bool SetCursorKeysMode(const bool applicationMode) override; // DECCKM bool SetCursorKeysMode(const bool applicationMode) override; // DECCKM
bool SetKeypadMode(const bool applicationMode) override; // DECKPAM, DECKPNM bool SetKeypadMode(const bool applicationMode) override; // DECKPAM, DECKPNM
bool EnableCursorBlinking(const bool enable) override; // ATT610 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, bool SetTopBottomScrollingMargins(const size_t topMargin,
const size_t bottomMargin) override; // DECSTBM const size_t bottomMargin) override; // DECSTBM
bool ReverseLineFeed() override; // RI bool ReverseLineFeed() override; // RI
@ -77,11 +77,11 @@ namespace Microsoft::Console::VirtualTerminal
bool ForwardTab(const size_t numTabs) override; // CHT bool ForwardTab(const size_t numTabs) override; // CHT
bool BackwardsTab(const size_t numTabs) override; // CBT bool BackwardsTab(const size_t numTabs) override; // CBT
bool TabClear(const size_t clearType) override; // TBC 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 SoftReset() override; // DECSTR
bool HardReset() override; // RIS bool HardReset() override; // RIS
bool ScreenAlignmentPattern() override; // DECALN 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 EnableVT200MouseMode(const bool enabled) override; // ?1000
bool EnableUTF8ExtendedMouseMode(const bool enabled) override; // ?1005 bool EnableUTF8ExtendedMouseMode(const bool enabled) override; // ?1005
bool EnableSGRExtendedMouseMode(const bool enabled) override; // ?1006 bool EnableSGRExtendedMouseMode(const bool enabled) override; // ?1006
@ -133,8 +133,8 @@ namespace Microsoft::Console::VirtualTerminal
bool _EraseAll(); bool _EraseAll();
bool _InsertDeleteHelper(const size_t count, const bool isInsert) const; bool _InsertDeleteHelper(const size_t count, const bool isInsert) const;
bool _ScrollMovement(const ScrollDirection dir, const size_t distance) const; bool _ScrollMovement(const ScrollDirection dir, const size_t distance) const;
static void s_DisableAllColors(WORD& attr, 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); static void s_ApplyColors(WORD& attr, const WORD applyThis, const bool isForeground) noexcept;
bool _DoSetTopBottomScrollingMargins(const size_t topMargin, bool _DoSetTopBottomScrollingMargins(const size_t topMargin,
const size_t bottomMargin); const size_t bottomMargin);
@ -175,10 +175,5 @@ namespace Microsoft::Console::VirtualTerminal
bool _SetBoldColorHelper(const DispatchTypes::GraphicsOptions option); bool _SetBoldColorHelper(const DispatchTypes::GraphicsOptions option);
bool _SetDefaultColorHelper(const DispatchTypes::GraphicsOptions option); bool _SetDefaultColorHelper(const DispatchTypes::GraphicsOptions option);
bool _SetExtendedTextAttributeHelper(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;
}; };
} }

View file

@ -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. // - isForeground - True if we're modifying the FOREGROUND colors. False if we're doing BACKGROUND.
// Return Value: // Return Value:
// - <none> // - <none>
void AdaptDispatch::s_DisableAllColors(WORD& attr, const bool isForeground) void AdaptDispatch::s_DisableAllColors(WORD& attr, const bool isForeground) noexcept
{ {
if (isForeground) if (isForeground)
{ {
@ -42,8 +42,9 @@ void AdaptDispatch::s_DisableAllColors(WORD& attr, const bool isForeground)
// upon. // upon.
// Return Value: // Return Value:
// - <none> // - <none>
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 // Copy the new attribute to apply
WORD wNewColors = applyThis; WORD wNewColors = applyThis;
@ -267,7 +268,7 @@ void AdaptDispatch::_SetGraphicsOptionHelper(const DispatchTypes::GraphicsOption
// These include things such as Underlined, Italics, Blinking, etc. // These include things such as Underlined, Italics, Blinking, etc.
// Return Value: // Return Value:
// - true if the opt is the indicator for an extended text attribute, false otherwise. // - 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). // TODO:GH#2916 add support for DoublyUnderlined, Faint(RGBColorOrFaint).
// These two are currently partially implemented as other things: // 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. // These are followed by up to 4 more values which compose the entire option.
// Return Value: // Return Value:
// - true if the opt is the indicator for an extended color sequence, false otherwise. // - 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 || return opt == DispatchTypes::GraphicsOptions::ForegroundExtended ||
opt == DispatchTypes::GraphicsOptions::BackgroundExtended; 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. // These are followed by up to 4 more values which compose the entire option.
// Return Value: // Return Value:
// - true if the opt is the indicator for an extended color sequence, false otherwise. // - 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 || return opt == DispatchTypes::GraphicsOptions::BoldBright ||
opt == DispatchTypes::GraphicsOptions::UnBold; opt == DispatchTypes::GraphicsOptions::UnBold;
@ -313,7 +314,7 @@ bool AdaptDispatch::s_IsBoldColorOption(const DispatchTypes::GraphicsOptions opt
//the default attributes. //the default attributes.
// Return Value: // Return Value:
// - true if the opt sets either/or attribute to the defaults, false otherwise. // - 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 || return opt == DispatchTypes::GraphicsOptions::Off ||
opt == DispatchTypes::GraphicsOptions::ForegroundDefault || opt == DispatchTypes::GraphicsOptions::ForegroundDefault ||
@ -344,11 +345,11 @@ bool AdaptDispatch::_SetRgbColorsHelper(const std::basic_string_view<DispatchTyp
{ {
bool success = false; bool success = false;
optionsConsumed = 1; optionsConsumed = 1;
if (options.size() >= 2 && s_IsRgbColorOption(options.at(0))) if (options.size() >= 2 && _isRgbColorOption(til::at(options, 0)))
{ {
optionsConsumed = 2; optionsConsumed = 2;
DispatchTypes::GraphicsOptions extendedOpt = options.at(0); const auto extendedOpt = til::at(options, 0);
DispatchTypes::GraphicsOptions typeOpt = options.at(1); const auto typeOpt = til::at(options, 1);
if (extendedOpt == DispatchTypes::GraphicsOptions::ForegroundExtended) if (extendedOpt == DispatchTypes::GraphicsOptions::ForegroundExtended)
{ {
@ -363,9 +364,9 @@ bool AdaptDispatch::_SetRgbColorsHelper(const std::basic_string_view<DispatchTyp
{ {
optionsConsumed = 5; optionsConsumed = 5;
// ensure that each value fits in a byte // ensure that each value fits in a byte
unsigned int red = std::min(static_cast<unsigned int>(options.at(2)), 255u); unsigned int red = std::min(static_cast<unsigned int>(til::at(options, 2)), 255u);
unsigned int green = std::min(static_cast<unsigned int>(options.at(3)), 255u); unsigned int green = std::min(static_cast<unsigned int>(til::at(options, 3)), 255u);
unsigned int blue = std::min(static_cast<unsigned int>(options.at(4)), 255u); unsigned int blue = std::min(static_cast<unsigned int>(til::at(options, 4)), 255u);
rgbColor = RGB(red, green, blue); rgbColor = RGB(red, green, blue);
@ -374,9 +375,9 @@ bool AdaptDispatch::_SetRgbColorsHelper(const std::basic_string_view<DispatchTyp
else if (typeOpt == DispatchTypes::GraphicsOptions::BlinkOrXterm256Index && options.size() >= 3) else if (typeOpt == DispatchTypes::GraphicsOptions::BlinkOrXterm256Index && options.size() >= 3)
{ {
optionsConsumed = 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); success = _pConApi->SetConsoleXtermTextAttribute(tableIndex, isForeground);
} }
@ -487,22 +488,22 @@ bool AdaptDispatch::SetGraphicsRendition(const std::basic_string_view<DispatchTy
// Run through the graphics options and apply them // Run through the graphics options and apply them
for (size_t i = 0; i < options.size(); i++) for (size_t i = 0; i < options.size(); i++)
{ {
DispatchTypes::GraphicsOptions opt = options.at(i); const auto opt = til::at(options, i);
if (s_IsDefaultColorOption(opt)) if (_isDefaultColorOption(opt))
{ {
success = _SetDefaultColorHelper(opt); success = _SetDefaultColorHelper(opt);
} }
else if (s_IsBoldColorOption(opt)) else if (_isBoldColorOption(opt))
{ {
success = _SetBoldColorHelper(opt); success = _SetBoldColorHelper(opt);
} }
else if (s_IsExtendedTextAttribute(opt)) else if (_isExtendedTextAttribute(opt))
{ {
success = _SetExtendedTextAttributeHelper(opt); success = _SetExtendedTextAttributeHelper(opt);
} }
else if (s_IsRgbColorOption(opt)) else if (_isRgbColorOption(opt))
{ {
COLORREF rgbColor; COLORREF rgbColor{ 0 };
bool isForeground = true; bool isForeground = true;
size_t optionsConsumed = 0; size_t optionsConsumed = 0;

View file

@ -6,7 +6,7 @@
<RootNamespace>adapter</RootNamespace> <RootNamespace>adapter</RootNamespace>
<ProjectName>TerminalAdapter</ProjectName> <ProjectName>TerminalAdapter</ProjectName>
<TargetName>ConTermAdapt</TargetName> <TargetName>ConTermAdapt</TargetName>
<ConfigurationType>StaticLibrary</ConfigurationType> <ConfigurationType>StaticLibrary</ConfigurationType>
</PropertyGroup> </PropertyGroup>
<Import Project="$(SolutionDir)src\common.build.pre.props" /> <Import Project="$(SolutionDir)src\common.build.pre.props" />
<ItemGroup> <ItemGroup>
@ -48,4 +48,4 @@
</ItemGroup> </ItemGroup>
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. --> <!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
<Import Project="$(SolutionDir)src\common.build.post.props" /> <Import Project="$(SolutionDir)src\common.build.post.props" />
</Project> </Project>

View file

@ -21,9 +21,6 @@
<ClCompile Include="..\telemetry.cpp"> <ClCompile Include="..\telemetry.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\terminalInput.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\terminalOutput.cpp"> <ClCompile Include="..\terminalOutput.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -36,6 +33,12 @@
<ClCompile Include="..\precomp.cpp"> <ClCompile Include="..\precomp.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\DispatchCommon.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\InteractDispatch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\MouseInput.cpp"> <ClCompile Include="..\MouseInput.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -56,9 +59,6 @@
<ClInclude Include="..\telemetry.hpp"> <ClInclude Include="..\telemetry.hpp">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\terminalInput.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\terminalOutput.hpp"> <ClInclude Include="..\terminalOutput.hpp">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@ -68,5 +68,26 @@
<ClInclude Include="..\MouseInput.hpp"> <ClInclude Include="..\MouseInput.hpp">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\DispatchCommon.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\IInteractDispatch.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\DispatchTypes.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\InteractDispatch.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\ITermDispatch.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\termDispatch.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -24,72 +24,72 @@ public:
void Print(const wchar_t wchPrintable) override = 0; void Print(const wchar_t wchPrintable) override = 0;
void PrintString(const std::wstring_view string) override = 0; void PrintString(const std::wstring_view string) override = 0;
bool CursorUp(const size_t /*distance*/) override { return false; } // CUU bool CursorUp(const size_t /*distance*/) noexcept override { return false; } // CUU
bool CursorDown(const size_t /*distance*/) override { return false; } // CUD bool CursorDown(const size_t /*distance*/) noexcept override { return false; } // CUD
bool CursorForward(const size_t /*distance*/) override { return false; } // CUF bool CursorForward(const size_t /*distance*/) noexcept override { return false; } // CUF
bool CursorBackward(const size_t /*distance*/) override { return false; } // CUB bool CursorBackward(const size_t /*distance*/) noexcept override { return false; } // CUB
bool CursorNextLine(const size_t /*distance*/) override { return false; } // CNL bool CursorNextLine(const size_t /*distance*/) noexcept override { return false; } // CNL
bool CursorPrevLine(const size_t /*distance*/) override { return false; } // CPL bool CursorPrevLine(const size_t /*distance*/) noexcept override { return false; } // CPL
bool CursorHorizontalPositionAbsolute(const size_t /*column*/) override { return false; } // CHA bool CursorHorizontalPositionAbsolute(const size_t /*column*/) noexcept override { return false; } // CHA
bool VerticalLinePositionAbsolute(const size_t /*line*/) override { return false; } // VPA bool VerticalLinePositionAbsolute(const size_t /*line*/) noexcept override { return false; } // VPA
bool CursorPosition(const size_t /*line*/, const size_t /*column*/) override { return false; } // CUP bool CursorPosition(const size_t /*line*/, const size_t /*column*/) noexcept override { return false; } // CUP
bool CursorSaveState() override { return false; } // DECSC bool CursorSaveState() noexcept override { return false; } // DECSC
bool CursorRestoreState() override { return false; } // DECRC bool CursorRestoreState() noexcept override { return false; } // DECRC
bool CursorVisibility(const bool /*isVisible*/) override { return false; } // DECTCEM bool CursorVisibility(const bool /*isVisible*/) noexcept override { return false; } // DECTCEM
bool InsertCharacter(const size_t /*count*/) override { return false; } // ICH bool InsertCharacter(const size_t /*count*/) noexcept override { return false; } // ICH
bool DeleteCharacter(const size_t /*count*/) override { return false; } // DCH bool DeleteCharacter(const size_t /*count*/) noexcept override { return false; } // DCH
bool ScrollUp(const size_t /*distance*/) override { return false; } // SU bool ScrollUp(const size_t /*distance*/) noexcept override { return false; } // SU
bool ScrollDown(const size_t /*distance*/) override { return false; } // SD bool ScrollDown(const size_t /*distance*/) noexcept override { return false; } // SD
bool InsertLine(const size_t /*distance*/) override { return false; } // IL bool InsertLine(const size_t /*distance*/) noexcept override { return false; } // IL
bool DeleteLine(const size_t /*distance*/) override { return false; } // DL bool DeleteLine(const size_t /*distance*/) noexcept override { return false; } // DL
bool SetColumns(const size_t /*columns*/) override { return false; } // DECSCPP, DECCOLM bool SetColumns(const size_t /*columns*/) noexcept override { return false; } // DECSCPP, DECCOLM
bool SetCursorKeysMode(const bool /*applicationMode*/) override { return false; } // DECCKM bool SetCursorKeysMode(const bool /*applicationMode*/) noexcept override { return false; } // DECCKM
bool SetKeypadMode(const bool /*applicationMode*/) override { return false; } // DECKPAM, DECKPNM bool SetKeypadMode(const bool /*applicationMode*/) noexcept override { return false; } // DECKPAM, DECKPNM
bool EnableCursorBlinking(const bool /*enable*/) override { return false; } // ATT610 bool EnableCursorBlinking(const bool /*enable*/) noexcept override { return false; } // ATT610
bool SetOriginMode(const bool /*relativeMode*/) override { return false; }; // DECOM bool SetOriginMode(const bool /*relativeMode*/) noexcept override { return false; }; // DECOM
bool SetTopBottomScrollingMargins(const size_t /*topMargin*/, const size_t /*bottomMargin*/) override { return false; } // DECSTBM bool SetTopBottomScrollingMargins(const size_t /*topMargin*/, const size_t /*bottomMargin*/) noexcept override { return false; } // DECSTBM
bool ReverseLineFeed() override { return false; } // RI bool ReverseLineFeed() noexcept override { return false; } // RI
bool SetWindowTitle(std::wstring_view /*title*/) override { return false; } // OscWindowTitle bool SetWindowTitle(std::wstring_view /*title*/) noexcept override { return false; } // OscWindowTitle
bool UseAlternateScreenBuffer() override { return false; } // ASBSET bool UseAlternateScreenBuffer() noexcept override { return false; } // ASBSET
bool UseMainScreenBuffer() override { return false; } // ASBRST bool UseMainScreenBuffer() noexcept override { return false; } // ASBRST
bool HorizontalTabSet() override { return false; } // HTS bool HorizontalTabSet() noexcept override { return false; } // HTS
bool ForwardTab(const size_t /*numTabs*/) override { return false; } // CHT bool ForwardTab(const size_t /*numTabs*/) noexcept override { return false; } // CHT
bool BackwardsTab(const size_t /*numTabs*/) override { return false; } // CBT bool BackwardsTab(const size_t /*numTabs*/) noexcept override { return false; } // CBT
bool TabClear(const size_t /*clearType*/) override { return false; } // TBC bool TabClear(const size_t /*clearType*/) noexcept override { return false; } // TBC
bool EnableDECCOLMSupport(const bool /*enabled*/) override { return false; } // ?40 bool EnableDECCOLMSupport(const bool /*enabled*/) noexcept override { return false; } // ?40
bool EnableVT200MouseMode(const bool /*enabled*/) override { return false; } // ?1000 bool EnableVT200MouseMode(const bool /*enabled*/) noexcept override { return false; } // ?1000
bool EnableUTF8ExtendedMouseMode(const bool /*enabled*/) override { return false; } // ?1005 bool EnableUTF8ExtendedMouseMode(const bool /*enabled*/) noexcept override { return false; } // ?1005
bool EnableSGRExtendedMouseMode(const bool /*enabled*/) override { return false; } // ?1006 bool EnableSGRExtendedMouseMode(const bool /*enabled*/) noexcept override { return false; } // ?1006
bool EnableButtonEventMouseMode(const bool /*enabled*/) override { return false; } // ?1002 bool EnableButtonEventMouseMode(const bool /*enabled*/) noexcept override { return false; } // ?1002
bool EnableAnyEventMouseMode(const bool /*enabled*/) override { return false; } // ?1003 bool EnableAnyEventMouseMode(const bool /*enabled*/) noexcept override { return false; } // ?1003
bool EnableAlternateScroll(const bool /*enabled*/) override { return false; } // ?1007 bool EnableAlternateScroll(const bool /*enabled*/) noexcept override { return false; } // ?1007
bool SetColorTableEntry(const size_t /*tableIndex*/, const DWORD /*color*/) override { return false; } // OSCColorTable bool SetColorTableEntry(const size_t /*tableIndex*/, const DWORD /*color*/) noexcept override { return false; } // OSCColorTable
bool SetDefaultForeground(const DWORD /*color*/) override { return false; } // OSCDefaultForeground bool SetDefaultForeground(const DWORD /*color*/) noexcept override { return false; } // OSCDefaultForeground
bool SetDefaultBackground(const DWORD /*color*/) override { return false; } // OSCDefaultBackground bool SetDefaultBackground(const DWORD /*color*/) noexcept override { return false; } // OSCDefaultBackground
bool EraseInDisplay(const DispatchTypes::EraseType /* eraseType*/) override { return false; } // ED bool EraseInDisplay(const DispatchTypes::EraseType /* eraseType*/) noexcept override { return false; } // ED
bool EraseInLine(const DispatchTypes::EraseType /* eraseType*/) override { return false; } // EL bool EraseInLine(const DispatchTypes::EraseType /* eraseType*/) noexcept override { return false; } // EL
bool EraseCharacters(const size_t /*numChars*/) override { return false; } // ECH bool EraseCharacters(const size_t /*numChars*/) noexcept override { return false; } // ECH
bool SetGraphicsRendition(const std::basic_string_view<DispatchTypes::GraphicsOptions> /*options*/) override { return false; } // SGR bool SetGraphicsRendition(const std::basic_string_view<DispatchTypes::GraphicsOptions> /*options*/) noexcept override { return false; } // SGR
bool SetPrivateModes(const std::basic_string_view<DispatchTypes::PrivateModeParams> /*params*/) override { return false; } // DECSET bool SetPrivateModes(const std::basic_string_view<DispatchTypes::PrivateModeParams> /*params*/) noexcept override { return false; } // DECSET
bool ResetPrivateModes(const std::basic_string_view<DispatchTypes::PrivateModeParams> /*params*/) override { return false; } // DECRST bool ResetPrivateModes(const std::basic_string_view<DispatchTypes::PrivateModeParams> /*params*/) noexcept override { return false; } // DECRST
bool DeviceStatusReport(const DispatchTypes::AnsiStatusType /*statusType*/) override { return false; } // DSR bool DeviceStatusReport(const DispatchTypes::AnsiStatusType /*statusType*/) noexcept override { return false; } // DSR
bool DeviceAttributes() override { return false; } // DA 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 SoftReset() noexcept override { return false; } // DECSTR
bool HardReset() override { return false; } // RIS bool HardReset() noexcept override { return false; } // RIS
bool ScreenAlignmentPattern() override { return false; } // DECALN bool ScreenAlignmentPattern() noexcept override { return false; } // DECALN
bool SetCursorStyle(const DispatchTypes::CursorStyle /*cursorStyle*/) override { return false; } // DECSCUSR bool SetCursorStyle(const DispatchTypes::CursorStyle /*cursorStyle*/) noexcept override { return false; } // DECSCUSR
bool SetCursorColor(const COLORREF /*color*/) override { return false; } // OSCSetCursorColor, OSCResetCursorColor bool SetCursorColor(const COLORREF /*color*/) noexcept override { return false; } // OSCSetCursorColor, OSCResetCursorColor
// DTTERM_WindowManipulation // DTTERM_WindowManipulation
bool WindowManipulation(const DispatchTypes::WindowManipulationType /*function*/, bool WindowManipulation(const DispatchTypes::WindowManipulationType /*function*/,
const std::basic_string_view<size_t> /*params*/) override { return false; } const std::basic_string_view<size_t> /*params*/) noexcept override { return false; }
}; };

View file

@ -8,18 +8,10 @@
using namespace Microsoft::Console::VirtualTerminal; using namespace Microsoft::Console::VirtualTerminal;
TerminalOutput::TerminalOutput()
{
}
TerminalOutput::~TerminalOutput()
{
}
// We include a full table so all we have to do is the lookup. // 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 // 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 // From http://vt100.net/docs/vt220-rm/table2-4.html
const wchar_t TerminalOutput::s_rgDECSpecialGraphicsTranslations[s_uiNumDisplayCharacters]{ static constexpr std::array<wchar_t, 96> s_decSpecialGraphicsTranslations{
L'\x20', L'\x20',
L'\x21', L'\x21',
L'\x22', L'\x22',
@ -118,13 +110,13 @@ const wchar_t TerminalOutput::s_rgDECSpecialGraphicsTranslations[s_uiNumDisplayC
L'\x7f' // L'\x7f', -> DEL L'\x7f' // L'\x7f', -> DEL
}; };
bool TerminalOutput::DesignateCharset(const wchar_t wchNewCharset) bool TerminalOutput::DesignateCharset(const wchar_t newCharset) noexcept
{ {
bool result = false; bool result = false;
if (wchNewCharset == DispatchTypes::VTCharacterSets::DEC_LineDrawing || if (newCharset == DispatchTypes::VTCharacterSets::DEC_LineDrawing ||
wchNewCharset == DispatchTypes::VTCharacterSets::USASCII) newCharset == DispatchTypes::VTCharacterSets::USASCII)
{ {
_wchCurrentCharset = wchNewCharset; _currentCharset = newCharset;
result = true; result = true;
} }
return result; return result;
@ -136,37 +128,35 @@ bool TerminalOutput::DesignateCharset(const wchar_t wchNewCharset)
// - <none> // - <none>
// Return Value: // Return Value:
// - True if the current charset is not USASCII // - 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 (_currentCharset)
switch (_wchCurrentCharset)
{ {
case DispatchTypes::VTCharacterSets::DEC_LineDrawing: case DispatchTypes::VTCharacterSets::DEC_LineDrawing:
pwchTranslation = TerminalOutput::s_rgDECSpecialGraphicsTranslations; return { s_decSpecialGraphicsTranslations.data(), s_decSpecialGraphicsTranslations.size() };
break;
} }
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; 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 wch < '\x5f' || wch > '\x7f') // filter out the region we know is unchanged
{ {
; // do nothing, these are the same as default. ; // do nothing, these are the same as default.
} }
else else
{ {
const wchar_t* pwchTranslationTable = _GetTranslationTable(); const auto translationTable = _GetTranslationTable();
if (pwchTranslationTable != nullptr) if (!translationTable.empty())
{ {
wchFound = (pwchTranslationTable[wch - '\x20']); wchFound = translationTable.at(wch - '\x20');
} }
} }
return wchFound; return wchFound;

View file

@ -23,20 +23,15 @@ namespace Microsoft::Console::VirtualTerminal
class TerminalOutput sealed class TerminalOutput sealed
{ {
public: public:
TerminalOutput(); TerminalOutput() = default;
~TerminalOutput();
wchar_t TranslateKey(const wchar_t wch) const; wchar_t TranslateKey(const wchar_t wch) const noexcept;
bool DesignateCharset(const wchar_t wchNewCharset); bool DesignateCharset(const wchar_t wchNewCharset) noexcept;
bool NeedToTranslate() const; bool NeedToTranslate() const noexcept;
private: 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) const std::wstring_view _GetTranslationTable() const noexcept;
static const unsigned int s_uiNumDisplayCharacters = 96;
static const wchar_t s_rgDECSpecialGraphicsTranslations[s_uiNumDisplayCharacters];
const wchar_t* _GetTranslationTable() const;
}; };
} }

View file

@ -27,50 +27,68 @@ TerminalInput::TerminalInput(_In_ std::function<void(std::deque<std::unique_ptr<
_pfnWriteEvents = pfn; _pfnWriteEvents = pfn;
} }
struct TermKeyMap
{
const WORD vkey;
const std::wstring_view sequence;
const DWORD modifiers;
constexpr TermKeyMap(WORD vkey, std::wstring_view sequence) noexcept :
TermKeyMap(vkey, 0, sequence)
{
}
constexpr TermKeyMap(const WORD vkey, const DWORD modifiers, std::wstring_view sequence) noexcept :
vkey(vkey),
sequence(sequence),
modifiers(modifiers)
{
}
};
// See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-PC-Style-Function-Keys // See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-PC-Style-Function-Keys
// For the source for these tables. // For the source for these tables.
// Also refer to the values in terminfo for kcub1, kcud1, kcuf1, kcuu1, kend, khome. // Also refer to the values in terminfo for kcub1, kcud1, kcuf1, kcuu1, kend, khome.
// the 'xterm' setting lists the application mode versions of these sequences. // the 'xterm' setting lists the application mode versions of these sequences.
const TerminalInput::_TermKeyMap TerminalInput::s_rgCursorKeysNormalMapping[]{ static constexpr std::array<TermKeyMap, 6> s_cursorKeysNormalMapping = {
{ VK_UP, L"\x1b[A" }, TermKeyMap{ VK_UP, L"\x1b[A" },
{ VK_DOWN, L"\x1b[B" }, TermKeyMap{ VK_DOWN, L"\x1b[B" },
{ VK_RIGHT, L"\x1b[C" }, TermKeyMap{ VK_RIGHT, L"\x1b[C" },
{ VK_LEFT, L"\x1b[D" }, TermKeyMap{ VK_LEFT, L"\x1b[D" },
{ VK_HOME, L"\x1b[H" }, TermKeyMap{ VK_HOME, L"\x1b[H" },
{ VK_END, L"\x1b[F" }, TermKeyMap{ VK_END, L"\x1b[F" },
}; };
const TerminalInput::_TermKeyMap TerminalInput::s_rgCursorKeysApplicationMapping[]{ static constexpr std::array<TermKeyMap, 6> s_cursorKeysApplicationMapping{
{ VK_UP, L"\x1bOA" }, TermKeyMap{ VK_UP, L"\x1bOA" },
{ VK_DOWN, L"\x1bOB" }, TermKeyMap{ VK_DOWN, L"\x1bOB" },
{ VK_RIGHT, L"\x1bOC" }, TermKeyMap{ VK_RIGHT, L"\x1bOC" },
{ VK_LEFT, L"\x1bOD" }, TermKeyMap{ VK_LEFT, L"\x1bOD" },
{ VK_HOME, L"\x1bOH" }, TermKeyMap{ VK_HOME, L"\x1bOH" },
{ VK_END, L"\x1bOF" }, TermKeyMap{ VK_END, L"\x1bOF" },
}; };
const TerminalInput::_TermKeyMap TerminalInput::s_rgKeypadNumericMapping[]{ static constexpr std::array<TermKeyMap, 20> s_keypadNumericMapping{
// HEY YOU. UPDATE THE MAX LENGTH DEF WHEN YOU MAKE CHANGES HERE. TermKeyMap{ VK_TAB, L"\x09" },
{ VK_TAB, L"\x09" }, TermKeyMap{ VK_BACK, L"\x7f" },
{ VK_BACK, L"\x7f" }, TermKeyMap{ VK_PAUSE, L"\x1a" },
{ VK_PAUSE, L"\x1a" }, TermKeyMap{ VK_ESCAPE, L"\x1b" },
{ VK_ESCAPE, L"\x1b" }, TermKeyMap{ VK_INSERT, L"\x1b[2~" },
{ VK_INSERT, L"\x1b[2~" }, TermKeyMap{ VK_DELETE, L"\x1b[3~" },
{ VK_DELETE, L"\x1b[3~" }, TermKeyMap{ VK_PRIOR, L"\x1b[5~" },
{ VK_PRIOR, L"\x1b[5~" }, TermKeyMap{ VK_NEXT, L"\x1b[6~" },
{ VK_NEXT, L"\x1b[6~" }, TermKeyMap{ VK_F1, L"\x1bOP" }, // also \x1b[11~, PuTTY uses \x1b\x1b[A
{ 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
{ 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
{ 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
{ VK_F4, L"\x1bOS" }, // also \x1b[14~, PuTTY uses \x1b\x1b[D TermKeyMap{ VK_F5, L"\x1b[15~" },
{ VK_F5, L"\x1b[15~" }, TermKeyMap{ VK_F6, L"\x1b[17~" },
{ VK_F6, L"\x1b[17~" }, TermKeyMap{ VK_F7, L"\x1b[18~" },
{ VK_F7, L"\x1b[18~" }, TermKeyMap{ VK_F8, L"\x1b[19~" },
{ VK_F8, L"\x1b[19~" }, TermKeyMap{ VK_F9, L"\x1b[20~" },
{ VK_F9, L"\x1b[20~" }, TermKeyMap{ VK_F10, L"\x1b[21~" },
{ VK_F10, L"\x1b[21~" }, TermKeyMap{ VK_F11, L"\x1b[23~" },
{ VK_F11, L"\x1b[23~" }, TermKeyMap{ VK_F12, L"\x1b[24~" },
{ VK_F12, L"\x1b[24~" },
}; };
//Application mode - Some terminals support both a "Numeric" input mode, and an "Application" mode //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 //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. // "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. //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[]{ static constexpr std::array<TermKeyMap, 20> s_keypadApplicationMapping{
// HEY YOU. UPDATE THE MAX LENGTH DEF WHEN YOU MAKE CHANGES HERE. TermKeyMap{ VK_TAB, L"\x09" },
{ VK_TAB, L"\x09" }, TermKeyMap{ VK_BACK, L"\x7f" },
{ VK_BACK, L"\x7f" }, TermKeyMap{ VK_PAUSE, L"\x1a" },
{ VK_PAUSE, L"\x1a" }, TermKeyMap{ VK_ESCAPE, L"\x1b" },
{ VK_ESCAPE, L"\x1b" }, TermKeyMap{ VK_INSERT, L"\x1b[2~" },
{ VK_INSERT, L"\x1b[2~" }, TermKeyMap{ VK_DELETE, L"\x1b[3~" },
{ VK_DELETE, L"\x1b[3~" }, TermKeyMap{ VK_PRIOR, L"\x1b[5~" },
{ VK_PRIOR, L"\x1b[5~" }, TermKeyMap{ VK_NEXT, L"\x1b[6~" },
{ VK_NEXT, L"\x1b[6~" }, TermKeyMap{ VK_F1, L"\x1bOP" }, // also \x1b[11~, PuTTY uses \x1b\x1b[A
{ 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
{ 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
{ 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
{ VK_F4, L"\x1bOS" }, // also \x1b[14~, PuTTY uses \x1b\x1b[D TermKeyMap{ VK_F5, L"\x1b[15~" },
{ VK_F5, L"\x1b[15~" }, TermKeyMap{ VK_F6, L"\x1b[17~" },
{ VK_F6, L"\x1b[17~" }, TermKeyMap{ VK_F7, L"\x1b[18~" },
{ VK_F7, L"\x1b[18~" }, TermKeyMap{ VK_F8, L"\x1b[19~" },
{ VK_F8, L"\x1b[19~" }, TermKeyMap{ VK_F9, L"\x1b[20~" },
{ VK_F9, L"\x1b[20~" }, TermKeyMap{ VK_F10, L"\x1b[21~" },
{ VK_F10, L"\x1b[21~" }, TermKeyMap{ VK_F11, L"\x1b[23~" },
{ VK_F11, L"\x1b[23~" }, TermKeyMap{ VK_F12, L"\x1b[24~" },
{ VK_F12, L"\x1b[24~" },
// The numpad has a variety of mappings, none of which seem standard or really configurable by the OS. // 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 // See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-PC-Style-Function-Keys
// to see just how convoluted this all is. // 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) // (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. // 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. // 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) // TermKeyMap{ 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) // TermKeyMap{ VK_ADD, L"\x1bOk" }, // PuTTY: \x1bOl, \x1bOm (with shift)
// { VK_SEPARATOR, L"\x1bOl" }, // ? I'm not sure which key this is... // TermKeyMap{ VK_SEPARATOR, L"\x1bOl" }, // ? I'm not sure which key this is...
// { VK_SUBTRACT, L"\x1bOm" }, // \x1bOS // TermKeyMap{ VK_SUBTRACT, L"\x1bOm" }, // \x1bOS
// { VK_DECIMAL, L"\x1bOn" }, // \x1bOn // TermKeyMap{ VK_DECIMAL, L"\x1bOn" }, // \x1bOn
// { VK_DIVIDE, L"\x1bOo" }, // \x1bOQ // TermKeyMap{ VK_DIVIDE, L"\x1bOo" }, // \x1bOQ
// { VK_NUMPAD0, L"\x1bOp" }, // TermKeyMap{ VK_NUMPAD0, L"\x1bOp" },
// { VK_NUMPAD1, L"\x1bOq" }, // TermKeyMap{ VK_NUMPAD1, L"\x1bOq" },
// { VK_NUMPAD2, L"\x1bOr" }, // TermKeyMap{ VK_NUMPAD2, L"\x1bOr" },
// { VK_NUMPAD3, L"\x1bOs" }, // TermKeyMap{ VK_NUMPAD3, L"\x1bOs" },
// { VK_NUMPAD4, L"\x1bOt" }, // TermKeyMap{ VK_NUMPAD4, L"\x1bOt" },
// { VK_NUMPAD5, L"\x1bOu" }, // \x1b0E // TermKeyMap{ VK_NUMPAD5, L"\x1bOu" }, // \x1b0E
// { VK_NUMPAD5, L"\x1bOE" }, // PuTTY \x1b[G // TermKeyMap{ VK_NUMPAD5, L"\x1bOE" }, // PuTTY \x1b[G
// { VK_NUMPAD6, L"\x1bOv" }, // TermKeyMap{ VK_NUMPAD6, L"\x1bOv" },
// { VK_NUMPAD7, L"\x1bOw" }, // TermKeyMap{ VK_NUMPAD7, L"\x1bOw" },
// { VK_NUMPAD8, L"\x1bOx" }, // TermKeyMap{ VK_NUMPAD8, L"\x1bOx" },
// { VK_NUMPAD9, L"\x1bOy" }, // TermKeyMap{ VK_NUMPAD9, L"\x1bOy" },
// { '=', L"\x1bOX" }, // I've also seen these codes mentioned in some documentation, // TermKeyMap{ '=', 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... // TermKeyMap{ 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_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 // Sequences to send when a modifier is pressed with any of these keys
// Basically, the 'm' will be replaced with a character indicating which // Basically, the 'm' will be replaced with a character indicating which
// modifier keys are pressed. // modifier keys are pressed.
const TerminalInput::_TermKeyMap TerminalInput::s_rgModifierKeyMapping[]{ static constexpr std::array<TermKeyMap, 22> s_modifierKeyMapping{
// HEY YOU. UPDATE THE MAX LENGTH DEF WHEN YOU MAKE CHANGES HERE. TermKeyMap{ VK_UP, L"\x1b[1;mA" },
{ VK_UP, L"\x1b[1;mA" }, TermKeyMap{ VK_DOWN, L"\x1b[1;mB" },
{ VK_DOWN, L"\x1b[1;mB" }, TermKeyMap{ VK_RIGHT, L"\x1b[1;mC" },
{ VK_RIGHT, L"\x1b[1;mC" }, TermKeyMap{ VK_LEFT, L"\x1b[1;mD" },
{ VK_LEFT, L"\x1b[1;mD" }, TermKeyMap{ VK_HOME, L"\x1b[1;mH" },
{ VK_HOME, L"\x1b[1;mH" }, TermKeyMap{ VK_END, L"\x1b[1;mF" },
{ VK_END, L"\x1b[1;mF" }, TermKeyMap{ VK_F1, L"\x1b[1;mP" },
{ VK_F1, L"\x1b[1;mP" }, TermKeyMap{ VK_F2, L"\x1b[1;mQ" },
{ VK_F2, L"\x1b[1;mQ" }, TermKeyMap{ VK_F3, L"\x1b[1;mR" },
{ VK_F3, L"\x1b[1;mR" }, TermKeyMap{ VK_F4, L"\x1b[1;mS" },
{ VK_F4, L"\x1b[1;mS" }, TermKeyMap{ VK_INSERT, L"\x1b[2;m~" },
{ VK_INSERT, L"\x1b[2;m~" }, TermKeyMap{ VK_DELETE, L"\x1b[3;m~" },
{ VK_DELETE, L"\x1b[3;m~" }, TermKeyMap{ VK_PRIOR, L"\x1b[5;m~" },
{ VK_PRIOR, L"\x1b[5;m~" }, TermKeyMap{ VK_NEXT, L"\x1b[6;m~" },
{ VK_NEXT, L"\x1b[6;m~" }, TermKeyMap{ VK_F5, L"\x1b[15;m~" },
{ VK_F5, L"\x1b[15;m~" }, TermKeyMap{ VK_F6, L"\x1b[17;m~" },
{ VK_F6, L"\x1b[17;m~" }, TermKeyMap{ VK_F7, L"\x1b[18;m~" },
{ VK_F7, L"\x1b[18;m~" }, TermKeyMap{ VK_F8, L"\x1b[19;m~" },
{ VK_F8, L"\x1b[19;m~" }, TermKeyMap{ VK_F9, L"\x1b[20;m~" },
{ VK_F9, L"\x1b[20;m~" }, TermKeyMap{ VK_F10, L"\x1b[21;m~" },
{ VK_F10, L"\x1b[21;m~" }, TermKeyMap{ VK_F11, L"\x1b[23;m~" },
{ VK_F11, L"\x1b[23;m~" }, TermKeyMap{ VK_F12, L"\x1b[24;m~" },
{ VK_F12, L"\x1b[24;m~" },
// Ubuntu's inputrc also defines \x1b[5C, \x1b\x1bC (and D) as 'forward/backward-word' mappings // 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 // 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 // \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 // These sequences are not later updated to encode the modifier state in the
// sequence itself, they are just weird exceptional cases to the general // sequence itself, they are just weird exceptional cases to the general
// rules above. // rules above.
const TerminalInput::_TermKeyMap TerminalInput::s_rgSimpleModifedKeyMapping[]{ static constexpr std::array<TermKeyMap, 6> s_simpleModifedKeyMapping{
// HEY YOU. UPDATE THE MAX LENGTH DEF WHEN YOU MAKE CHANGES HERE. TermKeyMap{ VK_BACK, CTRL_PRESSED, L"\x8" },
{ VK_BACK, CTRL_PRESSED, L"\x8" }, TermKeyMap{ VK_BACK, ALT_PRESSED, L"\x1b\x7f" },
{ VK_BACK, ALT_PRESSED, L"\x1b\x7f" }, TermKeyMap{ VK_BACK, CTRL_PRESSED | ALT_PRESSED, L"\x1b\x8" },
{ VK_BACK, CTRL_PRESSED | ALT_PRESSED, L"\x1b\x8" }, TermKeyMap{ VK_TAB, CTRL_PRESSED, L"\t" },
{ VK_TAB, CTRL_PRESSED, L"\t" }, TermKeyMap{ VK_TAB, SHIFT_PRESSED, L"\x1b[Z" },
{ VK_TAB, SHIFT_PRESSED, L"\x1b[Z" }, TermKeyMap{ VK_DIVIDE, CTRL_PRESSED, L"\x1F" },
{ VK_DIVIDE, CTRL_PRESSED, L"\x1F" },
// These two are not implemented here, because they are system keys. // 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. // TermKeyMap{ 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_ESCAPE, ALT_PRESSED, L""}, This is another Windows system shortcut for switching windows.
}; };
const wchar_t* const CTRL_SLASH_SEQUENCE = L"\x1f"; const wchar_t* const CTRL_SLASH_SEQUENCE = L"\x1f";
// Do NOT include the null terminator in the count. void TerminalInput::ChangeKeypadMode(const bool applicationMode) noexcept
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)
{ {
_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<TermKeyMap> _getKeyMapping(const KeyEvent& keyEvent,
const bool cursorApplicationMode,
const bool keypadApplicationMode) noexcept
{ {
if (keyEvent.IsCursorKey()) 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
return (_fKeypadApplicationMode) ? s_cKeypadApplicationMapping : s_cKeypadNumericMapping;
}
const TerminalInput::_TermKeyMap* TerminalInput::GetKeyMapping(const KeyEvent& keyEvent) const
{
if (keyEvent.IsCursorKey())
{ {
return (_fCursorApplicationMode) ? s_rgCursorKeysApplicationMapping : s_rgCursorKeysNormalMapping; if (keypadApplicationMode)
{
return { s_keypadApplicationMapping.data(), s_keypadApplicationMapping.size() };
}
else
{
return { s_keypadNumericMapping.data(), s_keypadNumericMapping.size() };
}
} }
return (_fKeypadApplicationMode) ? s_rgKeypadApplicationMapping : s_rgKeypadNumericMapping;
} }
// Routine Description: // Routine Description:
// - Searches the s_ModifierKeyMapping for a entry corresponding to this key event. // - 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<const TermKeyMap> _searchKeyMapping(const KeyEvent& keyEvent,
std::basic_string_view<TermKeyMap> keyMapping) noexcept
{
for (auto& map : keyMapping)
{
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());
}
if (modifiersMatch)
{
return map;
}
}
}
return std::nullopt;
}
typedef std::function<void(const std::wstring_view)> InputSender;
// Routine Description:
// - 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 // Changes the second to last byte to correspond to the currently pressed modifier keys
// before sending to the input. // before sending to the input.
// Arguments: // Arguments:
// - keyEvent - Key event to translate // - keyEvent - Key event to translate
// - sender - Function to use to dispatch translated event
// Return Value: // Return Value:
// - True if there was a match to a key translation, and we successfully modified and sent it to the input // - 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 success = false;
bool fSuccess = _SearchKeyMapping(keyEvent,
s_rgModifierKeyMapping, const auto match = _searchKeyMapping(keyEvent,
s_cModifierKeyMapping, { s_modifierKeyMapping.data(), s_modifierKeyMapping.size() });
&pMatchingMapping); if (match)
if (fSuccess)
{ {
size_t cch = 0; const auto v = match.value();
if (SUCCEEDED(StringCchLengthW(pMatchingMapping->pwszSequence, _TermKeyMap::s_cchMaxSequenceLength + 1, &cch)) && if (!v.sequence.empty())
cch > 0)
{ {
wchar_t* rwchModifiedSequence = new (std::nothrow) wchar_t[cch + 1]; std::wstring modified{ v.sequence }; // Make a copy so we can modify it.
if (rwchModifiedSequence != nullptr) const bool shift = keyEvent.IsShiftPressed();
{ const bool alt = keyEvent.IsAltPressed();
memcpy(rwchModifiedSequence, pMatchingMapping->pwszSequence, cch * sizeof(wchar_t)); const bool ctrl = keyEvent.IsCtrlPressed();
const bool fShift = keyEvent.IsShiftPressed(); modified.at(modified.size() - 2) = L'1' + (shift ? 1 : 0) + (alt ? 2 : 0) + (ctrl ? 4 : 0);
const bool fAlt = keyEvent.IsAltPressed(); sender(modified);
const bool fCtrl = keyEvent.IsCtrlPressed(); success = true;
rwchModifiedSequence[cch - 2] = L'1' + (fShift ? 1 : 0) + (fAlt ? 2 : 0) + (fCtrl ? 4 : 0);
rwchModifiedSequence[cch] = 0;
_SendInputSequence(rwchModifiedSequence);
fSuccess = true;
delete[] rwchModifiedSequence;
}
} }
} }
else 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, // 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 // maybe it's in the other map of modified keys with sequences that
// don't need editing before sending. // don't need editing before sending.
fSuccess = _SearchKeyMapping(keyEvent, const auto match2 = _searchKeyMapping(keyEvent,
s_rgSimpleModifedKeyMapping, { s_simpleModifedKeyMapping.data(), s_simpleModifedKeyMapping.size() });
s_cSimpleModifedKeyMapping, if (match2)
&pMatchingMapping);
if (fSuccess)
{ {
// This mapping doesn't need to be changed at all. // This mapping doesn't need to be changed at all.
_SendInputSequence(pMatchingMapping->pwszSequence); sender(match2.value().sequence);
fSuccess = true; success = true;
} }
else else
{ {
@ -284,62 +330,13 @@ bool TerminalInput::_SearchWithModifier(const KeyEvent& keyEvent) const
if (keyEvent.GetVirtualKeyCode() == slashVkey && keyEvent.IsCtrlPressed()) if (keyEvent.GetVirtualKeyCode() == slashVkey && keyEvent.IsCtrlPressed())
{ {
// This mapping doesn't need to be changed at all. // This mapping doesn't need to be changed at all.
_SendInputSequence(CTRL_SLASH_SEQUENCE); sender(CTRL_SLASH_SEQUENCE);
fSuccess = true; success = true;
} }
} }
} }
return fSuccess; return success;
}
// 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;
} }
// Routine Description: // Routine Description:
@ -347,30 +344,31 @@ bool TerminalInput::_SearchKeyMapping(const KeyEvent& keyEvent,
// Arguments: // Arguments:
// - keyEvent - Key event to translate // - keyEvent - Key event to translate
// - keyMapping - Array of key mappings to search // - keyMapping - Array of key mappings to search
// - cKeyMapping - number of entries in keyMapping // - sender - Function to use to dispatch translated event
// Return Value: // Return Value:
// - True if there was a match to a key translation, and we successfully sent it to the input // - True if there was a match to a key translation, and we successfully sent it to the input
bool TerminalInput::_TranslateDefaultMapping(const KeyEvent& keyEvent, static bool _translateDefaultMapping(const KeyEvent& keyEvent,
_In_reads_(cKeyMapping) const TerminalInput::_TermKeyMap* keyMapping, const std::basic_string_view<TermKeyMap> keyMapping,
const size_t cKeyMapping) const InputSender sender)
{ {
const TerminalInput::_TermKeyMap* pMatchingMapping; const auto match = _searchKeyMapping(keyEvent, keyMapping);
const bool fSuccess = _SearchKeyMapping(keyEvent, keyMapping, cKeyMapping, &pMatchingMapping); if (match)
if (fSuccess)
{ {
_SendInputSequence(pMatchingMapping->pwszSequence); sender(match->sequence);
} }
return fSuccess; return match.has_value();
} }
bool TerminalInput::HandleKey(const IInputEvent* const pInEvent) const bool TerminalInput::HandleKey(const IInputEvent* const pInEvent) const
{ {
// By default, we fail to handle the key // By default, we fail to handle the key
bool fKeyHandled = false; bool keyHandled = false;
// On key presses, prepare to translate to VT compatible sequences // On key presses, prepare to translate to VT compatible sequences
if (pInEvent->EventType() == InputEventType::KeyEvent) if (pInEvent->EventType() == InputEventType::KeyEvent)
{ {
const auto senderFunc = [this](const std::wstring_view seq) { _SendInputSequence(seq); };
auto keyEvent = *static_cast<const KeyEvent* const>(pInEvent); auto keyEvent = *static_cast<const KeyEvent* const>(pInEvent);
// Only need to handle key down. See raw key handler (see RawReadWaitRoutine in stream.cpp) // 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. // 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. // So we need to get the char from the vKey.
// EXCEPT for Alt+Ctrl+Space. Then the UnicodeChar is space, not NUL. // EXCEPT for Alt+Ctrl+Space. Then the UnicodeChar is space, not NUL.
auto wchPressedChar = static_cast<wchar_t>(MapVirtualKeyW(keyEvent.GetVirtualKeyCode(), MAPVK_VK_TO_CHAR)); auto wchPressedChar = gsl::narrow_cast<wchar_t>(MapVirtualKeyW(keyEvent.GetVirtualKeyCode(), MAPVK_VK_TO_CHAR));
// This is a trick - C-Spc is supposed to send NUL. So quick change space -> @ (0x40) // This is a trick - C-Spc is supposed to send NUL. So quick change space -> @ (0x40)
wchPressedChar = (wchPressedChar == UNICODE_SPACE) ? 0x40 : wchPressedChar; wchPressedChar = (wchPressedChar == UNICODE_SPACE) ? 0x40 : wchPressedChar;
if (wchPressedChar >= 0x40 && wchPressedChar < 0x7F) if (wchPressedChar >= 0x40 && wchPressedChar < 0x7F)
@ -414,23 +412,23 @@ bool TerminalInput::HandleKey(const IInputEvent* const pInEvent) const
//shift the char to the ctrl range //shift the char to the ctrl range
wchPressedChar -= 0x40; wchPressedChar -= 0x40;
_SendEscapedInputSequence(wchPressedChar); _SendEscapedInputSequence(wchPressedChar);
fKeyHandled = true; keyHandled = true;
} }
} }
// If a modifier key was pressed, then we need to try and send the modified sequence. // 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 // Translate the key using the modifier table
fKeyHandled = _SearchWithModifier(keyEvent); keyHandled = _searchWithModifier(keyEvent, senderFunc);
} }
// ALT is a sequence of ESC + KEY. // ALT is a sequence of ESC + KEY.
if (!fKeyHandled && keyEvent.GetCharData() != 0 && keyEvent.IsAltPressed()) if (!keyHandled && keyEvent.GetCharData() != 0 && keyEvent.IsAltPressed())
{ {
_SendEscapedInputSequence(keyEvent.GetCharData()); _SendEscapedInputSequence(keyEvent.GetCharData());
fKeyHandled = true; keyHandled = true;
} }
if (!fKeyHandled && keyEvent.IsCtrlPressed()) if (!keyHandled && keyEvent.IsCtrlPressed())
{ {
if ((keyEvent.GetCharData() == UNICODE_SPACE) || // Ctrl+Space if ((keyEvent.GetCharData() == UNICODE_SPACE) || // Ctrl+Space
// when Ctrl+@ comes through, the unicodechar // 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)))) (keyEvent.GetCharData() == UNICODE_NULL && keyEvent.GetVirtualKeyCode() == LOBYTE(VkKeyScanW(0))))
{ {
_SendNullInputSequence(keyEvent.GetActiveModifierKeys()); _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) // 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. // 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') && if ((keyEvent.GetVirtualKeyCode() < '0' || keyEvent.GetVirtualKeyCode() > 'Z') &&
keyEvent.GetVirtualKeyCode() != VK_CANCEL) keyEvent.GetVirtualKeyCode() != VK_CANCEL)
{ {
fKeyHandled = _TranslateDefaultMapping(keyEvent, GetKeyMapping(keyEvent), GetKeyMappingLength(keyEvent)); keyHandled = _translateDefaultMapping(keyEvent, _getKeyMapping(keyEvent, _cursorApplicationMode, _keypadApplicationMode), senderFunc);
} }
else else
{ {
@ -459,13 +457,13 @@ bool TerminalInput::HandleKey(const IInputEvent* const pInEvent) const
rgwchSequence[0] = keyEvent.GetCharData(); rgwchSequence[0] = keyEvent.GetCharData();
rgwchSequence[1] = UNICODE_NULL; rgwchSequence[1] = UNICODE_NULL;
_SendInputSequence(rgwchSequence); _SendInputSequence(rgwchSequence);
fKeyHandled = true; keyHandled = true;
} }
} }
} }
} }
return fKeyHandled; return keyHandled;
} }
bool TerminalInput::HandleChar(const wchar_t ch) 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 // 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 // saved surrogate piece and save the new one
wchar_t buffer[32]; const auto formatted = wil::str_printf<std::wstring>(L"%I32u", _leadingSurrogate.value());
swprintf_s(buffer, L"%I32u", _leadingSurrogate.value()); _SendInputSequence(formatted);
_SendInputSequence(buffer);
} }
// save the leading portion of a surrogate pair so that they can be sent at the same time // save the leading portion of a surrogate pair so that they can be sent at the same time
_leadingSurrogate.emplace(ch); _leadingSurrogate.emplace(ch);
@ -499,9 +496,7 @@ bool TerminalInput::HandleChar(const wchar_t ch)
} }
else else
{ {
wchar_t buffer[2] = { ch, 0 }; _SendInputSequence({ &ch, 1 });
std::wstring_view buffer_view(buffer, 1);
_SendInputSequence(buffer_view);
} }
return true; 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 try
{ {
@ -539,7 +534,7 @@ void TerminalInput::_SendNullInputSequence(const DWORD dwControlKeyState) const
LOBYTE(VkKeyScanW(0)), LOBYTE(VkKeyScanW(0)),
0ui16, 0ui16,
L'\x0', L'\x0',
dwControlKeyState)); controlKeyState));
_pfnWriteEvents(inputEvents); _pfnWriteEvents(inputEvents);
} }
catch (...) 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 (!sequence.empty())
if (length <= _TermKeyMap::s_cchMaxSequenceLength && length > 0)
{ {
try try
{ {
std::deque<std::unique_ptr<IInputEvent>> inputEvents; std::deque<std::unique_ptr<IInputEvent>> inputEvents;
for (size_t i = 0; i < length; i++) for (const auto& wch : sequence)
{ {
inputEvents.push_back(std::make_unique<KeyEvent>(true, 1ui16, 0ui16, 0ui16, sequence[i], 0)); inputEvents.push_back(std::make_unique<KeyEvent>(true, 1ui16, 0ui16, 0ui16, wch, 0));
} }
_pfnWriteEvents(inputEvents); _pfnWriteEvents(inputEvents);
} }

View file

@ -35,8 +35,8 @@ namespace Microsoft::Console::VirtualTerminal
bool HandleKey(const IInputEvent* const pInEvent) const; bool HandleKey(const IInputEvent* const pInEvent) const;
bool HandleChar(const wchar_t ch); bool HandleChar(const wchar_t ch);
void ChangeKeypadMode(const bool fApplicationMode); void ChangeKeypadMode(const bool applicationMode) noexcept;
void ChangeCursorKeysMode(const bool fApplicationMode); void ChangeCursorKeysMode(const bool applicationMode) noexcept;
private: private:
std::function<void(std::deque<std::unique_ptr<IInputEvent>>&)> _pfnWriteEvents; std::function<void(std::deque<std::unique_ptr<IInputEvent>>&)> _pfnWriteEvents;
@ -44,70 +44,11 @@ namespace Microsoft::Console::VirtualTerminal
// storage location for the leading surrogate of a utf-16 surrogate pair // storage location for the leading surrogate of a utf-16 surrogate pair
std::optional<wchar_t> _leadingSurrogate; std::optional<wchar_t> _leadingSurrogate;
bool _fKeypadApplicationMode = false; bool _keypadApplicationMode = false;
bool _fCursorApplicationMode = false; bool _cursorApplicationMode = false;
void _SendNullInputSequence(const DWORD dwControlKeyState) const; 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; 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;
}; };
} }

View file

@ -204,7 +204,7 @@ bool InputStateMachineEngine::_DoControlCharacter(const wchar_t wch, const bool
{ {
// This is a C0 Control Character. // This is a C0 Control Character.
// This should be translated as Ctrl+(wch+x40) // This should be translated as Ctrl+(wch+x40)
wchar_t actualChar = wch; const wchar_t actualChar = wch;
bool writeCtrl = true; bool writeCtrl = true;
short vkey = 0; 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<size_t>{}; const auto remainingArgs = parameters.size() > 1 ? parameters.substr(1) : std::basic_string_view<size_t>{};
bool success = false; bool success = false;
switch ((CsiActionCodes)wch) switch (static_cast<CsiActionCodes>(wch))
{ {
case CsiActionCodes::Generic: case CsiActionCodes::Generic:
modifierState = _GetGenericKeysModifierState(parameters); modifierState = _GetGenericKeysModifierState(parameters);
@ -437,7 +437,7 @@ bool InputStateMachineEngine::ActionCsiDispatch(const wchar_t wch,
if (success) if (success)
{ {
switch ((CsiActionCodes)wch) switch (static_cast<CsiActionCodes>(wch))
{ {
// case CsiActionCodes::DSR_DeviceStatusReportResponse: // case CsiActionCodes::DSR_DeviceStatusReportResponse:
case CsiActionCodes::CSI_F3: case CsiActionCodes::CSI_F3:
@ -493,14 +493,14 @@ bool InputStateMachineEngine::ActionSs3Dispatch(const wchar_t wch,
{ {
// Ss3 sequence keys aren't modified. // Ss3 sequence keys aren't modified.
// When F1-F4 *are* modified, they're sent as CSI sequences, not SS3's. // When F1-F4 *are* modified, they're sent as CSI sequences, not SS3's.
DWORD dwModifierState = 0; const DWORD modifierState = 0;
short vkey = 0; short vkey = 0;
bool success = _GetSs3KeysVkey(wch, vkey); bool success = _GetSs3KeysVkey(wch, vkey);
if (success) if (success)
{ {
success = _WriteSingleKey(vkey, dwModifierState); success = _WriteSingleKey(vkey, modifierState);
} }
return success; return success;
@ -513,7 +513,7 @@ bool InputStateMachineEngine::ActionSs3Dispatch(const wchar_t wch,
// - <none> // - <none>
// Return Value: // Return Value:
// - true iff we successfully dispatched the sequence. // - true iff we successfully dispatched the sequence.
bool InputStateMachineEngine::ActionClear() bool InputStateMachineEngine::ActionClear() noexcept
{ {
return true; return true;
} }
@ -525,7 +525,7 @@ bool InputStateMachineEngine::ActionClear()
// - <none> // - <none>
// Return Value: // Return Value:
// - true iff we successfully dispatched the sequence. // - true iff we successfully dispatched the sequence.
bool InputStateMachineEngine::ActionIgnore() bool InputStateMachineEngine::ActionIgnore() noexcept
{ {
return true; return true;
} }
@ -541,7 +541,7 @@ bool InputStateMachineEngine::ActionIgnore()
// - true if we handled the dsipatch. // - true if we handled the dsipatch.
bool InputStateMachineEngine::ActionOscDispatch(const wchar_t /*wch*/, bool InputStateMachineEngine::ActionOscDispatch(const wchar_t /*wch*/,
const size_t /*parameter*/, const size_t /*parameter*/,
const std::wstring_view /*string*/) const std::wstring_view /*string*/) noexcept
{ {
return false; return false;
} }
@ -575,7 +575,7 @@ void InputStateMachineEngine::_GenerateWrappedSequence(const wchar_t wch,
const bool ctrl = WI_IsFlagSet(modifierState, LEFT_CTRL_PRESSED); const bool ctrl = WI_IsFlagSet(modifierState, LEFT_CTRL_PRESSED);
const bool alt = WI_IsFlagSet(modifierState, LEFT_ALT_PRESSED); const bool alt = WI_IsFlagSet(modifierState, LEFT_ALT_PRESSED);
INPUT_RECORD next; INPUT_RECORD next{ 0 };
DWORD currentModifiers = 0; DWORD currentModifiers = 0;
@ -587,7 +587,7 @@ void InputStateMachineEngine::_GenerateWrappedSequence(const wchar_t wch,
next.Event.KeyEvent.dwControlKeyState = currentModifiers; next.Event.KeyEvent.dwControlKeyState = currentModifiers;
next.Event.KeyEvent.wRepeatCount = 1; next.Event.KeyEvent.wRepeatCount = 1;
next.Event.KeyEvent.wVirtualKeyCode = VK_SHIFT; next.Event.KeyEvent.wVirtualKeyCode = VK_SHIFT;
next.Event.KeyEvent.wVirtualScanCode = static_cast<WORD>(MapVirtualKey(VK_SHIFT, MAPVK_VK_TO_VSC)); next.Event.KeyEvent.wVirtualScanCode = gsl::narrow_cast<WORD>(MapVirtualKey(VK_SHIFT, MAPVK_VK_TO_VSC));
next.Event.KeyEvent.uChar.UnicodeChar = 0x0; next.Event.KeyEvent.uChar.UnicodeChar = 0x0;
input.push_back(next); input.push_back(next);
} }
@ -599,7 +599,7 @@ void InputStateMachineEngine::_GenerateWrappedSequence(const wchar_t wch,
next.Event.KeyEvent.dwControlKeyState = currentModifiers; next.Event.KeyEvent.dwControlKeyState = currentModifiers;
next.Event.KeyEvent.wRepeatCount = 1; next.Event.KeyEvent.wRepeatCount = 1;
next.Event.KeyEvent.wVirtualKeyCode = VK_MENU; next.Event.KeyEvent.wVirtualKeyCode = VK_MENU;
next.Event.KeyEvent.wVirtualScanCode = static_cast<WORD>(MapVirtualKey(VK_MENU, MAPVK_VK_TO_VSC)); next.Event.KeyEvent.wVirtualScanCode = gsl::narrow_cast<WORD>(MapVirtualKey(VK_MENU, MAPVK_VK_TO_VSC));
next.Event.KeyEvent.uChar.UnicodeChar = 0x0; next.Event.KeyEvent.uChar.UnicodeChar = 0x0;
input.push_back(next); input.push_back(next);
} }
@ -611,7 +611,7 @@ void InputStateMachineEngine::_GenerateWrappedSequence(const wchar_t wch,
next.Event.KeyEvent.dwControlKeyState = currentModifiers; next.Event.KeyEvent.dwControlKeyState = currentModifiers;
next.Event.KeyEvent.wRepeatCount = 1; next.Event.KeyEvent.wRepeatCount = 1;
next.Event.KeyEvent.wVirtualKeyCode = VK_CONTROL; next.Event.KeyEvent.wVirtualKeyCode = VK_CONTROL;
next.Event.KeyEvent.wVirtualScanCode = static_cast<WORD>(MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC)); next.Event.KeyEvent.wVirtualScanCode = gsl::narrow_cast<WORD>(MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC));
next.Event.KeyEvent.uChar.UnicodeChar = 0x0; next.Event.KeyEvent.uChar.UnicodeChar = 0x0;
input.push_back(next); input.push_back(next);
} }
@ -626,7 +626,7 @@ void InputStateMachineEngine::_GenerateWrappedSequence(const wchar_t wch,
next.Event.KeyEvent.dwControlKeyState = currentModifiers; next.Event.KeyEvent.dwControlKeyState = currentModifiers;
next.Event.KeyEvent.wRepeatCount = 1; next.Event.KeyEvent.wRepeatCount = 1;
next.Event.KeyEvent.wVirtualKeyCode = VK_CONTROL; next.Event.KeyEvent.wVirtualKeyCode = VK_CONTROL;
next.Event.KeyEvent.wVirtualScanCode = static_cast<WORD>(MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC)); next.Event.KeyEvent.wVirtualScanCode = gsl::narrow_cast<WORD>(MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC));
next.Event.KeyEvent.uChar.UnicodeChar = 0x0; next.Event.KeyEvent.uChar.UnicodeChar = 0x0;
input.push_back(next); input.push_back(next);
} }
@ -638,7 +638,7 @@ void InputStateMachineEngine::_GenerateWrappedSequence(const wchar_t wch,
next.Event.KeyEvent.dwControlKeyState = currentModifiers; next.Event.KeyEvent.dwControlKeyState = currentModifiers;
next.Event.KeyEvent.wRepeatCount = 1; next.Event.KeyEvent.wRepeatCount = 1;
next.Event.KeyEvent.wVirtualKeyCode = VK_MENU; next.Event.KeyEvent.wVirtualKeyCode = VK_MENU;
next.Event.KeyEvent.wVirtualScanCode = static_cast<WORD>(MapVirtualKey(VK_MENU, MAPVK_VK_TO_VSC)); next.Event.KeyEvent.wVirtualScanCode = gsl::narrow_cast<WORD>(MapVirtualKey(VK_MENU, MAPVK_VK_TO_VSC));
next.Event.KeyEvent.uChar.UnicodeChar = 0x0; next.Event.KeyEvent.uChar.UnicodeChar = 0x0;
input.push_back(next); input.push_back(next);
} }
@ -650,7 +650,7 @@ void InputStateMachineEngine::_GenerateWrappedSequence(const wchar_t wch,
next.Event.KeyEvent.dwControlKeyState = currentModifiers; next.Event.KeyEvent.dwControlKeyState = currentModifiers;
next.Event.KeyEvent.wRepeatCount = 1; next.Event.KeyEvent.wRepeatCount = 1;
next.Event.KeyEvent.wVirtualKeyCode = VK_SHIFT; next.Event.KeyEvent.wVirtualKeyCode = VK_SHIFT;
next.Event.KeyEvent.wVirtualScanCode = static_cast<WORD>(MapVirtualKey(VK_SHIFT, MAPVK_VK_TO_VSC)); next.Event.KeyEvent.wVirtualScanCode = gsl::narrow_cast<WORD>(MapVirtualKey(VK_SHIFT, MAPVK_VK_TO_VSC));
next.Event.KeyEvent.uChar.UnicodeChar = 0x0; next.Event.KeyEvent.uChar.UnicodeChar = 0x0;
input.push_back(next); input.push_back(next);
} }
@ -681,7 +681,7 @@ void InputStateMachineEngine::_GetSingleKeypress(const wchar_t wch,
rec.Event.KeyEvent.dwControlKeyState = modifierState; rec.Event.KeyEvent.dwControlKeyState = modifierState;
rec.Event.KeyEvent.wRepeatCount = 1; rec.Event.KeyEvent.wRepeatCount = 1;
rec.Event.KeyEvent.wVirtualKeyCode = vkey; rec.Event.KeyEvent.wVirtualKeyCode = vkey;
rec.Event.KeyEvent.wVirtualScanCode = (WORD)MapVirtualKey(vkey, MAPVK_VK_TO_VSC); rec.Event.KeyEvent.wVirtualScanCode = gsl::narrow_cast<WORD>(MapVirtualKey(vkey, MAPVK_VK_TO_VSC));
rec.Event.KeyEvent.uChar.UnicodeChar = wch; rec.Event.KeyEvent.uChar.UnicodeChar = wch;
input.push_back(rec); 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. // Will automatically get the wchar_t associated with that vkey.
// Arguments: // Arguments:
// - vkey - the VKEY of the key to write to the input callback. // - 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: // Return Value:
// - true iff we successfully wrote the keypress to the input callback. // - true iff we successfully wrote the keypress to the input callback.
bool InputStateMachineEngine::_WriteSingleKey(const short vkey, const DWORD dwModifierState) 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<wchar_t>(MapVirtualKey(vkey, MAPVK_VK_TO_CHAR));
return _WriteSingleKey(wch, vkey, dwModifierState); 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 // - cParams - the number of elements in rgusParams
// Return Value: // Return Value:
// - the INPUT_RECORD comaptible modifier state. // - the INPUT_RECORD comaptible modifier state.
DWORD InputStateMachineEngine::_GetCursorKeysModifierState(const std::basic_string_view<size_t> parameters) DWORD InputStateMachineEngine::_GetCursorKeysModifierState(const std::basic_string_view<size_t> parameters) noexcept
{ {
// Both Cursor keys and generic keys keep their modifiers in the same index. // Both Cursor keys and generic keys keep their modifiers in the same index.
return _GetGenericKeysModifierState(parameters); return _GetGenericKeysModifierState(parameters);
@ -746,7 +746,7 @@ DWORD InputStateMachineEngine::_GetCursorKeysModifierState(const std::basic_stri
// - cParams - the number of elements in rgusParams // - cParams - the number of elements in rgusParams
// Return Value: // Return Value:
// - the INPUT_RECORD compatible modifier state. // - the INPUT_RECORD compatible modifier state.
DWORD InputStateMachineEngine::_GetGenericKeysModifierState(const std::basic_string_view<size_t> parameters) DWORD InputStateMachineEngine::_GetGenericKeysModifierState(const std::basic_string_view<size_t> parameters) noexcept
{ {
DWORD modifiers = 0; DWORD modifiers = 0;
if (_IsModified(parameters.size()) && parameters.size() >= 2) 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 // - paramCount - the nummber of parameters we've collected in this sequence
// Return Value: // Return Value:
// - true iff the sequence is a modified sequence. // - 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 // modified input either looks like
// \x1b[1;mA or \x1b[17;m~ // \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 // - modifierParam - the VT modifier value to convert
// Return Value: // Return Value:
// - The equivalent INPUT_RECORD modifier 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) // VT Modifiers are 1+(modifier flags)
const auto vtParam = modifierParam - 1; const auto vtParam = modifierParam - 1;
@ -805,7 +805,7 @@ bool InputStateMachineEngine::_GetGenericVkey(const std::basic_string_view<size_
return false; return false;
} }
const auto identifier = (GenericKeyIdentifiers)parameters[0]; const auto identifier = (GenericKeyIdentifiers)til::at(parameters, 0);
const auto mapping = std::find(s_genericMap.cbegin(), s_genericMap.cend(), identifier); const auto mapping = std::find(s_genericMap.cbegin(), s_genericMap.cend(), identifier);
if (mapping != s_genericMap.end()) if (mapping != s_genericMap.end())
@ -869,14 +869,14 @@ bool InputStateMachineEngine::_GetSs3KeysVkey(const wchar_t wch, short& vkey) co
// <none> // <none>
bool InputStateMachineEngine::_GenerateKeyFromChar(const wchar_t wch, bool InputStateMachineEngine::_GenerateKeyFromChar(const wchar_t wch,
short& vkey, short& vkey,
DWORD& modifierState) DWORD& modifierState) noexcept
{ {
// Low order byte is key, high order is modifiers // Low order byte is key, high order is modifiers
short keyscan = VkKeyScanW(wch); const short keyscan = VkKeyScanW(wch);
short key = LOBYTE(keyscan); short key = LOBYTE(keyscan);
short keyscanModifiers = HIBYTE(keyscan); const short keyscanModifiers = HIBYTE(keyscan);
if (key == -1 && keyscanModifiers == -1) 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. // ProcessString, and dispatch only at the end of the sequence.
// Return Value: // Return Value:
// - True iff we should manually dispatch on the last character of a string. // - True iff we should manually dispatch on the last character of a string.
bool InputStateMachineEngine::FlushAtEndOfString() const bool InputStateMachineEngine::FlushAtEndOfString() const noexcept
{ {
return true; return true;
} }
@ -917,7 +917,7 @@ bool InputStateMachineEngine::FlushAtEndOfString() const
// Return Value: // Return Value:
// - True iff we should return to the Ground state when the state machine // - True iff we should return to the Ground state when the state machine
// encounters a Control (C0) character in the Escape state. // encounters a Control (C0) character in the Escape state.
bool InputStateMachineEngine::DispatchControlCharsFromEscape() const bool InputStateMachineEngine::DispatchControlCharsFromEscape() const noexcept
{ {
return true; return true;
} }
@ -930,7 +930,7 @@ bool InputStateMachineEngine::DispatchControlCharsFromEscape() const
// Return Value: // Return Value:
// - True iff we should dispatch in the Escape state when we encounter a // - True iff we should dispatch in the Escape state when we encounter a
// Intermediate character. // Intermediate character.
bool InputStateMachineEngine::DispatchIntermediatesFromEscape() const bool InputStateMachineEngine::DispatchIntermediatesFromEscape() const noexcept
{ {
return true; return true;
} }
@ -946,14 +946,14 @@ bool InputStateMachineEngine::DispatchIntermediatesFromEscape() const
// Return Value: // Return Value:
// - True iff we successfully pulled the function type from the parameters // - True iff we successfully pulled the function type from the parameters
bool InputStateMachineEngine::_GetWindowManipulationType(const std::basic_string_view<size_t> parameters, bool InputStateMachineEngine::_GetWindowManipulationType(const std::basic_string_view<size_t> parameters,
unsigned int& function) const unsigned int& function) const noexcept
{ {
bool success = false; bool success = false;
function = DispatchTypes::WindowManipulationType::Invalid; function = DispatchTypes::WindowManipulationType::Invalid;
if (!parameters.empty()) if (!parameters.empty())
{ {
switch (parameters[0]) switch (til::at(parameters, 0))
{ {
case DispatchTypes::WindowManipulationType::RefreshWindow: case DispatchTypes::WindowManipulationType::RefreshWindow:
function = 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. // - True if we successfully pulled the cursor coordinates from the parameters we've stored. False otherwise.
bool InputStateMachineEngine::_GetXYPosition(const std::basic_string_view<size_t> parameters, bool InputStateMachineEngine::_GetXYPosition(const std::basic_string_view<size_t> parameters,
size_t& line, size_t& line,
size_t& column) const size_t& column) const noexcept
{ {
bool success = true; bool success = true;
line = DefaultLine; line = DefaultLine;
@ -994,13 +994,13 @@ bool InputStateMachineEngine::_GetXYPosition(const std::basic_string_view<size_t
else if (parameters.size() == 1) else if (parameters.size() == 1)
{ {
// If there's only one param, leave the default for the column, and retrieve the specified row. // If there's only one param, leave the default for the column, and retrieve the specified row.
line = parameters[0]; line = til::at(parameters, 0);
} }
else if (parameters.size() == 2) else if (parameters.size() == 2)
{ {
// If there are exactly two parameters, use them. // If there are exactly two parameters, use them.
line = parameters[0]; line = til::at(parameters, 0);
column = parameters[1]; column = til::at(parameters, 1);
} }
else else
{ {

View file

@ -46,31 +46,31 @@ namespace Microsoft::Console::VirtualTerminal
const std::basic_string_view<wchar_t> intermediates, const std::basic_string_view<wchar_t> intermediates,
const std::basic_string_view<size_t> parameters) override; const std::basic_string_view<size_t> parameters) override;
bool ActionClear() override; bool ActionClear() noexcept override;
bool ActionIgnore() override; bool ActionIgnore() noexcept override;
bool ActionOscDispatch(const wchar_t wch, bool ActionOscDispatch(const wchar_t wch,
const size_t parameter, const size_t parameter,
const std::wstring_view string) override; const std::wstring_view string) noexcept override;
bool ActionSs3Dispatch(const wchar_t wch, bool ActionSs3Dispatch(const wchar_t wch,
const std::basic_string_view<size_t> parameters) override; const std::basic_string_view<size_t> parameters) override;
bool FlushAtEndOfString() const override; bool FlushAtEndOfString() const noexcept override;
bool DispatchControlCharsFromEscape() const override; bool DispatchControlCharsFromEscape() const noexcept override;
bool DispatchIntermediatesFromEscape() const override; bool DispatchIntermediatesFromEscape() const noexcept override;
private: private:
const std::unique_ptr<IInteractDispatch> _pDispatch; const std::unique_ptr<IInteractDispatch> _pDispatch;
bool _lookingForDSR; bool _lookingForDSR;
DWORD _GetCursorKeysModifierState(const std::basic_string_view<size_t> parameters); DWORD _GetCursorKeysModifierState(const std::basic_string_view<size_t> parameters) noexcept;
DWORD _GetGenericKeysModifierState(const std::basic_string_view<size_t> parameters); DWORD _GetGenericKeysModifierState(const std::basic_string_view<size_t> parameters) noexcept;
bool _GenerateKeyFromChar(const wchar_t wch, short& vkey, DWORD& modifierState); bool _GenerateKeyFromChar(const wchar_t wch, short& vkey, DWORD& modifierState) noexcept;
bool _IsModified(const size_t paramCount); bool _IsModified(const size_t paramCount) noexcept;
DWORD _GetModifier(const size_t parameter); DWORD _GetModifier(const size_t parameter) noexcept;
bool _GetGenericVkey(const std::basic_string_view<size_t> parameters, bool _GetGenericVkey(const std::basic_string_view<size_t> parameters,
short& vkey) const; short& vkey) const;
@ -91,13 +91,13 @@ namespace Microsoft::Console::VirtualTerminal
std::vector<INPUT_RECORD>& input); std::vector<INPUT_RECORD>& input);
bool _GetWindowManipulationType(const std::basic_string_view<size_t> parameters, bool _GetWindowManipulationType(const std::basic_string_view<size_t> parameters,
unsigned int& function) const; unsigned int& function) const noexcept;
static constexpr size_t DefaultLine = 1; static constexpr size_t DefaultLine = 1;
static constexpr size_t DefaultColumn = 1; static constexpr size_t DefaultColumn = 1;
bool _GetXYPosition(const std::basic_string_view<size_t> parameters, bool _GetXYPosition(const std::basic_string_view<size_t> parameters,
size_t& line, size_t& line,
size_t& column) const; size_t& column) const noexcept;
bool _DoControlCharacter(const wchar_t wch, const bool writeAlt); bool _DoControlCharacter(const wchar_t wch, const bool writeAlt);
}; };

View file

@ -17,10 +17,7 @@ OutputStateMachineEngine::OutputStateMachineEngine(std::unique_ptr<ITermDispatch
_pTtyConnection(nullptr), _pTtyConnection(nullptr),
_lastPrintedChar(AsciiChars::NUL) _lastPrintedChar(AsciiChars::NUL)
{ {
} THROW_IF_NULL_ALLOC(_dispatch.get());
OutputStateMachineEngine::~OutputStateMachineEngine()
{
} }
const ITermDispatch& OutputStateMachineEngine::Dispatch() const noexcept const ITermDispatch& OutputStateMachineEngine::Dispatch() const noexcept
@ -207,7 +204,7 @@ bool OutputStateMachineEngine::ActionEscDispatch(const wchar_t wch,
} }
else if (intermediates.size() == 1) else if (intermediates.size() == 1)
{ {
const auto value = intermediates[0]; const auto value = til::at(intermediates, 0);
DesignateCharsetTypes designateType = DefaultDesignateCharsetType; DesignateCharsetTypes designateType = DefaultDesignateCharsetType;
success = _GetDesignateType(value, designateType); success = _GetDesignateType(value, designateType);
if (success) if (success)
@ -282,7 +279,7 @@ bool OutputStateMachineEngine::ActionCsiDispatch(const wchar_t wch,
unsigned int function = 0; unsigned int function = 0;
DispatchTypes::EraseType eraseType = DispatchTypes::EraseType::ToEnd; DispatchTypes::EraseType eraseType = DispatchTypes::EraseType::ToEnd;
std::vector<DispatchTypes::GraphicsOptions> graphicsOptions; std::vector<DispatchTypes::GraphicsOptions> graphicsOptions;
DispatchTypes::AnsiStatusType deviceStatusType = (DispatchTypes::AnsiStatusType)-1; // there is no default status type. DispatchTypes::AnsiStatusType deviceStatusType = static_cast<DispatchTypes::AnsiStatusType>(0); // there is no default status type.
size_t repeatCount = 0; size_t repeatCount = 0;
// This is all the args after the first arg, and the count of args not including the first one. // 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<size_t>{}; const auto remainingParams = parameters.size() > 1 ? parameters.substr(1) : std::basic_string_view<size_t>{};
@ -500,7 +497,7 @@ bool OutputStateMachineEngine::ActionCsiDispatch(const wchar_t wch,
} }
else if (intermediates.size() == 1) else if (intermediates.size() == 1)
{ {
const auto value = intermediates[0]; const auto value = til::at(intermediates, 0);
switch (value) switch (value)
{ {
case L'?': case L'?':
@ -653,7 +650,7 @@ bool OutputStateMachineEngine::_IntermediateSpaceDispatch(const wchar_t wchActio
// - <none> // - <none>
// Return Value: // Return Value:
// - <none> // - <none>
bool OutputStateMachineEngine::ActionClear() bool OutputStateMachineEngine::ActionClear() noexcept
{ {
// do nothing. // do nothing.
return true; return true;
@ -666,7 +663,7 @@ bool OutputStateMachineEngine::ActionClear()
// - <none> // - <none>
// Return Value: // Return Value:
// - <none> // - <none>
bool OutputStateMachineEngine::ActionIgnore() bool OutputStateMachineEngine::ActionIgnore() noexcept
{ {
// do nothing. // do nothing.
return true; return true;
@ -774,7 +771,7 @@ bool OutputStateMachineEngine::ActionOscDispatch(const wchar_t /*wch*/,
// Return Value: // Return Value:
// - true iff we successfully dispatched the sequence. // - true iff we successfully dispatched the sequence.
bool OutputStateMachineEngine::ActionSs3Dispatch(const wchar_t /*wch*/, bool OutputStateMachineEngine::ActionSs3Dispatch(const wchar_t /*wch*/,
const std::basic_string_view<size_t> /*parameters*/) const std::basic_string_view<size_t> /*parameters*/) noexcept
{ {
// The output engine doesn't handle any SS3 sequences. // The output engine doesn't handle any SS3 sequences.
_ClearLastChar(); _ClearLastChar();
@ -825,7 +822,7 @@ bool OutputStateMachineEngine::_GetGraphicsOptions(const std::basic_string_view<
// Return Value: // Return Value:
// - True if we successfully pulled an erase type from the parameters we've stored. False otherwise. // - True if we successfully pulled an erase type from the parameters we've stored. False otherwise.
bool OutputStateMachineEngine::_GetEraseOperation(const std::basic_string_view<size_t> parameters, bool OutputStateMachineEngine::_GetEraseOperation(const std::basic_string_view<size_t> 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. 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. eraseType = DefaultEraseType; // if we fail, just put the default type in.
@ -839,7 +836,7 @@ bool OutputStateMachineEngine::_GetEraseOperation(const std::basic_string_view<s
else if (parameters.size() == 1) else if (parameters.size() == 1)
{ {
// If there's one parameter, attempt to match it to the values we accept. // If there's one parameter, attempt to match it to the values we accept.
const auto param = static_cast<DispatchTypes::EraseType>(parameters[0]); const auto param = static_cast<DispatchTypes::EraseType>(til::at(parameters, 0));
switch (param) switch (param)
{ {
@ -864,7 +861,7 @@ bool OutputStateMachineEngine::_GetEraseOperation(const std::basic_string_view<s
// Return Value: // Return Value:
// - True if we successfully pulled the cursor distance from the parameters we've stored. False otherwise. // - True if we successfully pulled the cursor distance from the parameters we've stored. False otherwise.
bool OutputStateMachineEngine::_GetCursorDistance(const std::basic_string_view<size_t> parameters, bool OutputStateMachineEngine::_GetCursorDistance(const std::basic_string_view<size_t> parameters,
size_t& distance) const size_t& distance) const noexcept
{ {
bool success = false; bool success = false;
distance = DefaultCursorDistance; distance = DefaultCursorDistance;
@ -877,7 +874,7 @@ bool OutputStateMachineEngine::_GetCursorDistance(const std::basic_string_view<s
else if (parameters.size() == 1) else if (parameters.size() == 1)
{ {
// If there's one parameter, use it. // If there's one parameter, use it.
distance = parameters[0]; distance = til::at(parameters, 0);
success = true; success = true;
} }
@ -898,7 +895,7 @@ bool OutputStateMachineEngine::_GetCursorDistance(const std::basic_string_view<s
// Return Value: // Return Value:
// - True if we successfully pulled the scroll distance from the parameters we've stored. False otherwise. // - True if we successfully pulled the scroll distance from the parameters we've stored. False otherwise.
bool OutputStateMachineEngine::_GetScrollDistance(const std::basic_string_view<size_t> parameters, bool OutputStateMachineEngine::_GetScrollDistance(const std::basic_string_view<size_t> parameters,
size_t& distance) const size_t& distance) const noexcept
{ {
bool success = false; bool success = false;
distance = DefaultScrollDistance; distance = DefaultScrollDistance;
@ -911,7 +908,7 @@ bool OutputStateMachineEngine::_GetScrollDistance(const std::basic_string_view<s
else if (parameters.size() == 1) else if (parameters.size() == 1)
{ {
// If there's one parameter, use it. // If there's one parameter, use it.
distance = parameters[0]; distance = til::at(parameters, 0);
success = true; success = true;
} }
@ -932,7 +929,7 @@ bool OutputStateMachineEngine::_GetScrollDistance(const std::basic_string_view<s
// Return Value: // Return Value:
// - True if we successfully pulled the width from the parameters we've stored. False otherwise. // - True if we successfully pulled the width from the parameters we've stored. False otherwise.
bool OutputStateMachineEngine::_GetConsoleWidth(const std::basic_string_view<size_t> parameters, bool OutputStateMachineEngine::_GetConsoleWidth(const std::basic_string_view<size_t> parameters,
size_t& consoleWidth) const size_t& consoleWidth) const noexcept
{ {
bool success = false; bool success = false;
consoleWidth = DefaultConsoleWidth; consoleWidth = DefaultConsoleWidth;
@ -945,7 +942,7 @@ bool OutputStateMachineEngine::_GetConsoleWidth(const std::basic_string_view<siz
else if (parameters.size() == 1) else if (parameters.size() == 1)
{ {
// If there's one parameter, use it. // If there's one parameter, use it.
consoleWidth = parameters[0]; consoleWidth = til::at(parameters, 0);
success = true; success = true;
} }
@ -968,7 +965,7 @@ bool OutputStateMachineEngine::_GetConsoleWidth(const std::basic_string_view<siz
// - True if we successfully pulled the cursor coordinates from the parameters we've stored. False otherwise. // - True if we successfully pulled the cursor coordinates from the parameters we've stored. False otherwise.
bool OutputStateMachineEngine::_GetXYPosition(const std::basic_string_view<size_t> parameters, bool OutputStateMachineEngine::_GetXYPosition(const std::basic_string_view<size_t> parameters,
size_t& line, size_t& line,
size_t& column) const size_t& column) const noexcept
{ {
bool success = false; bool success = false;
line = DefaultLine; line = DefaultLine;
@ -982,14 +979,14 @@ bool OutputStateMachineEngine::_GetXYPosition(const std::basic_string_view<size_
else if (parameters.size() == 1) else if (parameters.size() == 1)
{ {
// If there's only one param, leave the default for the column, and retrieve the specified row. // If there's only one param, leave the default for the column, and retrieve the specified row.
line = parameters[0]; line = til::at(parameters, 0);
success = true; success = true;
} }
else if (parameters.size() == 2) else if (parameters.size() == 2)
{ {
// If there are exactly two parameters, use them. // If there are exactly two parameters, use them.
line = parameters[0]; line = til::at(parameters, 0);
column = parameters[1]; column = til::at(parameters, 1);
success = true; success = true;
} }
@ -1017,7 +1014,7 @@ bool OutputStateMachineEngine::_GetXYPosition(const std::basic_string_view<size_
// - True if we successfully pulled the margin settings from the parameters we've stored. False otherwise. // - True if we successfully pulled the margin settings from the parameters we've stored. False otherwise.
bool OutputStateMachineEngine::_GetTopBottomMargins(const std::basic_string_view<size_t> parameters, bool OutputStateMachineEngine::_GetTopBottomMargins(const std::basic_string_view<size_t> parameters,
size_t& topMargin, size_t& topMargin,
size_t& bottomMargin) const size_t& bottomMargin) const noexcept
{ {
// Notes: (input -> state machine out) // Notes: (input -> state machine out)
// having only a top param is legal ([3;r -> 3,0) // 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) else if (parameters.size() == 1)
{ {
topMargin = parameters[0]; topMargin = til::at(parameters, 0);
success = true; success = true;
} }
else if (parameters.size() == 2) else if (parameters.size() == 2)
{ {
// If there are exactly two parameters, use them. // If there are exactly two parameters, use them.
topMargin = parameters[0]; topMargin = til::at(parameters, 0);
bottomMargin = parameters[1]; bottomMargin = til::at(parameters, 1);
success = true; success = true;
} }
@ -1061,15 +1058,15 @@ bool OutputStateMachineEngine::_GetTopBottomMargins(const std::basic_string_view
// Return Value: // Return Value:
// - True if we successfully found a device operation in the parameters stored. False otherwise. // - True if we successfully found a device operation in the parameters stored. False otherwise.
bool OutputStateMachineEngine::_GetDeviceStatusOperation(const std::basic_string_view<size_t> parameters, bool OutputStateMachineEngine::_GetDeviceStatusOperation(const std::basic_string_view<size_t> parameters,
DispatchTypes::AnsiStatusType& statusType) const DispatchTypes::AnsiStatusType& statusType) const noexcept
{ {
bool success = false; bool success = false;
statusType = (DispatchTypes::AnsiStatusType)0; statusType = static_cast<DispatchTypes::AnsiStatusType>(0);
if (parameters.size() == 1) if (parameters.size() == 1)
{ {
// If there's one parameter, attempt to match it to the values we accept. // 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) switch (param)
{ {
@ -1112,7 +1109,7 @@ bool OutputStateMachineEngine::_GetPrivateModeParams(const std::basic_string_vie
// - parameters - The parameters to parse // - parameters - The parameters to parse
// Return Value: // Return Value:
// - True if there were no parameters. False otherwise. // - True if there were no parameters. False otherwise.
bool OutputStateMachineEngine::_VerifyHasNoParameters(const std::basic_string_view<size_t> parameters) const bool OutputStateMachineEngine::_VerifyHasNoParameters(const std::basic_string_view<size_t> parameters) const noexcept
{ {
return parameters.empty(); return parameters.empty();
} }
@ -1124,7 +1121,7 @@ bool OutputStateMachineEngine::_VerifyHasNoParameters(const std::basic_string_vi
// - parameters - The parameters to parse // - parameters - The parameters to parse
// Return Value: // Return Value:
// - True if the DA params were valid. False otherwise. // - True if the DA params were valid. False otherwise.
bool OutputStateMachineEngine::_VerifyDeviceAttributesParams(const std::basic_string_view<size_t> parameters) const bool OutputStateMachineEngine::_VerifyDeviceAttributesParams(const std::basic_string_view<size_t> parameters) const noexcept
{ {
bool success = false; bool success = false;
@ -1134,7 +1131,7 @@ bool OutputStateMachineEngine::_VerifyDeviceAttributesParams(const std::basic_st
} }
else if (parameters.size() == 1) else if (parameters.size() == 1)
{ {
if (parameters[0] == 0) if (til::at(parameters, 0) == 0)
{ {
success = true; success = true;
} }
@ -1166,7 +1163,7 @@ bool OutputStateMachineEngine::_GetOscTitle(const std::wstring_view string,
// Return Value: // Return Value:
// - True if we successfully pulled the tab distance from the parameters we've stored. False otherwise. // - True if we successfully pulled the tab distance from the parameters we've stored. False otherwise.
bool OutputStateMachineEngine::_GetTabDistance(const std::basic_string_view<size_t> parameters, bool OutputStateMachineEngine::_GetTabDistance(const std::basic_string_view<size_t> parameters,
size_t& distance) const size_t& distance) const noexcept
{ {
bool success = false; bool success = false;
distance = DefaultTabDistance; distance = DefaultTabDistance;
@ -1179,7 +1176,7 @@ bool OutputStateMachineEngine::_GetTabDistance(const std::basic_string_view<size
else if (parameters.size() == 1) else if (parameters.size() == 1)
{ {
// If there's one parameter, use it. // If there's one parameter, use it.
distance = parameters[0]; distance = til::at(parameters, 0);
success = true; success = true;
} }
@ -1200,7 +1197,7 @@ bool OutputStateMachineEngine::_GetTabDistance(const std::basic_string_view<size
// Return Value: // Return Value:
// - True if we successfully pulled the tab clear type from the parameters we've stored. False otherwise. // - True if we successfully pulled the tab clear type from the parameters we've stored. False otherwise.
bool OutputStateMachineEngine::_GetTabClearType(const std::basic_string_view<size_t> parameters, bool OutputStateMachineEngine::_GetTabClearType(const std::basic_string_view<size_t> parameters,
size_t& clearType) const size_t& clearType) const noexcept
{ {
bool success = false; bool success = false;
clearType = DefaultTabClearType; clearType = DefaultTabClearType;
@ -1213,7 +1210,7 @@ bool OutputStateMachineEngine::_GetTabClearType(const std::basic_string_view<siz
else if (parameters.size() == 1) else if (parameters.size() == 1)
{ {
// If there's one parameter, use it. // If there's one parameter, use it.
clearType = parameters[0]; clearType = til::at(parameters, 0);
success = true; success = true;
} }
return success; return success;
@ -1227,7 +1224,7 @@ bool OutputStateMachineEngine::_GetTabClearType(const std::basic_string_view<siz
// Return Value: // Return Value:
// - True if we successfully pulled the designate type from the intermediate we've stored. False otherwise. // - True if we successfully pulled the designate type from the intermediate we've stored. False otherwise.
bool OutputStateMachineEngine::_GetDesignateType(const wchar_t intermediate, bool OutputStateMachineEngine::_GetDesignateType(const wchar_t intermediate,
DesignateCharsetTypes& designateType) const DesignateCharsetTypes& designateType) const noexcept
{ {
bool success = false; bool success = false;
designateType = DefaultDesignateCharsetType; designateType = DefaultDesignateCharsetType;
@ -1265,7 +1262,7 @@ bool OutputStateMachineEngine::_GetDesignateType(const wchar_t intermediate,
// ProcessString, and dispatch only at the end of the sequence. // ProcessString, and dispatch only at the end of the sequence.
// Return Value: // Return Value:
// - True iff we should manually dispatch on the last character of a string. // - True iff we should manually dispatch on the last character of a string.
bool OutputStateMachineEngine::FlushAtEndOfString() const bool OutputStateMachineEngine::FlushAtEndOfString() const noexcept
{ {
return false; return false;
} }
@ -1280,7 +1277,7 @@ bool OutputStateMachineEngine::FlushAtEndOfString() const
// Return Value: // Return Value:
// - True iff we should return to the Ground state when the state machine // - True iff we should return to the Ground state when the state machine
// encounters a Control (C0) character in the Escape state. // encounters a Control (C0) character in the Escape state.
bool OutputStateMachineEngine::DispatchControlCharsFromEscape() const bool OutputStateMachineEngine::DispatchControlCharsFromEscape() const noexcept
{ {
return false; return false;
} }
@ -1292,7 +1289,7 @@ bool OutputStateMachineEngine::DispatchControlCharsFromEscape() const
// Return Value: // Return Value:
// - True iff we should dispatch in the Escape state when we encounter a // - True iff we should dispatch in the Escape state when we encounter a
// Intermediate character. // Intermediate character.
bool OutputStateMachineEngine::DispatchIntermediatesFromEscape() const bool OutputStateMachineEngine::DispatchIntermediatesFromEscape() const noexcept
{ {
return false; return false;
} }
@ -1305,7 +1302,7 @@ bool OutputStateMachineEngine::DispatchIntermediatesFromEscape() const
// Return Value: // Return Value:
// - true iff the character is a hex character. // - true iff the character is a hex character.
bool OutputStateMachineEngine::s_HexToUint(const wchar_t wch, bool OutputStateMachineEngine::s_HexToUint(const wchar_t wch,
unsigned int& value) unsigned int& value) noexcept
{ {
value = 0; value = 0;
bool success = false; bool success = false;
@ -1333,7 +1330,7 @@ bool OutputStateMachineEngine::s_HexToUint(const wchar_t wch,
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - True if it is. False if it isn't.
bool OutputStateMachineEngine::s_IsNumber(const wchar_t wch) static constexpr bool _isNumber(const wchar_t wch) noexcept
{ {
return wch >= L'0' && wch <= L'9'; // 0x30 - 0x39 return wch >= L'0' && wch <= L'9'; // 0x30 - 0x39
} }
@ -1344,7 +1341,7 @@ bool OutputStateMachineEngine::s_IsNumber(const wchar_t wch)
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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 return (wch >= L'0' && wch <= L'9') || // 0x30 - 0x39
(wch >= L'A' && wch <= L'F') || (wch >= L'A' && wch <= L'F') ||
@ -1363,11 +1360,11 @@ bool OutputStateMachineEngine::s_IsHexNumber(const wchar_t wch)
// Return Value: // Return Value:
// - True if a color was successfully parsed // - True if a color was successfully parsed
bool OutputStateMachineEngine::s_ParseColorSpec(const std::wstring_view string, bool OutputStateMachineEngine::s_ParseColorSpec(const std::wstring_view string,
DWORD& rgb) DWORD& rgb) noexcept
{ {
bool foundRGB = false; bool foundRGB = false;
bool foundValidColorSpec = false; bool foundValidColorSpec = false;
unsigned int rguiColorValues[3] = { 0 }; std::array<unsigned int, 3> colorValues = { 0 };
bool success = false; bool success = false;
// We can have anywhere between [11,15] characters // We can have anywhere between [11,15] characters
// 9 "rgb:h/h/h" // 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++) for (size_t component = 0; component < 3; component++)
{ {
bool foundColor = false; bool foundColor = false;
unsigned int* const pValue = &(rguiColorValues[component]); auto& value = colorValues.at(component);
for (size_t i = 0; i < 3; i++) for (size_t i = 0; i < 3; i++)
{ {
const wchar_t wch = *curr++; const wchar_t wch = *curr++;
if (s_IsHexNumber(wch)) if (_isHexNumber(wch))
{ {
*pValue *= 16; value *= 16;
unsigned int intVal = 0; unsigned int intVal = 0;
if (s_HexToUint(wch, intVal)) if (s_HexToUint(wch, intVal))
{ {
*pValue += intVal; value += intVal;
} }
else 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. // Only if we find a valid colorspec can we pass it out successfully.
if (foundValidColorSpec) if (foundValidColorSpec)
{ {
DWORD color = RGB(LOBYTE(rguiColorValues[0]), DWORD color = RGB(LOBYTE(colorValues.at(0)),
LOBYTE(rguiColorValues[1]), LOBYTE(colorValues.at(1)),
LOBYTE(rguiColorValues[2])); LOBYTE(colorValues.at(2)));
rgb = color; rgb = color;
success = true; 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. // - True if a table index and color was parsed successfully. False otherwise.
bool OutputStateMachineEngine::_GetOscSetColorTable(const std::wstring_view string, bool OutputStateMachineEngine::_GetOscSetColorTable(const std::wstring_view string,
size_t& tableIndex, size_t& tableIndex,
DWORD& rgb) const DWORD& rgb) const noexcept
{ {
tableIndex = 0; tableIndex = 0;
rgb = 0; rgb = 0;
@ -1497,7 +1494,7 @@ bool OutputStateMachineEngine::_GetOscSetColorTable(const std::wstring_view stri
for (size_t i = 0; i < 4; i++) for (size_t i = 0; i < 4; i++)
{ {
const wchar_t wch = string.at(current); const wchar_t wch = string.at(current);
if (s_IsNumber(wch)) if (_isNumber(wch))
{ {
_TableIndex *= 10; _TableIndex *= 10;
_TableIndex += wch - L'0'; _TableIndex += wch - L'0';
@ -1546,7 +1543,7 @@ bool OutputStateMachineEngine::_GetOscSetColorTable(const std::wstring_view stri
// Return Value: // Return Value:
// - True if a table index and color was parsed successfully. False otherwise. // - True if a table index and color was parsed successfully. False otherwise.
bool OutputStateMachineEngine::_GetOscSetColor(const std::wstring_view string, bool OutputStateMachineEngine::_GetOscSetColor(const std::wstring_view string,
DWORD& rgb) const DWORD& rgb) const noexcept
{ {
rgb = 0; rgb = 0;
@ -1574,14 +1571,14 @@ bool OutputStateMachineEngine::_GetOscSetColor(const std::wstring_view string,
// Return Value: // Return Value:
// - True iff we successfully pulled the function type from the parameters // - True iff we successfully pulled the function type from the parameters
bool OutputStateMachineEngine::_GetWindowManipulationType(const std::basic_string_view<size_t> parameters, bool OutputStateMachineEngine::_GetWindowManipulationType(const std::basic_string_view<size_t> parameters,
unsigned int& function) const unsigned int& function) const noexcept
{ {
bool success = false; bool success = false;
function = DefaultWindowManipulationType; function = DefaultWindowManipulationType;
if (parameters.size() > 0) if (parameters.size() > 0)
{ {
switch (parameters[0]) switch (til::at(parameters, 0))
{ {
case DispatchTypes::WindowManipulationType::RefreshWindow: case DispatchTypes::WindowManipulationType::RefreshWindow:
function = DispatchTypes::WindowManipulationType::RefreshWindow; function = DispatchTypes::WindowManipulationType::RefreshWindow;
@ -1608,7 +1605,7 @@ bool OutputStateMachineEngine::_GetWindowManipulationType(const std::basic_strin
// Return Value: // Return Value:
// - True if we successfully pulled the cursor style from the parameters we've stored. False otherwise. // - True if we successfully pulled the cursor style from the parameters we've stored. False otherwise.
bool OutputStateMachineEngine::_GetCursorStyle(const std::basic_string_view<size_t> parameters, bool OutputStateMachineEngine::_GetCursorStyle(const std::basic_string_view<size_t> parameters,
DispatchTypes::CursorStyle& cursorStyle) const DispatchTypes::CursorStyle& cursorStyle) const noexcept
{ {
bool success = false; bool success = false;
cursorStyle = DefaultCursorStyle; cursorStyle = DefaultCursorStyle;
@ -1621,7 +1618,7 @@ bool OutputStateMachineEngine::_GetCursorStyle(const std::basic_string_view<size
else if (parameters.size() == 1) else if (parameters.size() == 1)
{ {
// If there's one parameter, use it. // If there's one parameter, use it.
cursorStyle = (DispatchTypes::CursorStyle)parameters[0]; cursorStyle = (DispatchTypes::CursorStyle)til::at(parameters, 0);
success = true; success = true;
} }
@ -1670,7 +1667,7 @@ bool OutputStateMachineEngine::_GetRepeatCount(std::basic_string_view<size_t> pa
else if (parameters.size() == 1) else if (parameters.size() == 1)
{ {
// If there's one parameter, use it. // If there's one parameter, use it.
repeatCount = parameters[0]; repeatCount = til::at(parameters, 0);
success = true; success = true;
} }

View file

@ -23,7 +23,6 @@ namespace Microsoft::Console::VirtualTerminal
{ {
public: public:
OutputStateMachineEngine(std::unique_ptr<ITermDispatch> pDispatch); OutputStateMachineEngine(std::unique_ptr<ITermDispatch> pDispatch);
~OutputStateMachineEngine();
bool ActionExecute(const wchar_t wch) override; bool ActionExecute(const wchar_t wch) override;
bool ActionExecuteFromEscape(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<wchar_t> intermediates, const std::basic_string_view<wchar_t> intermediates,
const std::basic_string_view<size_t> parameters) override; const std::basic_string_view<size_t> parameters) override;
bool ActionClear() override; bool ActionClear() noexcept override;
bool ActionIgnore() override; bool ActionIgnore() noexcept override;
bool ActionOscDispatch(const wchar_t wch, bool ActionOscDispatch(const wchar_t wch,
const size_t parameter, const size_t parameter,
const std::wstring_view string) override; const std::wstring_view string) override;
bool ActionSs3Dispatch(const wchar_t wch, bool ActionSs3Dispatch(const wchar_t wch,
const std::basic_string_view<size_t> parameters) override; const std::basic_string_view<size_t> parameters) noexcept override;
bool FlushAtEndOfString() const override; bool FlushAtEndOfString() const noexcept override;
bool DispatchControlCharsFromEscape() const override; bool DispatchControlCharsFromEscape() const noexcept override;
bool DispatchIntermediatesFromEscape() const override; bool DispatchIntermediatesFromEscape() const noexcept override;
void SetTerminalConnection(Microsoft::Console::ITerminalOutputConnection* const pTtyConnection, void SetTerminalConnection(Microsoft::Console::ITerminalOutputConnection* const pTtyConnection,
std::function<bool()> pfnFlushToTerminal); std::function<bool()> pfnFlushToTerminal);
@ -152,32 +151,32 @@ namespace Microsoft::Console::VirtualTerminal
static constexpr DispatchTypes::EraseType DefaultEraseType = DispatchTypes::EraseType::ToEnd; static constexpr DispatchTypes::EraseType DefaultEraseType = DispatchTypes::EraseType::ToEnd;
bool _GetEraseOperation(const std::basic_string_view<size_t> parameters, bool _GetEraseOperation(const std::basic_string_view<size_t> parameters,
DispatchTypes::EraseType& eraseType) const; DispatchTypes::EraseType& eraseType) const noexcept;
static constexpr size_t DefaultCursorDistance = 1; static constexpr size_t DefaultCursorDistance = 1;
bool _GetCursorDistance(const std::basic_string_view<size_t> parameters, bool _GetCursorDistance(const std::basic_string_view<size_t> parameters,
size_t& distance) const; size_t& distance) const noexcept;
static constexpr size_t DefaultScrollDistance = 1; static constexpr size_t DefaultScrollDistance = 1;
bool _GetScrollDistance(const std::basic_string_view<size_t> parameters, bool _GetScrollDistance(const std::basic_string_view<size_t> parameters,
size_t& distance) const; size_t& distance) const noexcept;
static constexpr size_t DefaultConsoleWidth = 80; static constexpr size_t DefaultConsoleWidth = 80;
bool _GetConsoleWidth(const std::basic_string_view<size_t> parameters, bool _GetConsoleWidth(const std::basic_string_view<size_t> parameters,
size_t& consoleWidth) const; size_t& consoleWidth) const noexcept;
static constexpr size_t DefaultLine = 1; static constexpr size_t DefaultLine = 1;
static constexpr size_t DefaultColumn = 1; static constexpr size_t DefaultColumn = 1;
bool _GetXYPosition(const std::basic_string_view<size_t> parameters, bool _GetXYPosition(const std::basic_string_view<size_t> parameters,
size_t& line, size_t& line,
size_t& column) const; size_t& column) const noexcept;
bool _GetDeviceStatusOperation(const std::basic_string_view<size_t> parameters, bool _GetDeviceStatusOperation(const std::basic_string_view<size_t> parameters,
DispatchTypes::AnsiStatusType& statusType) const; DispatchTypes::AnsiStatusType& statusType) const noexcept;
bool _VerifyHasNoParameters(const std::basic_string_view<size_t> parameters) const; bool _VerifyHasNoParameters(const std::basic_string_view<size_t> parameters) const noexcept;
bool _VerifyDeviceAttributesParams(const std::basic_string_view<size_t> parameters) const; bool _VerifyDeviceAttributesParams(const std::basic_string_view<size_t> parameters) const noexcept;
bool _GetPrivateModeParams(const std::basic_string_view<size_t> parameters, bool _GetPrivateModeParams(const std::basic_string_view<size_t> parameters,
std::vector<DispatchTypes::PrivateModeParams>& privateModes) const; std::vector<DispatchTypes::PrivateModeParams>& privateModes) const;
@ -186,44 +185,42 @@ namespace Microsoft::Console::VirtualTerminal
static constexpr size_t DefaultBottomMargin = 0; static constexpr size_t DefaultBottomMargin = 0;
bool _GetTopBottomMargins(const std::basic_string_view<size_t> parameters, bool _GetTopBottomMargins(const std::basic_string_view<size_t> parameters,
size_t& topMargin, size_t& topMargin,
size_t& bottomMargin) const; size_t& bottomMargin) const noexcept;
bool _GetOscTitle(const std::wstring_view string, bool _GetOscTitle(const std::wstring_view string,
std::wstring& title) const; std::wstring& title) const;
static constexpr size_t DefaultTabDistance = 1; static constexpr size_t DefaultTabDistance = 1;
bool _GetTabDistance(const std::basic_string_view<size_t> parameters, bool _GetTabDistance(const std::basic_string_view<size_t> parameters,
size_t& distance) const; size_t& distance) const noexcept;
static constexpr size_t DefaultTabClearType = 0; static constexpr size_t DefaultTabClearType = 0;
bool _GetTabClearType(const std::basic_string_view<size_t> parameters, bool _GetTabClearType(const std::basic_string_view<size_t> parameters,
size_t& clearType) const; size_t& clearType) const noexcept;
static constexpr DesignateCharsetTypes DefaultDesignateCharsetType = DesignateCharsetTypes::G0; static constexpr DesignateCharsetTypes DefaultDesignateCharsetType = DesignateCharsetTypes::G0;
bool _GetDesignateType(const wchar_t intermediate, bool _GetDesignateType(const wchar_t intermediate,
DesignateCharsetTypes& designateType) const; DesignateCharsetTypes& designateType) const noexcept;
static constexpr DispatchTypes::WindowManipulationType DefaultWindowManipulationType = DispatchTypes::WindowManipulationType::Invalid; static constexpr DispatchTypes::WindowManipulationType DefaultWindowManipulationType = DispatchTypes::WindowManipulationType::Invalid;
bool _GetWindowManipulationType(const std::basic_string_view<size_t> parameters, bool _GetWindowManipulationType(const std::basic_string_view<size_t> parameters,
unsigned int& function) const; unsigned int& function) const noexcept;
static bool s_HexToUint(const wchar_t wch, static bool s_HexToUint(const wchar_t wch,
unsigned int& value); unsigned int& value) noexcept;
static bool s_IsNumber(const wchar_t wch);
static bool s_IsHexNumber(const wchar_t wch);
bool _GetOscSetColorTable(const std::wstring_view string, bool _GetOscSetColorTable(const std::wstring_view string,
size_t& tableIndex, size_t& tableIndex,
DWORD& rgb) const; DWORD& rgb) const noexcept;
static bool s_ParseColorSpec(const std::wstring_view string, static bool s_ParseColorSpec(const std::wstring_view string,
DWORD& rgb); DWORD& rgb) noexcept;
bool _GetOscSetColor(const std::wstring_view string, bool _GetOscSetColor(const std::wstring_view string,
DWORD& rgb) const; DWORD& rgb) const noexcept;
static constexpr DispatchTypes::CursorStyle DefaultCursorStyle = DispatchTypes::CursorStyle::BlinkingBlockDefault; static constexpr DispatchTypes::CursorStyle DefaultCursorStyle = DispatchTypes::CursorStyle::BlinkingBlockDefault;
bool _GetCursorStyle(const std::basic_string_view<size_t> parameters, bool _GetCursorStyle(const std::basic_string_view<size_t> parameters,
DispatchTypes::CursorStyle& cursorStyle) const; DispatchTypes::CursorStyle& cursorStyle) const noexcept;
static constexpr size_t DefaultRepeatCount = 1; static constexpr size_t DefaultRepeatCount = 1;
bool _GetRepeatCount(const std::basic_string_view<size_t> parameters, bool _GetRepeatCount(const std::basic_string_view<size_t> parameters,

View file

@ -33,15 +33,14 @@ IStateMachineEngine& StateMachine::Engine() noexcept
} }
// Routine Description: // Routine Description:
// - Determines if a character indicates an action that should be taken in the ground state - // - Determines if a character is a valid number character, 0-9.
// These are C0 characters and the C1 [single-character] CSI.
// Arguments: // Arguments:
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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: // Routine Description:
@ -52,7 +51,7 @@ bool StateMachine::s_IsActionableFromGround(const wchar_t wch)
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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) || return (wch >= AsciiChars::NUL && wch <= AsciiChars::ETB) ||
wch == AsciiChars::EM || wch == AsciiChars::EM ||
@ -78,7 +77,7 @@ bool StateMachine::s_IsC0Code(const wchar_t wch)
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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'; return wch == L'\x9b';
} }
@ -92,7 +91,7 @@ bool StateMachine::s_IsC1Csi(const wchar_t wch)
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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 return wch >= L' ' && wch <= L'/'; // 0x20 - 0x2F
} }
@ -103,7 +102,7 @@ bool StateMachine::s_IsIntermediate(const wchar_t wch)
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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; return wch == AsciiChars::DEL;
} }
@ -115,7 +114,7 @@ bool StateMachine::s_IsDelete(const wchar_t wch)
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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; return wch == AsciiChars::ESC;
} }
@ -127,7 +126,7 @@ bool StateMachine::s_IsEscape(const wchar_t wch)
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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 return wch == L'['; // 0x5B
} }
@ -140,7 +139,7 @@ bool StateMachine::s_IsCsiIndicator(const wchar_t wch)
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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 return wch == L';'; // 0x3B
} }
@ -152,7 +151,7 @@ bool StateMachine::s_IsCsiDelimiter(const wchar_t wch)
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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 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. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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 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. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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 return wch == L':'; // 0x3A
} }
@ -189,7 +188,7 @@ bool StateMachine::s_IsCsiInvalid(const wchar_t wch)
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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 return wch == L'O'; // 0x4F
} }
@ -201,7 +200,7 @@ bool StateMachine::s_IsSs3Indicator(const wchar_t wch)
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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 return wch == L']'; // 0x5D
} }
@ -214,7 +213,7 @@ bool StateMachine::s_IsOscIndicator(const wchar_t wch)
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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 return wch == L';'; // 0x3B
} }
@ -227,9 +226,9 @@ bool StateMachine::s_IsOscDelimiter(const wchar_t wch)
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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: // Routine Description:
@ -238,7 +237,7 @@ bool StateMachine::s_IsOscParamValue(const wchar_t wch)
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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; return wch == AsciiChars::ESC;
} }
@ -249,7 +248,7 @@ bool StateMachine::s_IsOscTerminationInitiator(const wchar_t wch)
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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' || return wch <= L'\x17' ||
wch == L'\x19' || wch == L'\x19' ||
@ -263,20 +262,21 @@ bool StateMachine::s_IsOscInvalid(const wchar_t wch)
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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 return wch == L'\x7' || wch == L'\x9C'; // Bell character or C1 terminator
} }
// Routine Description: // 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: // Arguments:
// - wch - Character to check. // - wch - Character to check.
// Return Value: // Return Value:
// - True if it is. False if it isn't. // - 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: // Routine Description:
@ -328,7 +328,7 @@ void StateMachine::_ActionEscDispatch(const wchar_t wch)
{ {
_trace.TraceOnAction(L"EscDispatch"); _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 the result.
_trace.DispatchSequenceTrace(success); _trace.DispatchSequenceTrace(success);
@ -351,9 +351,9 @@ void StateMachine::_ActionCsiDispatch(const wchar_t wch)
{ {
_trace.TraceOnAction(L"CsiDispatch"); _trace.TraceOnAction(L"CsiDispatch");
bool success = _engine->ActionCsiDispatch(wch, const bool success = _engine->ActionCsiDispatch(wch,
{ _intermediates.data(), _intermediates.size() }, { _intermediates.data(), _intermediates.size() },
{ _parameters.data(), _parameters.size() }); { _parameters.data(), _parameters.size() });
// Trace the result. // Trace the result.
_trace.DispatchSequenceTrace(success); _trace.DispatchSequenceTrace(success);
@ -438,7 +438,7 @@ void StateMachine::_ActionClear()
// - wch - Character to dispatch. // - wch - Character to dispatch.
// Return Value: // Return Value:
// - <none> // - <none>
void StateMachine::_ActionIgnore() void StateMachine::_ActionIgnore() noexcept
{ {
// do nothing. // do nothing.
_trace.TraceOnAction(L"Ignore"); _trace.TraceOnAction(L"Ignore");
@ -481,7 +481,7 @@ void StateMachine::_ActionOscDispatch(const wchar_t wch)
{ {
_trace.TraceOnAction(L"OscDispatch"); _trace.TraceOnAction(L"OscDispatch");
bool success = _engine->ActionOscDispatch(wch, _oscParameter, _oscString); const bool success = _engine->ActionOscDispatch(wch, _oscParameter, _oscString);
// Trace the result. // Trace the result.
_trace.DispatchSequenceTrace(success); _trace.DispatchSequenceTrace(success);
@ -504,7 +504,7 @@ void StateMachine::_ActionSs3Dispatch(const wchar_t wch)
{ {
_trace.TraceOnAction(L"Ss3Dispatch"); _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 the result.
_trace.DispatchSequenceTrace(success); _trace.DispatchSequenceTrace(success);
@ -525,7 +525,7 @@ void StateMachine::_ActionSs3Dispatch(const wchar_t wch)
// - <none> // - <none>
// Return Value: // Return Value:
// - <none> // - <none>
void StateMachine::_EnterGround() void StateMachine::_EnterGround() noexcept
{ {
_state = VTStates::Ground; _state = VTStates::Ground;
_trace.TraceStateChange(L"Ground"); _trace.TraceStateChange(L"Ground");
@ -555,7 +555,7 @@ void StateMachine::_EnterEscape()
// - <none> // - <none>
// Return Value: // Return Value:
// - <none> // - <none>
void StateMachine::_EnterEscapeIntermediate() void StateMachine::_EnterEscapeIntermediate() noexcept
{ {
_state = VTStates::EscapeIntermediate; _state = VTStates::EscapeIntermediate;
_trace.TraceStateChange(L"EscapeIntermediate"); _trace.TraceStateChange(L"EscapeIntermediate");
@ -584,7 +584,7 @@ void StateMachine::_EnterCsiEntry()
// - <none> // - <none>
// Return Value: // Return Value:
// - <none> // - <none>
void StateMachine::_EnterCsiParam() void StateMachine::_EnterCsiParam() noexcept
{ {
_state = VTStates::CsiParam; _state = VTStates::CsiParam;
_trace.TraceStateChange(L"CsiParam"); _trace.TraceStateChange(L"CsiParam");
@ -599,7 +599,7 @@ void StateMachine::_EnterCsiParam()
// - <none> // - <none>
// Return Value: // Return Value:
// - <none> // - <none>
void StateMachine::_EnterCsiIgnore() void StateMachine::_EnterCsiIgnore() noexcept
{ {
_state = VTStates::CsiIgnore; _state = VTStates::CsiIgnore;
_trace.TraceStateChange(L"CsiIgnore"); _trace.TraceStateChange(L"CsiIgnore");
@ -614,7 +614,7 @@ void StateMachine::_EnterCsiIgnore()
// - <none> // - <none>
// Return Value: // Return Value:
// - <none> // - <none>
void StateMachine::_EnterCsiIntermediate() void StateMachine::_EnterCsiIntermediate() noexcept
{ {
_state = VTStates::CsiIntermediate; _state = VTStates::CsiIntermediate;
_trace.TraceStateChange(L"CsiIntermediate"); _trace.TraceStateChange(L"CsiIntermediate");
@ -628,7 +628,7 @@ void StateMachine::_EnterCsiIntermediate()
// - <none> // - <none>
// Return Value: // Return Value:
// - <none> // - <none>
void StateMachine::_EnterOscParam() void StateMachine::_EnterOscParam() noexcept
{ {
_state = VTStates::OscParam; _state = VTStates::OscParam;
_trace.TraceStateChange(L"OscParam"); _trace.TraceStateChange(L"OscParam");
@ -642,7 +642,7 @@ void StateMachine::_EnterOscParam()
// - <none> // - <none>
// Return Value: // Return Value:
// - <none> // - <none>
void StateMachine::_EnterOscString() void StateMachine::_EnterOscString() noexcept
{ {
_state = VTStates::OscString; _state = VTStates::OscString;
_trace.TraceStateChange(L"OscString"); _trace.TraceStateChange(L"OscString");
@ -657,7 +657,7 @@ void StateMachine::_EnterOscString()
// - <none> // - <none>
// Return Value: // Return Value:
// - <none> // - <none>
void StateMachine::_EnterOscTermination() void StateMachine::_EnterOscTermination() noexcept
{ {
_state = VTStates::OscTermination; _state = VTStates::OscTermination;
_trace.TraceStateChange(L"OscTermination"); _trace.TraceStateChange(L"OscTermination");
@ -686,7 +686,7 @@ void StateMachine::_EnterSs3Entry()
// - <none> // - <none>
// Return Value: // Return Value:
// - <none> // - <none>
void StateMachine::_EnterSs3Param() void StateMachine::_EnterSs3Param() noexcept
{ {
_state = VTStates::Ss3Param; _state = VTStates::Ss3Param;
_trace.TraceStateChange(L"Ss3Param"); _trace.TraceStateChange(L"Ss3Param");
@ -705,11 +705,11 @@ void StateMachine::_EnterSs3Param()
void StateMachine::_EventGround(const wchar_t wch) void StateMachine::_EventGround(const wchar_t wch)
{ {
_trace.TraceOnEvent(L"Ground"); _trace.TraceOnEvent(L"Ground");
if (s_IsC0Code(wch) || s_IsDelete(wch)) if (_isC0Code(wch) || _isDelete(wch))
{ {
_ActionExecute(wch); _ActionExecute(wch);
} }
else if (s_IsC1Csi(wch)) else if (_isC1Csi(wch))
{ {
_EnterCsiEntry(); _EnterCsiEntry();
} }
@ -734,7 +734,7 @@ void StateMachine::_EventGround(const wchar_t wch)
void StateMachine::_EventEscape(const wchar_t wch) void StateMachine::_EventEscape(const wchar_t wch)
{ {
_trace.TraceOnEvent(L"Escape"); _trace.TraceOnEvent(L"Escape");
if (s_IsC0Code(wch)) if (_isC0Code(wch))
{ {
if (_engine->DispatchControlCharsFromEscape()) if (_engine->DispatchControlCharsFromEscape())
{ {
@ -746,11 +746,11 @@ void StateMachine::_EventEscape(const wchar_t wch)
_ActionExecute(wch); _ActionExecute(wch);
} }
} }
else if (s_IsDelete(wch)) else if (_isDelete(wch))
{ {
_ActionIgnore(); _ActionIgnore();
} }
else if (s_IsIntermediate(wch)) else if (_isIntermediate(wch))
{ {
if (_engine->DispatchIntermediatesFromEscape()) if (_engine->DispatchIntermediatesFromEscape())
{ {
@ -763,15 +763,15 @@ void StateMachine::_EventEscape(const wchar_t wch)
_EnterEscapeIntermediate(); _EnterEscapeIntermediate();
} }
} }
else if (s_IsCsiIndicator(wch)) else if (_isCsiIndicator(wch))
{ {
_EnterCsiEntry(); _EnterCsiEntry();
} }
else if (s_IsOscIndicator(wch)) else if (_isOscIndicator(wch))
{ {
_EnterOscParam(); _EnterOscParam();
} }
else if (s_IsSs3Indicator(wch)) else if (_isSs3Indicator(wch))
{ {
_EnterSs3Entry(); _EnterSs3Entry();
} }
@ -796,15 +796,15 @@ void StateMachine::_EventEscape(const wchar_t wch)
void StateMachine::_EventEscapeIntermediate(const wchar_t wch) void StateMachine::_EventEscapeIntermediate(const wchar_t wch)
{ {
_trace.TraceOnEvent(L"EscapeIntermediate"); _trace.TraceOnEvent(L"EscapeIntermediate");
if (s_IsC0Code(wch)) if (_isC0Code(wch))
{ {
_ActionExecute(wch); _ActionExecute(wch);
} }
else if (s_IsIntermediate(wch)) else if (_isIntermediate(wch))
{ {
_ActionCollect(wch); _ActionCollect(wch);
} }
else if (s_IsDelete(wch)) else if (_isDelete(wch))
{ {
_ActionIgnore(); _ActionIgnore();
} }
@ -832,29 +832,29 @@ void StateMachine::_EventEscapeIntermediate(const wchar_t wch)
void StateMachine::_EventCsiEntry(const wchar_t wch) void StateMachine::_EventCsiEntry(const wchar_t wch)
{ {
_trace.TraceOnEvent(L"CsiEntry"); _trace.TraceOnEvent(L"CsiEntry");
if (s_IsC0Code(wch)) if (_isC0Code(wch))
{ {
_ActionExecute(wch); _ActionExecute(wch);
} }
else if (s_IsDelete(wch)) else if (_isDelete(wch))
{ {
_ActionIgnore(); _ActionIgnore();
} }
else if (s_IsIntermediate(wch)) else if (_isIntermediate(wch))
{ {
_ActionCollect(wch); _ActionCollect(wch);
_EnterCsiIntermediate(); _EnterCsiIntermediate();
} }
else if (s_IsCsiInvalid(wch)) else if (_isCsiInvalid(wch))
{ {
_EnterCsiIgnore(); _EnterCsiIgnore();
} }
else if (s_IsCsiParamValue(wch) || s_IsCsiDelimiter(wch)) else if (_isCsiParamValue(wch) || _isCsiDelimiter(wch))
{ {
_ActionParam(wch); _ActionParam(wch);
_EnterCsiParam(); _EnterCsiParam();
} }
else if (s_IsCsiPrivateMarker(wch)) else if (_isCsiPrivateMarker(wch))
{ {
_ActionCollect(wch); _ActionCollect(wch);
_EnterCsiParam(); _EnterCsiParam();
@ -881,19 +881,19 @@ void StateMachine::_EventCsiEntry(const wchar_t wch)
void StateMachine::_EventCsiIntermediate(const wchar_t wch) void StateMachine::_EventCsiIntermediate(const wchar_t wch)
{ {
_trace.TraceOnEvent(L"CsiIntermediate"); _trace.TraceOnEvent(L"CsiIntermediate");
if (s_IsC0Code(wch)) if (_isC0Code(wch))
{ {
_ActionExecute(wch); _ActionExecute(wch);
} }
else if (s_IsIntermediate(wch)) else if (_isIntermediate(wch))
{ {
_ActionCollect(wch); _ActionCollect(wch);
} }
else if (s_IsDelete(wch)) else if (_isDelete(wch))
{ {
_ActionIgnore(); _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(); _EnterCsiIgnore();
} }
@ -919,19 +919,19 @@ void StateMachine::_EventCsiIntermediate(const wchar_t wch)
void StateMachine::_EventCsiIgnore(const wchar_t wch) void StateMachine::_EventCsiIgnore(const wchar_t wch)
{ {
_trace.TraceOnEvent(L"CsiIgnore"); _trace.TraceOnEvent(L"CsiIgnore");
if (s_IsC0Code(wch)) if (_isC0Code(wch))
{ {
_ActionExecute(wch); _ActionExecute(wch);
} }
else if (s_IsDelete(wch)) else if (_isDelete(wch))
{ {
_ActionIgnore(); _ActionIgnore();
} }
else if (s_IsIntermediate(wch)) else if (_isIntermediate(wch))
{ {
_ActionIgnore(); _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(); _ActionIgnore();
} }
@ -957,24 +957,24 @@ void StateMachine::_EventCsiIgnore(const wchar_t wch)
void StateMachine::_EventCsiParam(const wchar_t wch) void StateMachine::_EventCsiParam(const wchar_t wch)
{ {
_trace.TraceOnEvent(L"CsiParam"); _trace.TraceOnEvent(L"CsiParam");
if (s_IsC0Code(wch)) if (_isC0Code(wch))
{ {
_ActionExecute(wch); _ActionExecute(wch);
} }
else if (s_IsDelete(wch)) else if (_isDelete(wch))
{ {
_ActionIgnore(); _ActionIgnore();
} }
else if (s_IsCsiParamValue(wch) || s_IsCsiDelimiter(wch)) else if (_isCsiParamValue(wch) || _isCsiDelimiter(wch))
{ {
_ActionParam(wch); _ActionParam(wch);
} }
else if (s_IsIntermediate(wch)) else if (_isIntermediate(wch))
{ {
_ActionCollect(wch); _ActionCollect(wch);
_EnterCsiIntermediate(); _EnterCsiIntermediate();
} }
else if (s_IsCsiInvalid(wch) || s_IsCsiPrivateMarker(wch)) else if (_isCsiInvalid(wch) || _isCsiPrivateMarker(wch))
{ {
_EnterCsiIgnore(); _EnterCsiIgnore();
} }
@ -998,15 +998,15 @@ void StateMachine::_EventCsiParam(const wchar_t wch)
void StateMachine::_EventOscParam(const wchar_t wch) void StateMachine::_EventOscParam(const wchar_t wch)
{ {
_trace.TraceOnEvent(L"OscParam"); _trace.TraceOnEvent(L"OscParam");
if (s_IsOscTerminator(wch)) if (_isOscTerminator(wch))
{ {
_EnterGround(); _EnterGround();
} }
else if (s_IsOscParamValue(wch)) else if (_isOscParamValue(wch))
{ {
_ActionOscParam(wch); _ActionOscParam(wch);
} }
else if (s_IsOscDelimiter(wch)) else if (_isOscDelimiter(wch))
{ {
_EnterOscString(); _EnterOscString();
} }
@ -1031,16 +1031,16 @@ void StateMachine::_EventOscParam(const wchar_t wch)
void StateMachine::_EventOscString(const wchar_t wch) void StateMachine::_EventOscString(const wchar_t wch)
{ {
_trace.TraceOnEvent(L"OscString"); _trace.TraceOnEvent(L"OscString");
if (s_IsOscTerminator(wch)) if (_isOscTerminator(wch))
{ {
_ActionOscDispatch(wch); _ActionOscDispatch(wch);
_EnterGround(); _EnterGround();
} }
else if (s_IsOscTerminationInitiator(wch)) else if (_isOscTerminationInitiator(wch))
{ {
_EnterOscTermination(); _EnterOscTermination();
} }
else if (s_IsOscInvalid(wch)) else if (_isOscInvalid(wch))
{ {
_ActionIgnore(); _ActionIgnore();
} }
@ -1085,21 +1085,21 @@ void StateMachine::_EventOscTermination(const wchar_t wch)
void StateMachine::_EventSs3Entry(const wchar_t wch) void StateMachine::_EventSs3Entry(const wchar_t wch)
{ {
_trace.TraceOnEvent(L"Ss3Entry"); _trace.TraceOnEvent(L"Ss3Entry");
if (s_IsC0Code(wch)) if (_isC0Code(wch))
{ {
_ActionExecute(wch); _ActionExecute(wch);
} }
else if (s_IsDelete(wch)) else if (_isDelete(wch))
{ {
_ActionIgnore(); _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 // It's safe for us to go into the CSI ignore here, because both SS3 and
// CSI sequences ignore characters the same way. // CSI sequences ignore characters the same way.
_EnterCsiIgnore(); _EnterCsiIgnore();
} }
else if (s_IsCsiParamValue(wch) || s_IsCsiDelimiter(wch)) else if (_isCsiParamValue(wch) || _isCsiDelimiter(wch))
{ {
_ActionParam(wch); _ActionParam(wch);
_EnterSs3Param(); _EnterSs3Param();
@ -1126,19 +1126,19 @@ void StateMachine::_EventSs3Entry(const wchar_t wch)
void StateMachine::_EventSs3Param(const wchar_t wch) void StateMachine::_EventSs3Param(const wchar_t wch)
{ {
_trace.TraceOnEvent(L"Ss3Param"); _trace.TraceOnEvent(L"Ss3Param");
if (s_IsC0Code(wch)) if (_isC0Code(wch))
{ {
_ActionExecute(wch); _ActionExecute(wch);
} }
else if (s_IsDelete(wch)) else if (_isDelete(wch))
{ {
_ActionIgnore(); _ActionIgnore();
} }
else if (s_IsCsiParamValue(wch) || s_IsCsiDelimiter(wch)) else if (_isCsiParamValue(wch) || _isCsiDelimiter(wch))
{ {
_ActionParam(wch); _ActionParam(wch);
} }
else if (s_IsCsiInvalid(wch) || s_IsCsiPrivateMarker(wch)) else if (_isCsiInvalid(wch) || _isCsiPrivateMarker(wch))
{ {
_EnterCsiIgnore(); _EnterCsiIgnore();
} }
@ -1166,7 +1166,7 @@ void StateMachine::ProcessCharacter(const wchar_t wch)
_ActionExecute(wch); _ActionExecute(wch);
_EnterGround(); _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 // Don't go to escape from the OSC string state - ESC can be used to
// terminate OSC strings. // terminate OSC strings.
@ -1259,7 +1259,7 @@ void StateMachine::ProcessString(const std::wstring_view string)
} }
else 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... _engine->ActionPrintString(_run); // ... print all the chars leading up to it as part of the run...
_trace.DispatchPrintRunTrace(_run); _trace.DispatchPrintRunTrace(_run);
@ -1356,7 +1356,7 @@ void StateMachine::ProcessString(const std::wstring_view string)
// - <none> // - <none>
// Return Value: // Return Value:
// - <none> // - <none>
void StateMachine::ResetState() void StateMachine::ResetState() noexcept
{ {
_EnterGround(); _EnterGround();
} }

View file

@ -34,7 +34,7 @@ namespace Microsoft::Console::VirtualTerminal
void ProcessCharacter(const wchar_t wch); void ProcessCharacter(const wchar_t wch);
void ProcessString(const std::wstring_view string); void ProcessString(const std::wstring_view string);
void ResetState(); void ResetState() noexcept;
bool FlushToTerminal(); bool FlushToTerminal();
@ -42,26 +42,6 @@ namespace Microsoft::Console::VirtualTerminal
IStateMachineEngine& Engine() noexcept; IStateMachineEngine& Engine() noexcept;
private: 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 _ActionExecute(const wchar_t wch);
void _ActionExecuteFromEscape(const wchar_t wch); void _ActionExecuteFromEscape(const wchar_t wch);
void _ActionPrint(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 _ActionSs3Dispatch(const wchar_t wch);
void _ActionClear(); void _ActionClear();
void _ActionIgnore(); void _ActionIgnore() noexcept;
void _EnterGround(); void _EnterGround() noexcept;
void _EnterEscape(); void _EnterEscape();
void _EnterEscapeIntermediate(); void _EnterEscapeIntermediate() noexcept;
void _EnterCsiEntry(); void _EnterCsiEntry();
void _EnterCsiParam(); void _EnterCsiParam() noexcept;
void _EnterCsiIgnore(); void _EnterCsiIgnore() noexcept;
void _EnterCsiIntermediate(); void _EnterCsiIntermediate() noexcept;
void _EnterOscParam(); void _EnterOscParam() noexcept;
void _EnterOscString(); void _EnterOscString() noexcept;
void _EnterOscTermination(); void _EnterOscTermination() noexcept;
void _EnterSs3Entry(); void _EnterSs3Entry();
void _EnterSs3Param(); void _EnterSs3Param() noexcept;
void _EventGround(const wchar_t wch); void _EventGround(const wchar_t wch);
void _EventEscape(const wchar_t wch); void _EventEscape(const wchar_t wch);

View file

@ -5,6 +5,13 @@
#include "telemetry.hpp" #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, TRACELOGGING_DEFINE_PROVIDER(g_hConsoleVirtTermParserEventTraceProvider,
"Microsoft.Windows.Console.VirtualTerminal.Parser", "Microsoft.Windows.Console.VirtualTerminal.Parser",
// {c9ba2a84-d3ca-5e19-2bd6-776a0910cb9d} // {c9ba2a84-d3ca-5e19-2bd6-776a0910cb9d}
@ -15,7 +22,7 @@ using namespace Microsoft::Console::VirtualTerminal;
#pragma warning(push) #pragma warning(push)
// Disable 4351 so we can initialize the arrays to 0 without a warning. // Disable 4351 so we can initialize the arrays to 0 without a warning.
#pragma warning(disable : 4351) #pragma warning(disable : 4351)
TermTelemetry::TermTelemetry() : TermTelemetry::TermTelemetry() noexcept :
_uiTimesUsedCurrent(0), _uiTimesUsedCurrent(0),
_uiTimesFailedCurrent(0), _uiTimesFailedCurrent(0),
_uiTimesFailedOutsideRangeCurrent(0), _uiTimesFailedOutsideRangeCurrent(0),
@ -34,8 +41,12 @@ TermTelemetry::TermTelemetry() :
TermTelemetry::~TermTelemetry() TermTelemetry::~TermTelemetry()
{ {
WriteFinalTraceLog(); try
TraceLoggingUnregister(g_hConsoleVirtTermParserEventTraceProvider); {
WriteFinalTraceLog();
TraceLoggingUnregister(g_hConsoleVirtTermParserEventTraceProvider);
}
CATCH_LOG()
} }
// Routine Description: // Routine Description:
@ -45,7 +56,7 @@ TermTelemetry::~TermTelemetry()
// - code - VT100 code. // - code - VT100 code.
// Return Value: // Return Value:
// - <none> // - <none>
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. // 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 // 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. // - code - VT100 code.
// Return Value: // Return Value:
// - <none> // - <none>
void TermTelemetry::LogFailed(const wchar_t wch) void TermTelemetry::LogFailed(const wchar_t wch) noexcept
{ {
if (wch > CHAR_MAX) if (wch > CHAR_MAX)
{ {
@ -85,11 +96,11 @@ void TermTelemetry::LogFailed(const wchar_t wch)
// - <none> // - <none>
// Return Value: // Return Value:
// - total number. // - total number.
unsigned int TermTelemetry::GetAndResetTimesUsedCurrent() unsigned int TermTelemetry::GetAndResetTimesUsedCurrent() noexcept
{ {
unsigned int uiTemp = _uiTimesUsedCurrent; const auto temp = _uiTimesUsedCurrent;
_uiTimesUsedCurrent = 0; _uiTimesUsedCurrent = 0;
return uiTemp; return temp;
} }
// Routine Description: // Routine Description:
@ -99,11 +110,11 @@ unsigned int TermTelemetry::GetAndResetTimesUsedCurrent()
// - <none> // - <none>
// Return Value: // Return Value:
// - total number. // - total number.
unsigned int TermTelemetry::GetAndResetTimesFailedCurrent() unsigned int TermTelemetry::GetAndResetTimesFailedCurrent() noexcept
{ {
unsigned int uiTemp = _uiTimesFailedCurrent; const auto temp = _uiTimesFailedCurrent;
_uiTimesFailedCurrent = 0; _uiTimesFailedCurrent = 0;
return uiTemp; return temp;
} }
// Routine Description: // Routine Description:
@ -113,11 +124,11 @@ unsigned int TermTelemetry::GetAndResetTimesFailedCurrent()
// - <none> // - <none>
// Return Value: // Return Value:
// - total number. // - total number.
unsigned int TermTelemetry::GetAndResetTimesFailedOutsideRangeCurrent() unsigned int TermTelemetry::GetAndResetTimesFailedOutsideRangeCurrent() noexcept
{ {
unsigned int uiTemp = _uiTimesFailedOutsideRangeCurrent; const auto temp = _uiTimesFailedOutsideRangeCurrent;
_uiTimesFailedOutsideRangeCurrent = 0; _uiTimesFailedOutsideRangeCurrent = 0;
return uiTemp; return temp;
} }
// Routine Description: // Routine Description:
@ -128,7 +139,7 @@ unsigned int TermTelemetry::GetAndResetTimesFailedOutsideRangeCurrent()
// - writeLog - true if we should write the log. // - writeLog - true if we should write the log.
// Return Value: // Return Value:
// - <none> // - <none>
void TermTelemetry::SetShouldWriteFinalLog(const bool writeLog) void TermTelemetry::SetShouldWriteFinalLog(const bool writeLog) noexcept
{ {
_fShouldWriteFinalLog = writeLog; _fShouldWriteFinalLog = writeLog;
} }
@ -140,7 +151,7 @@ void TermTelemetry::SetShouldWriteFinalLog(const bool writeLog)
// - activityId - Pointer to Guid to set our activity Id to. // - activityId - Pointer to Guid to set our activity Id to.
// Return Value: // Return Value:
// - <none> // - <none>
void TermTelemetry::SetActivityId(const GUID* activityId) void TermTelemetry::SetActivityId(const GUID* activityId) noexcept
{ {
_activityId = *activityId; _activityId = *activityId;
} }
@ -252,3 +263,5 @@ void TermTelemetry::WriteFinalTraceLog() const
} }
} }
} }
#pragma warning(pop)

View file

@ -24,7 +24,7 @@ namespace Microsoft::Console::VirtualTerminal
{ {
public: public:
// Implement this as a singleton class. // Implement this as a singleton class.
static TermTelemetry& Instance() static TermTelemetry& Instance() noexcept
{ {
static TermTelemetry s_Instance; static TermTelemetry s_Instance;
return 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. // Only use this last enum as a count of the number of codes.
NUMBER_OF_CODES NUMBER_OF_CODES
}; };
void Log(const Codes code); void Log(const Codes code) noexcept;
void LogFailed(const wchar_t wch); void LogFailed(const wchar_t wch) noexcept;
void SetShouldWriteFinalLog(const bool writeLog); void SetShouldWriteFinalLog(const bool writeLog) noexcept;
void SetActivityId(const GUID* activityId); void SetActivityId(const GUID* activityId) noexcept;
unsigned int GetAndResetTimesUsedCurrent(); unsigned int GetAndResetTimesUsedCurrent() noexcept;
unsigned int GetAndResetTimesFailedCurrent(); unsigned int GetAndResetTimesFailedCurrent() noexcept;
unsigned int GetAndResetTimesFailedOutsideRangeCurrent(); unsigned int GetAndResetTimesFailedOutsideRangeCurrent() noexcept;
private: private:
// Used to prevent multiple instances // Used to prevent multiple instances
TermTelemetry(); TermTelemetry() noexcept;
~TermTelemetry(); ~TermTelemetry();
TermTelemetry(TermTelemetry const&); TermTelemetry(TermTelemetry const&) = delete;
void operator=(TermTelemetry const&); TermTelemetry(TermTelemetry&&) = delete;
TermTelemetry& operator=(const TermTelemetry&) = delete;
TermTelemetry& operator=(TermTelemetry&&) = delete;
void WriteFinalTraceLog() const; void WriteFinalTraceLog() const;

View file

@ -6,16 +6,19 @@
using namespace Microsoft::Console::VirtualTerminal; 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(); ClearSequenceTrace();
} }
ParserTracing::~ParserTracing() void ParserTracing::TraceStateChange(const std::wstring_view name) const noexcept
{
}
void ParserTracing::TraceStateChange(const std::wstring_view name) const
{ {
TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider, TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider,
"StateMachine_EnterState", "StateMachine_EnterState",
@ -23,7 +26,7 @@ void ParserTracing::TraceStateChange(const std::wstring_view name) const
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE)); 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, TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider,
"StateMachine_Action", "StateMachine_Action",
@ -33,7 +36,7 @@ void ParserTracing::TraceOnAction(const std::wstring_view name) const
void ParserTracing::TraceOnExecute(const wchar_t wch) const void ParserTracing::TraceOnExecute(const wchar_t wch) const
{ {
INT16 sch = (INT16)wch; const auto sch = gsl::narrow_cast<INT16>(wch);
TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider, TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider,
"StateMachine_Execute", "StateMachine_Execute",
TraceLoggingWChar(wch), TraceLoggingWChar(wch),
@ -43,7 +46,7 @@ void ParserTracing::TraceOnExecute(const wchar_t wch) const
void ParserTracing::TraceOnExecuteFromEscape(const wchar_t wch) const void ParserTracing::TraceOnExecuteFromEscape(const wchar_t wch) const
{ {
INT16 sch = (INT16)wch; const auto sch = gsl::narrow_cast<INT16>(wch);
TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider, TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider,
"StateMachine_ExecuteFromEscape", "StateMachine_ExecuteFromEscape",
TraceLoggingWChar(wch), TraceLoggingWChar(wch),
@ -51,7 +54,7 @@ void ParserTracing::TraceOnExecuteFromEscape(const wchar_t wch) const
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE)); 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, TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider,
"StateMachine_Event", "StateMachine_Event",
@ -62,7 +65,7 @@ void ParserTracing::TraceOnEvent(const std::wstring_view name) const
void ParserTracing::TraceCharInput(const wchar_t wch) void ParserTracing::TraceCharInput(const wchar_t wch)
{ {
AddSequenceTrace(wch); AddSequenceTrace(wch);
INT16 sch = (INT16)wch; const auto sch = gsl::narrow_cast<INT16>(wch);
TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider, TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider,
"StateMachine_NewChar", "StateMachine_NewChar",
@ -76,7 +79,7 @@ void ParserTracing::AddSequenceTrace(const wchar_t wch)
_sequenceTrace.push_back(wch); _sequenceTrace.push_back(wch);
} }
void ParserTracing::DispatchSequenceTrace(const bool fSuccess) void ParserTracing::DispatchSequenceTrace(const bool fSuccess) noexcept
{ {
if (fSuccess) if (fSuccess)
{ {
@ -96,7 +99,7 @@ void ParserTracing::DispatchSequenceTrace(const bool fSuccess)
ClearSequenceTrace(); ClearSequenceTrace();
} }
void ParserTracing::ClearSequenceTrace() void ParserTracing::ClearSequenceTrace() noexcept
{ {
_sequenceTrace.clear(); _sequenceTrace.clear();
} }
@ -106,8 +109,8 @@ void ParserTracing::DispatchPrintRunTrace(const std::wstring_view string) const
{ {
if (string.size() == 1) if (string.size() == 1)
{ {
wchar_t wch = string.front(); const auto wch = til::at(string, 0);
INT16 sch = (INT16)wch; const auto sch = gsl::narrow_cast<INT16>(wch);
TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider, TraceLoggingWrite(g_hConsoleVirtTermParserEventTraceProvider,
"StateMachine_PrintRun", "StateMachine_PrintRun",
TraceLoggingWChar(wch), TraceLoggingWChar(wch),
@ -125,3 +128,5 @@ void ParserTracing::DispatchPrintRunTrace(const std::wstring_view string) const
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE)); TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
} }
} }
#pragma warning(pop)

View file

@ -21,19 +21,18 @@ namespace Microsoft::Console::VirtualTerminal
class ParserTracing sealed class ParserTracing sealed
{ {
public: public:
ParserTracing(); ParserTracing() noexcept;
~ParserTracing();
void TraceStateChange(const std::wstring_view name) const; void TraceStateChange(const std::wstring_view name) const noexcept;
void TraceOnAction(const std::wstring_view name) const; void TraceOnAction(const std::wstring_view name) const noexcept;
void TraceOnExecute(const wchar_t wch) const; void TraceOnExecute(const wchar_t wch) const;
void TraceOnExecuteFromEscape(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 TraceCharInput(const wchar_t wch);
void AddSequenceTrace(const wchar_t wch); void AddSequenceTrace(const wchar_t wch);
void DispatchSequenceTrace(const bool fSuccess); void DispatchSequenceTrace(const bool fSuccess) noexcept;
void ClearSequenceTrace(); void ClearSequenceTrace() noexcept;
void DispatchPrintRunTrace(const std::wstring_view string) const; void DispatchPrintRunTrace(const std::wstring_view string) const;
private: private:

View file

@ -689,63 +689,63 @@ public:
*this = dispatch; *this = dispatch;
} }
bool CursorUp(_In_ size_t const uiDistance) override bool CursorUp(_In_ size_t const uiDistance) noexcept override
{ {
_cursorUp = true; _cursorUp = true;
_cursorDistance = uiDistance; _cursorDistance = uiDistance;
return true; return true;
} }
bool CursorDown(_In_ size_t const uiDistance) override bool CursorDown(_In_ size_t const uiDistance) noexcept override
{ {
_cursorDown = true; _cursorDown = true;
_cursorDistance = uiDistance; _cursorDistance = uiDistance;
return true; return true;
} }
bool CursorBackward(_In_ size_t const uiDistance) override bool CursorBackward(_In_ size_t const uiDistance) noexcept override
{ {
_cursorBackward = true; _cursorBackward = true;
_cursorDistance = uiDistance; _cursorDistance = uiDistance;
return true; return true;
} }
bool CursorForward(_In_ size_t const uiDistance) override bool CursorForward(_In_ size_t const uiDistance) noexcept override
{ {
_cursorForward = true; _cursorForward = true;
_cursorDistance = uiDistance; _cursorDistance = uiDistance;
return true; return true;
} }
bool CursorNextLine(_In_ size_t const uiDistance) override bool CursorNextLine(_In_ size_t const uiDistance) noexcept override
{ {
_cursorNextLine = true; _cursorNextLine = true;
_cursorDistance = uiDistance; _cursorDistance = uiDistance;
return true; return true;
} }
bool CursorPrevLine(_In_ size_t const uiDistance) override bool CursorPrevLine(_In_ size_t const uiDistance) noexcept override
{ {
_cursorPreviousLine = true; _cursorPreviousLine = true;
_cursorDistance = uiDistance; _cursorDistance = uiDistance;
return true; return true;
} }
bool CursorHorizontalPositionAbsolute(_In_ size_t const uiPosition) override bool CursorHorizontalPositionAbsolute(_In_ size_t const uiPosition) noexcept override
{ {
_cursorHorizontalPositionAbsolute = true; _cursorHorizontalPositionAbsolute = true;
_cursorDistance = uiPosition; _cursorDistance = uiPosition;
return true; return true;
} }
bool VerticalLinePositionAbsolute(_In_ size_t const uiPosition) override bool VerticalLinePositionAbsolute(_In_ size_t const uiPosition) noexcept override
{ {
_verticalLinePositionAbsolute = true; _verticalLinePositionAbsolute = true;
_cursorDistance = uiPosition; _cursorDistance = uiPosition;
return true; 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; _cursorPosition = true;
_line = uiLine; _line = uiLine;
@ -753,61 +753,62 @@ public:
return true; return true;
} }
bool CursorSaveState() override bool CursorSaveState() noexcept override
{ {
_cursorSave = true; _cursorSave = true;
return true; return true;
} }
bool CursorRestoreState() override bool CursorRestoreState() noexcept override
{ {
_cursorLoad = true; _cursorLoad = true;
return true; return true;
} }
bool EraseInDisplay(const DispatchTypes::EraseType eraseType) override bool EraseInDisplay(const DispatchTypes::EraseType eraseType) noexcept override
{ {
_eraseDisplay = true; _eraseDisplay = true;
_eraseType = eraseType; _eraseType = eraseType;
return true; return true;
} }
bool EraseInLine(const DispatchTypes::EraseType eraseType) override bool EraseInLine(const DispatchTypes::EraseType eraseType) noexcept override
{ {
_eraseLine = true; _eraseLine = true;
_eraseType = eraseType; _eraseType = eraseType;
return true; return true;
} }
bool InsertCharacter(_In_ size_t const uiCount) override bool InsertCharacter(_In_ size_t const uiCount) noexcept override
{ {
_insertCharacter = true; _insertCharacter = true;
_cursorDistance = uiCount; _cursorDistance = uiCount;
return true; return true;
} }
bool DeleteCharacter(_In_ size_t const uiCount) override bool DeleteCharacter(_In_ size_t const uiCount) noexcept override
{ {
_deleteCharacter = true; _deleteCharacter = true;
_cursorDistance = uiCount; _cursorDistance = uiCount;
return true; return true;
} }
bool CursorVisibility(const bool fIsVisible) override bool CursorVisibility(const bool fIsVisible) noexcept override
{ {
_cursorVisible = fIsVisible; _cursorVisible = fIsVisible;
return true; return true;
} }
bool SetGraphicsRendition(const std::basic_string_view<DispatchTypes::GraphicsOptions> options) override bool SetGraphicsRendition(const std::basic_string_view<DispatchTypes::GraphicsOptions> options) noexcept override
try
{ {
_options.assign(options.cbegin(), options.cend()); _options.assign(options.cbegin(), options.cend());
_setGraphics = true; _setGraphics = true;
return true; return true;
} }
CATCH_LOG_RETURN_FALSE()
bool DeviceStatusReport(const DispatchTypes::AnsiStatusType statusType) override bool DeviceStatusReport(const DispatchTypes::AnsiStatusType statusType) noexcept override
{ {
_deviceStatusReport = true; _deviceStatusReport = true;
_statusReportType = statusType; _statusReportType = statusType;
@ -815,7 +816,7 @@ public:
return true; return true;
} }
bool DeviceAttributes() override bool DeviceAttributes() noexcept override
{ {
_deviceAttributes = true; _deviceAttributes = true;
@ -869,53 +870,53 @@ public:
return cFailures == 0; return cFailures == 0;
} }
bool SetPrivateModes(const std::basic_string_view<DispatchTypes::PrivateModeParams> params) override bool SetPrivateModes(const std::basic_string_view<DispatchTypes::PrivateModeParams> params) noexcept override
{ {
return _SetResetPrivateModesHelper(params, true); return _SetResetPrivateModesHelper(params, true);
} }
bool ResetPrivateModes(const std::basic_string_view<DispatchTypes::PrivateModeParams> params) override bool ResetPrivateModes(const std::basic_string_view<DispatchTypes::PrivateModeParams> params) noexcept override
{ {
return _SetResetPrivateModesHelper(params, false); return _SetResetPrivateModesHelper(params, false);
} }
bool SetColumns(_In_ size_t const uiColumns) override bool SetColumns(_In_ size_t const uiColumns) noexcept override
{ {
_windowWidth = uiColumns; _windowWidth = uiColumns;
return true; return true;
} }
bool SetVirtualTerminalInputMode(const bool fApplicationMode) bool SetVirtualTerminalInputMode(const bool fApplicationMode) noexcept
{ {
_cursorKeysMode = fApplicationMode; _cursorKeysMode = fApplicationMode;
return true; return true;
} }
bool EnableCursorBlinking(const bool bEnable) override bool EnableCursorBlinking(const bool bEnable) noexcept override
{ {
_cursorBlinking = bEnable; _cursorBlinking = bEnable;
return true; return true;
} }
bool SetOriginMode(const bool fRelativeMode) override bool SetOriginMode(const bool fRelativeMode) noexcept override
{ {
_isOriginModeRelative = fRelativeMode; _isOriginModeRelative = fRelativeMode;
return true; return true;
} }
bool EnableDECCOLMSupport(const bool fEnabled) override bool EnableDECCOLMSupport(const bool fEnabled) noexcept override
{ {
_isDECCOLMAllowed = fEnabled; _isDECCOLMAllowed = fEnabled;
return true; return true;
} }
bool UseAlternateScreenBuffer() override bool UseAlternateScreenBuffer() noexcept override
{ {
_isAltBuffer = true; _isAltBuffer = true;
return true; return true;
} }
bool UseMainScreenBuffer() override bool UseMainScreenBuffer() noexcept override
{ {
_isAltBuffer = false; _isAltBuffer = false;
return true; return true;

View file

@ -11,19 +11,6 @@ Author(s):
- Mike Griese (migrie) 12-Jun-2018 - 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 namespace Microsoft::Console::Utils
{ {
bool IsValidHandle(const HANDLE handle) noexcept; bool IsValidHandle(const HANDLE handle) noexcept;