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