Refactor VT control sequence identification (#7304)
This PR changes the way VT control sequences are identified and dispatched, to be more efficient and easier to extend. Instead of parsing the intermediate characters into a vector, and then having to identify a sequence using both that vector and the final char, we now use just a single `uint64_t` value as the identifier. The way the identifier is constructed is by taking the private parameter prefix, each of the intermediate characters, and then the final character, and shifting them into a 64-bit integer one byte at a time, in reverse order. For example, the `DECTLTC` control has a private parameter prefix of `?`, one intermediate of `'`, and a final character of `s`. The ASCII values of those characters are `0x3F`, `0x27`, and `0x73` respectively, and reversing them gets you 0x73273F, so that would then be the identifier for the control. The reason for storing them in reverse order, is because sometimes we need to look at the first intermediate to determine the operation, and treat the rest of the sequence as a kind of sub-identifier (the character set designation sequences are one example of this). When in reverse order, this can easily be achieved by masking off the low byte to get the first intermediate, and then shifting the value right by 8 bits to get a new identifier with the rest of the sequence. With 64 bits we have enough space for a private prefix, six intermediates, and the final char, which is way more than we should ever need (the _DEC STD 070_ specification recommends supporting at least three intermediates, but in practice we're unlikely to see more than two). With this new way of identifying controls, it should now be possible for every action code to be unique (for the most part). So I've also used this PR to clean up the action codes a bit, splitting the codes for the escape sequences from the control sequences, and sorting them into alphabetical order (which also does a reasonable job of clustering associated controls). ## Validation Steps Performed I think the existing unit tests should be good enough to confirm that all sequences are still being dispatched correctly. However, I've also manually tested a number of sequences to make sure they were still working as expected, in particular those that used intermediates, since they were the most affected by the dispatch code refactoring. Since these changes also affected the input state machine, I've done some manual testing of the conpty keyboard handling (both with and without the new Win32 input mode enabled) to make sure the keyboard VT sequences were processed correctly. I've also manually tested the various VT mouse modes in Vttest to confirm that they were still working correctly too. Closes #7276
This commit is contained in:
parent
5d082ffe67
commit
7fcff4d33a
|
@ -548,6 +548,7 @@ DECSCUSR
|
|||
DECSED
|
||||
DECSEL
|
||||
DECSET
|
||||
DECSLPP
|
||||
DECSLRM
|
||||
DECSMBV
|
||||
DECSMKR
|
||||
|
@ -2579,6 +2580,7 @@ vstudio
|
|||
vswhere
|
||||
vtapp
|
||||
VTE
|
||||
VTID
|
||||
vtio
|
||||
vtmode
|
||||
vtpipeterm
|
||||
|
|
|
@ -3,6 +3,94 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
namespace Microsoft::Console::VirtualTerminal
|
||||
{
|
||||
class VTID
|
||||
{
|
||||
public:
|
||||
template<size_t Length>
|
||||
constexpr VTID(const char (&s)[Length]) :
|
||||
_value{ _FromString(s) }
|
||||
{
|
||||
}
|
||||
|
||||
constexpr VTID(const uint64_t value) :
|
||||
_value{ value }
|
||||
{
|
||||
}
|
||||
|
||||
constexpr operator uint64_t() const
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
constexpr char operator[](const size_t offset) const
|
||||
{
|
||||
return SubSequence(offset)._value & 0xFF;
|
||||
}
|
||||
|
||||
constexpr VTID SubSequence(const size_t offset) const
|
||||
{
|
||||
return _value >> (CHAR_BIT * offset);
|
||||
}
|
||||
|
||||
private:
|
||||
template<size_t Length>
|
||||
static constexpr uint64_t _FromString(const char (&s)[Length])
|
||||
{
|
||||
static_assert(Length - 1 <= sizeof(_value));
|
||||
uint64_t value = 0;
|
||||
for (auto i = Length - 1; i-- > 0;)
|
||||
{
|
||||
value = (value << CHAR_BIT) + gsl::at(s, i);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
uint64_t _value;
|
||||
};
|
||||
|
||||
class VTIDBuilder
|
||||
{
|
||||
public:
|
||||
void Clear() noexcept
|
||||
{
|
||||
_idAccumulator = 0;
|
||||
_idShift = 0;
|
||||
}
|
||||
|
||||
void AddIntermediate(const wchar_t intermediateChar) noexcept
|
||||
{
|
||||
if (_idShift + CHAR_BIT >= sizeof(_idAccumulator) * CHAR_BIT)
|
||||
{
|
||||
// If there is not enough space in the accumulator to add
|
||||
// the intermediate and still have room left for the final,
|
||||
// then we reset the accumulator to zero. This will result
|
||||
// in an id with all zero intermediates, which shouldn't
|
||||
// match anything.
|
||||
_idAccumulator = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise we shift the intermediate so as to add it to the
|
||||
// accumulator in the next available space, and then increment
|
||||
// the shift by 8 bits in preparation for the next character.
|
||||
_idAccumulator += (static_cast<uint64_t>(intermediateChar) << _idShift);
|
||||
_idShift += CHAR_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
VTID Finalize(const wchar_t finalChar) noexcept
|
||||
{
|
||||
return _idAccumulator + (static_cast<uint64_t>(finalChar) << _idShift);
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t _idAccumulator = 0;
|
||||
size_t _idShift = 0;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Microsoft::Console::VirtualTerminal::DispatchTypes
|
||||
{
|
||||
enum class EraseType : unsigned int
|
||||
|
@ -101,16 +189,16 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes
|
|||
W32IM_Win32InputMode = 9001
|
||||
};
|
||||
|
||||
namespace CharacterSets
|
||||
enum CharacterSets : uint64_t
|
||||
{
|
||||
constexpr auto DecSpecialGraphics = std::make_pair(L'0', L'\0');
|
||||
constexpr auto ASCII = std::make_pair(L'B', L'\0');
|
||||
}
|
||||
DecSpecialGraphics = VTID("0"),
|
||||
ASCII = VTID("B")
|
||||
};
|
||||
|
||||
enum CodingSystem : wchar_t
|
||||
enum CodingSystem : uint64_t
|
||||
{
|
||||
ISO2022 = L'@',
|
||||
UTF8 = L'G'
|
||||
ISO2022 = VTID("@"),
|
||||
UTF8 = VTID("G")
|
||||
};
|
||||
|
||||
enum TabClearType : unsigned short
|
||||
|
|
|
@ -98,9 +98,9 @@ public:
|
|||
virtual bool TertiaryDeviceAttributes() = 0; // DA3
|
||||
virtual bool Vt52DeviceAttributes() = 0; // VT52 Identify
|
||||
|
||||
virtual bool DesignateCodingSystem(const wchar_t codingSystem) = 0; // DOCS
|
||||
virtual bool Designate94Charset(const size_t gsetNumber, const std::pair<wchar_t, wchar_t> charset) = 0; // SCS
|
||||
virtual bool Designate96Charset(const size_t gsetNumber, const std::pair<wchar_t, wchar_t> charset) = 0; // SCS
|
||||
virtual bool DesignateCodingSystem(const VTID codingSystem) = 0; // DOCS
|
||||
virtual bool Designate94Charset(const size_t gsetNumber, const VTID charset) = 0; // SCS
|
||||
virtual bool Designate96Charset(const size_t gsetNumber, const VTID charset) = 0; // SCS
|
||||
virtual bool LockingShift(const size_t gsetNumber) = 0; // LS0, LS1, LS2, LS3
|
||||
virtual bool LockingShiftRight(const size_t gsetNumber) = 0; // LS1R, LS2R, LS3R
|
||||
virtual bool SingleShift(const size_t gsetNumber) = 0; // SS2, SS3
|
||||
|
|
|
@ -1670,7 +1670,7 @@ void AdaptDispatch::_InitTabStopsForWidth(const size_t width)
|
|||
// - codingSystem - The coding system that will be selected.
|
||||
// Return value:
|
||||
// True if handled successfully. False otherwise.
|
||||
bool AdaptDispatch::DesignateCodingSystem(const wchar_t codingSystem)
|
||||
bool AdaptDispatch::DesignateCodingSystem(const VTID codingSystem)
|
||||
{
|
||||
// If we haven't previously saved the initial code page, do so now.
|
||||
// This will be used to restore the code page in response to a reset.
|
||||
|
@ -1712,10 +1712,10 @@ bool AdaptDispatch::DesignateCodingSystem(const wchar_t codingSystem)
|
|||
// If the specified charset is unsupported, we do nothing (remain on the current one)
|
||||
//Arguments:
|
||||
// - gsetNumber - The G-set into which the charset will be selected.
|
||||
// - charset - The characters indicating the charset that will be used.
|
||||
// - charset - The identifier indicating the charset that will be used.
|
||||
// Return value:
|
||||
// True if handled successfully. False otherwise.
|
||||
bool AdaptDispatch::Designate94Charset(const size_t gsetNumber, const std::pair<wchar_t, wchar_t> charset)
|
||||
bool AdaptDispatch::Designate94Charset(const size_t gsetNumber, const VTID charset)
|
||||
{
|
||||
return _termOutput.Designate94Charset(gsetNumber, charset);
|
||||
}
|
||||
|
@ -1727,10 +1727,10 @@ bool AdaptDispatch::Designate94Charset(const size_t gsetNumber, const std::pair<
|
|||
// If the specified charset is unsupported, we do nothing (remain on the current one)
|
||||
//Arguments:
|
||||
// - gsetNumber - The G-set into which the charset will be selected.
|
||||
// - charset - The characters indicating the charset that will be used.
|
||||
// - charset - The identifier indicating the charset that will be used.
|
||||
// Return value:
|
||||
// True if handled successfully. False otherwise.
|
||||
bool AdaptDispatch::Designate96Charset(const size_t gsetNumber, const std::pair<wchar_t, wchar_t> charset)
|
||||
bool AdaptDispatch::Designate96Charset(const size_t gsetNumber, const VTID charset)
|
||||
{
|
||||
return _termOutput.Designate96Charset(gsetNumber, charset);
|
||||
}
|
||||
|
|
|
@ -89,9 +89,9 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
bool ForwardTab(const size_t numTabs) override; // CHT, HT
|
||||
bool BackwardsTab(const size_t numTabs) override; // CBT
|
||||
bool TabClear(const size_t clearType) override; // TBC
|
||||
bool DesignateCodingSystem(const wchar_t codingSystem) override; // DOCS
|
||||
bool Designate94Charset(const size_t gsetNumber, const std::pair<wchar_t, wchar_t> charset) override; // SCS
|
||||
bool Designate96Charset(const size_t gsetNumber, const std::pair<wchar_t, wchar_t> charset) override; // SCS
|
||||
bool DesignateCodingSystem(const VTID codingSystem) override; // DOCS
|
||||
bool Designate94Charset(const size_t gsetNumber, const VTID charset) override; // SCS
|
||||
bool Designate96Charset(const size_t gsetNumber, const VTID charset) override; // SCS
|
||||
bool LockingShift(const size_t gsetNumber) override; // LS0, LS1, LS2, LS3
|
||||
bool LockingShiftRight(const size_t gsetNumber) override; // LS1R, LS2R, LS3R
|
||||
bool SingleShift(const size_t gsetNumber) override; // SS2, SS3
|
||||
|
|
|
@ -92,9 +92,9 @@ public:
|
|||
bool TertiaryDeviceAttributes() noexcept override { return false; } // DA3
|
||||
bool Vt52DeviceAttributes() noexcept override { return false; } // VT52 Identify
|
||||
|
||||
bool DesignateCodingSystem(const wchar_t /*codingSystem*/) noexcept override { return false; } // DOCS
|
||||
bool Designate94Charset(const size_t /*gsetNumber*/, const std::pair<wchar_t, wchar_t> /*charset*/) noexcept override { return false; } // SCS
|
||||
bool Designate96Charset(const size_t /*gsetNumber*/, const std::pair<wchar_t, wchar_t> /*charset*/) noexcept override { return false; } // SCS
|
||||
bool DesignateCodingSystem(const VTID /*codingSystem*/) noexcept override { return false; } // DOCS
|
||||
bool Designate94Charset(const size_t /*gsetNumber*/, const VTID /*charset*/) noexcept override { return false; } // SCS
|
||||
bool Designate96Charset(const size_t /*gsetNumber*/, const VTID /*charset*/) noexcept override { return false; } // SCS
|
||||
bool LockingShift(const size_t /*gsetNumber*/) noexcept override { return false; } // LS0, LS1, LS2, LS3
|
||||
bool LockingShiftRight(const size_t /*gsetNumber*/) noexcept override { return false; } // LS1R, LS2R, LS3R
|
||||
bool SingleShift(const size_t /*gsetNumber*/) noexcept override { return false; } // SS2, SS3
|
||||
|
|
|
@ -17,107 +17,89 @@ TerminalOutput::TerminalOutput() noexcept
|
|||
_gsetTranslationTables.at(3) = Latin1;
|
||||
}
|
||||
|
||||
bool TerminalOutput::Designate94Charset(size_t gsetNumber, const std::pair<wchar_t, wchar_t> charset)
|
||||
bool TerminalOutput::Designate94Charset(size_t gsetNumber, const VTID charset)
|
||||
{
|
||||
switch (charset.first)
|
||||
switch (charset)
|
||||
{
|
||||
case L'B': // US ASCII
|
||||
case L'1': // Alternate Character ROM
|
||||
case VTID("B"): // US ASCII
|
||||
case VTID("1"): // Alternate Character ROM
|
||||
return _SetTranslationTable(gsetNumber, Ascii);
|
||||
case L'0': // DEC Special Graphics
|
||||
case L'2': // Alternate Character ROM Special Graphics
|
||||
case VTID("0"): // DEC Special Graphics
|
||||
case VTID("2"): // Alternate Character ROM Special Graphics
|
||||
return _SetTranslationTable(gsetNumber, DecSpecialGraphics);
|
||||
case L'<': // DEC Supplemental
|
||||
case VTID("<"): // DEC Supplemental
|
||||
return _SetTranslationTable(gsetNumber, DecSupplemental);
|
||||
case L'A': // British NRCS
|
||||
case VTID("A"): // British NRCS
|
||||
return _SetTranslationTable(gsetNumber, BritishNrcs);
|
||||
case L'4': // Dutch NRCS
|
||||
case VTID("4"): // Dutch NRCS
|
||||
return _SetTranslationTable(gsetNumber, DutchNrcs);
|
||||
case L'5': // Finnish NRCS
|
||||
case L'C': // (fallback)
|
||||
case VTID("5"): // Finnish NRCS
|
||||
case VTID("C"): // (fallback)
|
||||
return _SetTranslationTable(gsetNumber, FinnishNrcs);
|
||||
case L'R': // French NRCS
|
||||
case VTID("R"): // French NRCS
|
||||
return _SetTranslationTable(gsetNumber, FrenchNrcs);
|
||||
case L'f': // French NRCS (ISO update)
|
||||
case VTID("f"): // French NRCS (ISO update)
|
||||
return _SetTranslationTable(gsetNumber, FrenchNrcsIso);
|
||||
case L'9': // French Canadian NRCS
|
||||
case L'Q': // (fallback)
|
||||
case VTID("9"): // French Canadian NRCS
|
||||
case VTID("Q"): // (fallback)
|
||||
return _SetTranslationTable(gsetNumber, FrenchCanadianNrcs);
|
||||
case L'K': // German NRCS
|
||||
case VTID("K"): // German NRCS
|
||||
return _SetTranslationTable(gsetNumber, GermanNrcs);
|
||||
case L'Y': // Italian NRCS
|
||||
case VTID("Y"): // Italian NRCS
|
||||
return _SetTranslationTable(gsetNumber, ItalianNrcs);
|
||||
case L'6': // Norwegian/Danish NRCS
|
||||
case L'E': // (fallback)
|
||||
case VTID("6"): // Norwegian/Danish NRCS
|
||||
case VTID("E"): // (fallback)
|
||||
return _SetTranslationTable(gsetNumber, NorwegianDanishNrcs);
|
||||
case L'`': // Norwegian/Danish NRCS (ISO standard)
|
||||
case VTID("`"): // Norwegian/Danish NRCS (ISO standard)
|
||||
return _SetTranslationTable(gsetNumber, NorwegianDanishNrcsIso);
|
||||
case L'Z': // Spanish NRCS
|
||||
case VTID("Z"): // Spanish NRCS
|
||||
return _SetTranslationTable(gsetNumber, SpanishNrcs);
|
||||
case L'7': // Swedish NRCS
|
||||
case L'H': // (fallback)
|
||||
case VTID("7"): // Swedish NRCS
|
||||
case VTID("H"): // (fallback)
|
||||
return _SetTranslationTable(gsetNumber, SwedishNrcs);
|
||||
case L'=': // Swiss NRCS
|
||||
case VTID("="): // Swiss NRCS
|
||||
return _SetTranslationTable(gsetNumber, SwissNrcs);
|
||||
case L'&':
|
||||
switch (charset.second)
|
||||
{
|
||||
case L'4': // DEC Cyrillic
|
||||
return _SetTranslationTable(gsetNumber, DecCyrillic);
|
||||
case L'5': // Russian NRCS
|
||||
return _SetTranslationTable(gsetNumber, RussianNrcs);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case L'"':
|
||||
switch (charset.second)
|
||||
{
|
||||
case L'?': // DEC Greek
|
||||
return _SetTranslationTable(gsetNumber, DecGreek);
|
||||
case L'>': // Greek NRCS
|
||||
return _SetTranslationTable(gsetNumber, GreekNrcs);
|
||||
case L'4': // DEC Hebrew
|
||||
return _SetTranslationTable(gsetNumber, DecHebrew);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case L'%':
|
||||
switch (charset.second)
|
||||
{
|
||||
case L'=': // Hebrew NRCS
|
||||
return _SetTranslationTable(gsetNumber, HebrewNrcs);
|
||||
case L'0': // DEC Turkish
|
||||
return _SetTranslationTable(gsetNumber, DecTurkish);
|
||||
case L'2': // Turkish NRCS
|
||||
return _SetTranslationTable(gsetNumber, TurkishNrcs);
|
||||
case L'5': // DEC Supplemental
|
||||
return _SetTranslationTable(gsetNumber, DecSupplemental);
|
||||
case L'6': // Portuguese NRCS
|
||||
return _SetTranslationTable(gsetNumber, PortugueseNrcs);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case VTID("&4"): // DEC Cyrillic
|
||||
return _SetTranslationTable(gsetNumber, DecCyrillic);
|
||||
case VTID("&5"): // Russian NRCS
|
||||
return _SetTranslationTable(gsetNumber, RussianNrcs);
|
||||
case VTID("\"?"): // DEC Greek
|
||||
return _SetTranslationTable(gsetNumber, DecGreek);
|
||||
case VTID("\">"): // Greek NRCS
|
||||
return _SetTranslationTable(gsetNumber, GreekNrcs);
|
||||
case VTID("\"4"): // DEC Hebrew
|
||||
return _SetTranslationTable(gsetNumber, DecHebrew);
|
||||
case VTID("%="): // Hebrew NRCS
|
||||
return _SetTranslationTable(gsetNumber, HebrewNrcs);
|
||||
case VTID("%0"): // DEC Turkish
|
||||
return _SetTranslationTable(gsetNumber, DecTurkish);
|
||||
case VTID("%2"): // Turkish NRCS
|
||||
return _SetTranslationTable(gsetNumber, TurkishNrcs);
|
||||
case VTID("%5"): // DEC Supplemental
|
||||
return _SetTranslationTable(gsetNumber, DecSupplemental);
|
||||
case VTID("%6"): // Portuguese NRCS
|
||||
return _SetTranslationTable(gsetNumber, PortugueseNrcs);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TerminalOutput::Designate96Charset(size_t gsetNumber, const std::pair<wchar_t, wchar_t> charset)
|
||||
bool TerminalOutput::Designate96Charset(size_t gsetNumber, const VTID charset)
|
||||
{
|
||||
switch (charset.first)
|
||||
switch (charset)
|
||||
{
|
||||
case L'A': // ISO Latin-1 Supplemental
|
||||
case L'<': // (UPSS when assigned to Latin-1)
|
||||
case VTID("A"): // ISO Latin-1 Supplemental
|
||||
case VTID("<"): // (UPSS when assigned to Latin-1)
|
||||
return _SetTranslationTable(gsetNumber, Latin1);
|
||||
case L'B': // ISO Latin-2 Supplemental
|
||||
case VTID("B"): // ISO Latin-2 Supplemental
|
||||
return _SetTranslationTable(gsetNumber, Latin2);
|
||||
case L'L': // ISO Latin-Cyrillic Supplemental
|
||||
case VTID("L"): // ISO Latin-Cyrillic Supplemental
|
||||
return _SetTranslationTable(gsetNumber, LatinCyrillic);
|
||||
case L'F': // ISO Latin-Greek Supplemental
|
||||
case VTID("F"): // ISO Latin-Greek Supplemental
|
||||
return _SetTranslationTable(gsetNumber, LatinGreek);
|
||||
case L'H': // ISO Latin-Hebrew Supplemental
|
||||
case VTID("H"): // ISO Latin-Hebrew Supplemental
|
||||
return _SetTranslationTable(gsetNumber, LatinHebrew);
|
||||
case L'M': // ISO Latin-5 Supplemental
|
||||
case VTID("M"): // ISO Latin-5 Supplemental
|
||||
return _SetTranslationTable(gsetNumber, Latin5);
|
||||
default:
|
||||
return false;
|
||||
|
|
|
@ -26,8 +26,8 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
TerminalOutput() noexcept;
|
||||
|
||||
wchar_t TranslateKey(const wchar_t wch) const noexcept;
|
||||
bool Designate94Charset(const size_t gsetNumber, const std::pair<wchar_t, wchar_t> charset);
|
||||
bool Designate96Charset(const size_t gsetNumber, const std::pair<wchar_t, wchar_t> charset);
|
||||
bool Designate94Charset(const size_t gsetNumber, const VTID charset);
|
||||
bool Designate96Charset(const size_t gsetNumber, const VTID charset);
|
||||
bool LockingShift(const size_t gsetNumber);
|
||||
bool LockingShiftRight(const size_t gsetNumber);
|
||||
bool SingleShift(const size_t gsetNumber);
|
||||
|
|
|
@ -12,6 +12,9 @@ Abstract:
|
|||
the existing VT parsing.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../adapter/DispatchTypes.hpp"
|
||||
|
||||
namespace Microsoft::Console::VirtualTerminal
|
||||
{
|
||||
class IStateMachineEngine
|
||||
|
@ -30,14 +33,9 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
|
||||
virtual bool ActionPassThroughString(const std::wstring_view string) = 0;
|
||||
|
||||
virtual bool ActionEscDispatch(const wchar_t wch,
|
||||
const gsl::span<const wchar_t> intermediates) = 0;
|
||||
virtual bool ActionVt52EscDispatch(const wchar_t wch,
|
||||
const gsl::span<const wchar_t> intermediates,
|
||||
const gsl::span<const size_t> parameters) = 0;
|
||||
virtual bool ActionCsiDispatch(const wchar_t wch,
|
||||
const gsl::span<const wchar_t> intermediates,
|
||||
const gsl::span<const size_t> parameters) = 0;
|
||||
virtual bool ActionEscDispatch(const VTID id) = 0;
|
||||
virtual bool ActionVt52EscDispatch(const VTID id, const gsl::span<const size_t> parameters) = 0;
|
||||
virtual bool ActionCsiDispatch(const VTID id, const gsl::span<const size_t> parameters) = 0;
|
||||
|
||||
virtual bool ActionClear() = 0;
|
||||
|
||||
|
|
|
@ -34,9 +34,9 @@ static constexpr std::array<CsiToVkey, 10> s_csiMap = {
|
|||
CsiToVkey{ CsiActionCodes::CSI_F4, VK_F4 }
|
||||
};
|
||||
|
||||
static bool operator==(const CsiToVkey& pair, const CsiActionCodes code) noexcept
|
||||
static bool operator==(const CsiToVkey& pair, const VTID id) noexcept
|
||||
{
|
||||
return pair.action == code;
|
||||
return pair.action == id;
|
||||
}
|
||||
|
||||
struct GenericToVkey
|
||||
|
@ -298,12 +298,10 @@ bool InputStateMachineEngine::ActionPassThroughString(const std::wstring_view st
|
|||
// a simple escape sequence. These sequences traditionally start with ESC
|
||||
// and a simple letter. No complicated parameters.
|
||||
// Arguments:
|
||||
// - wch - Character to dispatch.
|
||||
// - intermediates - Intermediate characters in the sequence
|
||||
// - id - Identifier of the escape sequence to dispatch.
|
||||
// Return Value:
|
||||
// - true iff we successfully dispatched the sequence.
|
||||
bool InputStateMachineEngine::ActionEscDispatch(const wchar_t wch,
|
||||
const gsl::span<const wchar_t> /*intermediates*/)
|
||||
bool InputStateMachineEngine::ActionEscDispatch(const VTID id)
|
||||
{
|
||||
if (_pDispatch->IsVtInputEnabled() && _pfnFlushToInputQueue)
|
||||
{
|
||||
|
@ -312,6 +310,9 @@ bool InputStateMachineEngine::ActionEscDispatch(const wchar_t wch,
|
|||
|
||||
bool success = false;
|
||||
|
||||
// There are no intermediates, so the id is effectively the final char.
|
||||
const wchar_t wch = gsl::narrow_cast<wchar_t>(id);
|
||||
|
||||
// 0x7f is DEL, which we treat effectively the same as a ctrl character.
|
||||
if (wch == 0x7f)
|
||||
{
|
||||
|
@ -339,14 +340,11 @@ bool InputStateMachineEngine::ActionEscDispatch(const wchar_t wch,
|
|||
// a VT52 escape sequence. These sequences start with ESC and a single letter,
|
||||
// sometimes followed by parameters.
|
||||
// Arguments:
|
||||
// - wch - Character to dispatch.
|
||||
// - intermediates - Intermediate characters in the sequence.
|
||||
// - id - Identifier of the VT52 sequence to dispatch.
|
||||
// - parameters - Set of parameters collected while parsing the sequence.
|
||||
// Return Value:
|
||||
// - true iff we successfully dispatched the sequence.
|
||||
bool InputStateMachineEngine::ActionVt52EscDispatch(const wchar_t /*wch*/,
|
||||
const gsl::span<const wchar_t> /*intermediates*/,
|
||||
const gsl::span<const size_t> /*parameters*/) noexcept
|
||||
bool InputStateMachineEngine::ActionVt52EscDispatch(const VTID /*id*/, const gsl::span<const size_t> /*parameters*/) noexcept
|
||||
{
|
||||
// VT52 escape sequences are not used in the input state machine.
|
||||
return false;
|
||||
|
@ -357,17 +355,12 @@ bool InputStateMachineEngine::ActionVt52EscDispatch(const wchar_t /*wch*/,
|
|||
// a control sequence. These sequences perform various API-type commands
|
||||
// that can include many parameters.
|
||||
// Arguments:
|
||||
// - wch - Character to dispatch.
|
||||
// - intermediates - Intermediate characters in the sequence
|
||||
// - id - Identifier of the control sequence to dispatch.
|
||||
// - parameters - set of numeric parameters collected while parsing the sequence.
|
||||
// Return Value:
|
||||
// - true iff we successfully dispatched the sequence.
|
||||
bool InputStateMachineEngine::ActionCsiDispatch(const wchar_t wch,
|
||||
const gsl::span<const wchar_t> intermediates,
|
||||
const gsl::span<const size_t> parameters)
|
||||
bool InputStateMachineEngine::ActionCsiDispatch(const VTID id, const gsl::span<const size_t> parameters)
|
||||
{
|
||||
const auto actionCode = static_cast<CsiActionCodes>(wch);
|
||||
|
||||
// GH#4999 - If the client was in VT input mode, but we received a
|
||||
// win32-input-mode sequence, then _don't_ passthrough the sequence to the
|
||||
// client. It's impossibly unlikely that the client actually wanted
|
||||
|
@ -376,7 +369,7 @@ bool InputStateMachineEngine::ActionCsiDispatch(const wchar_t wch,
|
|||
// client reads it.
|
||||
if (_pDispatch->IsVtInputEnabled() &&
|
||||
_pfnFlushToInputQueue &&
|
||||
actionCode != CsiActionCodes::Win32KeyboardInput)
|
||||
id != CsiActionCodes::Win32KeyboardInput)
|
||||
{
|
||||
return _pfnFlushToInputQueue();
|
||||
}
|
||||
|
@ -392,32 +385,22 @@ bool InputStateMachineEngine::ActionCsiDispatch(const wchar_t wch,
|
|||
const auto remainingArgs = parameters.size() > 1 ? parameters.subspan(1) : gsl::span<const size_t>{};
|
||||
|
||||
bool success = false;
|
||||
// Handle intermediate characters, if any
|
||||
if (!intermediates.empty())
|
||||
switch (id)
|
||||
{
|
||||
switch (static_cast<CsiIntermediateCodes>(til::at(intermediates, 0)))
|
||||
{
|
||||
case CsiIntermediateCodes::MOUSE_SGR:
|
||||
{
|
||||
DWORD buttonState = 0;
|
||||
DWORD eventFlags = 0;
|
||||
modifierState = _GetSGRMouseModifierState(parameters);
|
||||
success = _GetSGRXYPosition(parameters, row, col);
|
||||
case CsiActionCodes::MouseDown:
|
||||
case CsiActionCodes::MouseUp:
|
||||
{
|
||||
DWORD buttonState = 0;
|
||||
DWORD eventFlags = 0;
|
||||
modifierState = _GetSGRMouseModifierState(parameters);
|
||||
success = _GetSGRXYPosition(parameters, row, col);
|
||||
|
||||
// we need _UpdateSGRMouseButtonState() on the left side here because we _always_ should be updating our state
|
||||
// even if we failed to parse a portion of this sequence.
|
||||
success = _UpdateSGRMouseButtonState(wch, parameters, buttonState, eventFlags) && success;
|
||||
success = success && _WriteMouseEvent(col, row, buttonState, modifierState, eventFlags);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
// we need _UpdateSGRMouseButtonState() on the left side here because we _always_ should be updating our state
|
||||
// even if we failed to parse a portion of this sequence.
|
||||
success = _UpdateSGRMouseButtonState(id, parameters, buttonState, eventFlags) && success;
|
||||
success = success && _WriteMouseEvent(col, row, buttonState, modifierState, eventFlags);
|
||||
return success;
|
||||
}
|
||||
switch (actionCode)
|
||||
{
|
||||
case CsiActionCodes::Generic:
|
||||
modifierState = _GetGenericKeysModifierState(parameters);
|
||||
success = _GetGenericVkey(parameters, vkey);
|
||||
|
@ -443,8 +426,8 @@ bool InputStateMachineEngine::ActionCsiDispatch(const wchar_t wch,
|
|||
case CsiActionCodes::CSI_F1:
|
||||
case CsiActionCodes::CSI_F2:
|
||||
case CsiActionCodes::CSI_F4:
|
||||
success = _GetCursorKeysVkey(wch, vkey);
|
||||
modifierState = _GetCursorKeysModifierState(parameters, static_cast<CsiActionCodes>(wch));
|
||||
success = _GetCursorKeysVkey(id, vkey);
|
||||
modifierState = _GetCursorKeysModifierState(parameters, id);
|
||||
break;
|
||||
case CsiActionCodes::CursorBackTab:
|
||||
modifierState = SHIFT_PRESSED;
|
||||
|
@ -464,7 +447,7 @@ bool InputStateMachineEngine::ActionCsiDispatch(const wchar_t wch,
|
|||
|
||||
if (success)
|
||||
{
|
||||
switch (static_cast<CsiActionCodes>(wch))
|
||||
switch (id)
|
||||
{
|
||||
// case CsiActionCodes::DSR_DeviceStatusReportResponse:
|
||||
case CsiActionCodes::CSI_F3:
|
||||
|
@ -799,10 +782,10 @@ bool InputStateMachineEngine::_WriteMouseEvent(const size_t column, const size_t
|
|||
// sequence. This is for Arrow keys, Home, End, etc.
|
||||
// Arguments:
|
||||
// - parameters - the set of parameters to get the modifier state from.
|
||||
// - actionCode - the actionCode for the sequence we're operating on.
|
||||
// - id - the identifier for the sequence we're operating on.
|
||||
// Return Value:
|
||||
// - the INPUT_RECORD compatible modifier state.
|
||||
DWORD InputStateMachineEngine::_GetCursorKeysModifierState(const gsl::span<const size_t> parameters, const CsiActionCodes actionCode) noexcept
|
||||
DWORD InputStateMachineEngine::_GetCursorKeysModifierState(const gsl::span<const size_t> parameters, const VTID id) noexcept
|
||||
{
|
||||
DWORD modifiers = 0;
|
||||
if (_IsModified(parameters.size()) && parameters.size() >= 2)
|
||||
|
@ -816,7 +799,7 @@ DWORD InputStateMachineEngine::_GetCursorKeysModifierState(const gsl::span<const
|
|||
// of the keypad; and the divide (/) and ENTER keys in the keypad.
|
||||
// This snippet detects the direction keys + HOME + END
|
||||
// actionCode should be one of the above, so just make sure it's not a CSI_F# code
|
||||
if (actionCode < CsiActionCodes::CSI_F1 || actionCode > CsiActionCodes::CSI_F4)
|
||||
if (id < CsiActionCodes::CSI_F1 || id > CsiActionCodes::CSI_F4)
|
||||
{
|
||||
WI_SetFlag(modifiers, ENHANCED_KEY);
|
||||
}
|
||||
|
@ -917,13 +900,13 @@ DWORD InputStateMachineEngine::_GetModifier(const size_t modifierParam) noexcept
|
|||
// - Here, we refer to and maintain the global state of our mouse.
|
||||
// - Mouse wheel events are added at the end to keep them out of the global state
|
||||
// Arguments:
|
||||
// - wch: the wchar_t representing whether the button was pressed or released
|
||||
// - id: the sequence identifier representing whether the button was pressed or released
|
||||
// - parameters: the wchar_t to get the mapped vkey of. Represents the direction of the button (down vs up)
|
||||
// - buttonState: Receives the button state for the record
|
||||
// - eventFlags: Receives the special mouse events for the record
|
||||
// Return Value:
|
||||
// true iff we were able to synthesize buttonState
|
||||
bool InputStateMachineEngine::_UpdateSGRMouseButtonState(const wchar_t wch,
|
||||
bool InputStateMachineEngine::_UpdateSGRMouseButtonState(const VTID id,
|
||||
const gsl::span<const size_t> parameters,
|
||||
DWORD& buttonState,
|
||||
DWORD& eventFlags) noexcept
|
||||
|
@ -987,7 +970,7 @@ bool InputStateMachineEngine::_UpdateSGRMouseButtonState(const wchar_t wch,
|
|||
|
||||
// Step 2: Decide whether to set or clear that button's bit
|
||||
// NOTE: WI_SetFlag/WI_ClearFlag can't be used here because buttonFlag would have to be a compile-time constant
|
||||
switch (static_cast<CsiActionCodes>(wch))
|
||||
switch (id)
|
||||
{
|
||||
case CsiActionCodes::MouseDown:
|
||||
// set flag
|
||||
|
@ -1049,15 +1032,15 @@ bool InputStateMachineEngine::_GetGenericVkey(const gsl::span<const size_t> para
|
|||
// Method Description:
|
||||
// - Gets the Vkey from the CSI codes table associated with a particular character.
|
||||
// Arguments:
|
||||
// - wch: the wchar_t to get the mapped vkey of.
|
||||
// - id: the sequence identifier to get the mapped vkey of.
|
||||
// - vkey: Receives the vkey
|
||||
// Return Value:
|
||||
// true iff we found the key
|
||||
bool InputStateMachineEngine::_GetCursorKeysVkey(const wchar_t wch, short& vkey) const
|
||||
bool InputStateMachineEngine::_GetCursorKeysVkey(const VTID id, short& vkey) const
|
||||
{
|
||||
vkey = 0;
|
||||
|
||||
const auto mapping = std::find(s_csiMap.cbegin(), s_csiMap.cend(), (CsiActionCodes)wch);
|
||||
const auto mapping = std::find(s_csiMap.cbegin(), s_csiMap.cend(), id);
|
||||
if (mapping != s_csiMap.end())
|
||||
{
|
||||
vkey = mapping->vkey;
|
||||
|
|
|
@ -50,30 +50,25 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
// CAPSLOCK_ON 0x0080
|
||||
// ENHANCED_KEY 0x0100
|
||||
|
||||
enum CsiIntermediateCodes : wchar_t
|
||||
enum CsiActionCodes : uint64_t
|
||||
{
|
||||
MOUSE_SGR = L'<',
|
||||
};
|
||||
|
||||
enum class CsiActionCodes : wchar_t
|
||||
{
|
||||
ArrowUp = L'A',
|
||||
ArrowDown = L'B',
|
||||
ArrowRight = L'C',
|
||||
ArrowLeft = L'D',
|
||||
Home = L'H',
|
||||
End = L'F',
|
||||
MouseDown = L'M',
|
||||
MouseUp = L'm',
|
||||
Generic = L'~', // Used for a whole bunch of possible keys
|
||||
CSI_F1 = L'P',
|
||||
CSI_F2 = L'Q',
|
||||
CSI_F3 = L'R', // Both F3 and DSR are on R.
|
||||
// DSR_DeviceStatusReportResponse = L'R',
|
||||
CSI_F4 = L'S',
|
||||
DTTERM_WindowManipulation = L't',
|
||||
CursorBackTab = L'Z',
|
||||
Win32KeyboardInput = L'_'
|
||||
ArrowUp = VTID("A"),
|
||||
ArrowDown = VTID("B"),
|
||||
ArrowRight = VTID("C"),
|
||||
ArrowLeft = VTID("D"),
|
||||
Home = VTID("H"),
|
||||
End = VTID("F"),
|
||||
MouseDown = VTID("<M"),
|
||||
MouseUp = VTID("<m"),
|
||||
Generic = VTID("~"), // Used for a whole bunch of possible keys
|
||||
CSI_F1 = VTID("P"),
|
||||
CSI_F2 = VTID("Q"),
|
||||
CSI_F3 = VTID("R"), // Both F3 and DSR are on R.
|
||||
// DSR_DeviceStatusReportResponse = VTID("R"),
|
||||
CSI_F4 = VTID("S"),
|
||||
DTTERM_WindowManipulation = VTID("t"),
|
||||
CursorBackTab = VTID("Z"),
|
||||
Win32KeyboardInput = VTID("_")
|
||||
};
|
||||
|
||||
enum CsiMouseButtonCodes : unsigned short
|
||||
|
@ -145,16 +140,11 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
|
||||
bool ActionPassThroughString(const std::wstring_view string) override;
|
||||
|
||||
bool ActionEscDispatch(const wchar_t wch,
|
||||
const gsl::span<const wchar_t> intermediates) override;
|
||||
bool ActionEscDispatch(const VTID id) override;
|
||||
|
||||
bool ActionVt52EscDispatch(const wchar_t wch,
|
||||
const gsl::span<const wchar_t> intermediates,
|
||||
const gsl::span<const size_t> parameters) noexcept override;
|
||||
bool ActionVt52EscDispatch(const VTID id, const gsl::span<const size_t> parameters) noexcept override;
|
||||
|
||||
bool ActionCsiDispatch(const wchar_t wch,
|
||||
const gsl::span<const wchar_t> intermediates,
|
||||
const gsl::span<const size_t> parameters) override;
|
||||
bool ActionCsiDispatch(const VTID id, const gsl::span<const size_t> parameters) override;
|
||||
|
||||
bool ActionClear() noexcept override;
|
||||
|
||||
|
@ -180,7 +170,7 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
bool _lookingForDSR;
|
||||
DWORD _mouseButtonState = 0;
|
||||
|
||||
DWORD _GetCursorKeysModifierState(const gsl::span<const size_t> parameters, const CsiActionCodes actionCode) noexcept;
|
||||
DWORD _GetCursorKeysModifierState(const gsl::span<const size_t> parameters, const VTID id) noexcept;
|
||||
DWORD _GetGenericKeysModifierState(const gsl::span<const size_t> parameters) noexcept;
|
||||
DWORD _GetSGRMouseModifierState(const gsl::span<const size_t> parameters) noexcept;
|
||||
bool _GenerateKeyFromChar(const wchar_t wch, short& vkey, DWORD& modifierState) noexcept;
|
||||
|
@ -188,13 +178,13 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
bool _IsModified(const size_t paramCount) noexcept;
|
||||
DWORD _GetModifier(const size_t parameter) noexcept;
|
||||
|
||||
bool _UpdateSGRMouseButtonState(const wchar_t wch,
|
||||
bool _UpdateSGRMouseButtonState(const VTID id,
|
||||
const gsl::span<const size_t> parameters,
|
||||
DWORD& buttonState,
|
||||
DWORD& eventFlags) noexcept;
|
||||
bool _GetGenericVkey(const gsl::span<const size_t> parameters,
|
||||
short& vkey) const;
|
||||
bool _GetCursorKeysVkey(const wchar_t wch, short& vkey) const;
|
||||
bool _GetCursorKeysVkey(const VTID id, short& vkey) const;
|
||||
bool _GetSs3KeysVkey(const wchar_t wch, short& vkey) const;
|
||||
|
||||
bool _WriteSingleKey(const short vkey, const DWORD modifierState);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -33,16 +33,11 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
|
||||
bool ActionPassThroughString(const std::wstring_view string) override;
|
||||
|
||||
bool ActionEscDispatch(const wchar_t wch,
|
||||
const gsl::span<const wchar_t> intermediates) override;
|
||||
bool ActionEscDispatch(const VTID id) override;
|
||||
|
||||
bool ActionVt52EscDispatch(const wchar_t wch,
|
||||
const gsl::span<const wchar_t> intermediates,
|
||||
const gsl::span<const size_t> parameters) override;
|
||||
bool ActionVt52EscDispatch(const VTID id, const gsl::span<const size_t> parameters) override;
|
||||
|
||||
bool ActionCsiDispatch(const wchar_t wch,
|
||||
const gsl::span<const wchar_t> intermediates,
|
||||
const gsl::span<const size_t> parameters) override;
|
||||
bool ActionCsiDispatch(const VTID id, const gsl::span<const size_t> parameters) override;
|
||||
|
||||
bool ActionClear() noexcept override;
|
||||
|
||||
|
@ -73,94 +68,89 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
wchar_t _lastPrintedChar;
|
||||
std::vector<DispatchTypes::GraphicsOptions> _graphicsOptions;
|
||||
|
||||
bool _IntermediateScsDispatch(const wchar_t wch,
|
||||
const gsl::span<const wchar_t> intermediates);
|
||||
bool _IntermediateQuestionMarkDispatch(const wchar_t wchAction,
|
||||
const gsl::span<const size_t> parameters);
|
||||
bool _IntermediateGreaterThanOrEqualDispatch(const wchar_t wch,
|
||||
const wchar_t intermediate,
|
||||
const gsl::span<const size_t> parameters);
|
||||
bool _IntermediateExclamationDispatch(const wchar_t wch);
|
||||
bool _IntermediateSpaceDispatch(const wchar_t wchAction,
|
||||
const gsl::span<const size_t> parameters);
|
||||
|
||||
enum VTActionCodes : wchar_t
|
||||
enum EscActionCodes : uint64_t
|
||||
{
|
||||
CUU_CursorUp = L'A',
|
||||
CUD_CursorDown = L'B',
|
||||
CUF_CursorForward = L'C',
|
||||
CUB_CursorBackward = L'D',
|
||||
CNL_CursorNextLine = L'E',
|
||||
CPL_CursorPrevLine = L'F',
|
||||
CHA_CursorHorizontalAbsolute = L'G',
|
||||
CUP_CursorPosition = L'H',
|
||||
ED_EraseDisplay = L'J',
|
||||
EL_EraseLine = L'K',
|
||||
SU_ScrollUp = L'S',
|
||||
SD_ScrollDown = L'T',
|
||||
ICH_InsertCharacter = L'@',
|
||||
DCH_DeleteCharacter = L'P',
|
||||
SGR_SetGraphicsRendition = L'm',
|
||||
DECSC_CursorSave = L'7',
|
||||
DECRC_CursorRestore = L'8',
|
||||
DECSET_PrivateModeSet = L'h',
|
||||
DECRST_PrivateModeReset = L'l',
|
||||
ANSISYSSC_CursorSave = L's', // NOTE: Overlaps with DECLRMM/DECSLRM. Fix when/if implemented.
|
||||
ANSISYSRC_CursorRestore = L'u', // NOTE: Overlaps with DECSMBV. Fix when/if implemented.
|
||||
DECKPAM_KeypadApplicationMode = L'=',
|
||||
DECKPNM_KeypadNumericMode = L'>',
|
||||
DSR_DeviceStatusReport = L'n',
|
||||
DA_DeviceAttributes = L'c',
|
||||
DECSCPP_SetColumnsPerPage = L'|',
|
||||
IL_InsertLine = L'L',
|
||||
DL_DeleteLine = L'M', // Yes, this is the same as RI, however, RI is not preceded by a CSI, and DL is.
|
||||
HPA_HorizontalPositionAbsolute = L'`',
|
||||
VPA_VerticalLinePositionAbsolute = L'd',
|
||||
HPR_HorizontalPositionRelative = L'a',
|
||||
VPR_VerticalPositionRelative = L'e',
|
||||
DECSTBM_SetScrollingRegion = L'r',
|
||||
NEL_NextLine = L'E', // Not a CSI, so doesn't overlap with CNL
|
||||
IND_Index = L'D', // Not a CSI, so doesn't overlap with CUB
|
||||
RI_ReverseLineFeed = L'M',
|
||||
HTS_HorizontalTabSet = L'H', // Not a CSI, so doesn't overlap with CUP
|
||||
CHT_CursorForwardTab = L'I',
|
||||
CBT_CursorBackTab = L'Z',
|
||||
TBC_TabClear = L'g',
|
||||
ECH_EraseCharacters = L'X',
|
||||
HVP_HorizontalVerticalPosition = L'f',
|
||||
DECSTR_SoftReset = L'p',
|
||||
RIS_ResetToInitialState = L'c', // DA is prefaced by CSI, RIS by ESC
|
||||
// 'q' is overloaded - no postfix is DECLL, ' ' postfix is DECSCUSR, and '"' is DECSCA
|
||||
DECSCUSR_SetCursorStyle = L'q', // I believe we'll only ever implement DECSCUSR
|
||||
DTTERM_WindowManipulation = L't',
|
||||
REP_RepeatCharacter = L'b',
|
||||
SS2_SingleShift = L'N',
|
||||
SS3_SingleShift = L'O',
|
||||
LS2_LockingShift = L'n',
|
||||
LS3_LockingShift = L'o',
|
||||
LS1R_LockingShift = L'~',
|
||||
LS2R_LockingShift = L'}',
|
||||
LS3R_LockingShift = L'|',
|
||||
DECALN_ScreenAlignmentPattern = L'8'
|
||||
DECSC_CursorSave = VTID("7"),
|
||||
DECRC_CursorRestore = VTID("8"),
|
||||
DECKPAM_KeypadApplicationMode = VTID("="),
|
||||
DECKPNM_KeypadNumericMode = VTID(">"),
|
||||
IND_Index = VTID("D"),
|
||||
NEL_NextLine = VTID("E"),
|
||||
HTS_HorizontalTabSet = VTID("H"),
|
||||
RI_ReverseLineFeed = VTID("M"),
|
||||
SS2_SingleShift = VTID("N"),
|
||||
SS3_SingleShift = VTID("O"),
|
||||
ST_StringTerminator = VTID("\\"),
|
||||
RIS_ResetToInitialState = VTID("c"),
|
||||
LS2_LockingShift = VTID("n"),
|
||||
LS3_LockingShift = VTID("o"),
|
||||
LS1R_LockingShift = VTID("~"),
|
||||
LS2R_LockingShift = VTID("}"),
|
||||
LS3R_LockingShift = VTID("|"),
|
||||
DECALN_ScreenAlignmentPattern = VTID("#8")
|
||||
};
|
||||
|
||||
enum Vt52ActionCodes : wchar_t
|
||||
enum CsiActionCodes : uint64_t
|
||||
{
|
||||
CursorUp = L'A',
|
||||
CursorDown = L'B',
|
||||
CursorRight = L'C',
|
||||
CursorLeft = L'D',
|
||||
EnterGraphicsMode = L'F',
|
||||
ExitGraphicsMode = L'G',
|
||||
CursorToHome = L'H',
|
||||
ReverseLineFeed = L'I',
|
||||
EraseToEndOfScreen = L'J',
|
||||
EraseToEndOfLine = L'K',
|
||||
DirectCursorAddress = L'Y',
|
||||
Identify = L'Z',
|
||||
EnterAlternateKeypadMode = L'=',
|
||||
ExitAlternateKeypadMode = L'>',
|
||||
ExitVt52Mode = L'<'
|
||||
ICH_InsertCharacter = VTID("@"),
|
||||
CUU_CursorUp = VTID("A"),
|
||||
CUD_CursorDown = VTID("B"),
|
||||
CUF_CursorForward = VTID("C"),
|
||||
CUB_CursorBackward = VTID("D"),
|
||||
CNL_CursorNextLine = VTID("E"),
|
||||
CPL_CursorPrevLine = VTID("F"),
|
||||
CHA_CursorHorizontalAbsolute = VTID("G"),
|
||||
CUP_CursorPosition = VTID("H"),
|
||||
CHT_CursorForwardTab = VTID("I"),
|
||||
ED_EraseDisplay = VTID("J"),
|
||||
EL_EraseLine = VTID("K"),
|
||||
IL_InsertLine = VTID("L"),
|
||||
DL_DeleteLine = VTID("M"),
|
||||
DCH_DeleteCharacter = VTID("P"),
|
||||
SU_ScrollUp = VTID("S"),
|
||||
SD_ScrollDown = VTID("T"),
|
||||
ECH_EraseCharacters = VTID("X"),
|
||||
CBT_CursorBackTab = VTID("Z"),
|
||||
HPA_HorizontalPositionAbsolute = VTID("`"),
|
||||
HPR_HorizontalPositionRelative = VTID("a"),
|
||||
REP_RepeatCharacter = VTID("b"),
|
||||
DA_DeviceAttributes = VTID("c"),
|
||||
DA2_SecondaryDeviceAttributes = VTID(">c"),
|
||||
DA3_TertiaryDeviceAttributes = VTID("=c"),
|
||||
VPA_VerticalLinePositionAbsolute = VTID("d"),
|
||||
VPR_VerticalPositionRelative = VTID("e"),
|
||||
HVP_HorizontalVerticalPosition = VTID("f"),
|
||||
TBC_TabClear = VTID("g"),
|
||||
DECSET_PrivateModeSet = VTID("?h"),
|
||||
DECRST_PrivateModeReset = VTID("?l"),
|
||||
SGR_SetGraphicsRendition = VTID("m"),
|
||||
DSR_DeviceStatusReport = VTID("n"),
|
||||
DECSTBM_SetScrollingRegion = VTID("r"),
|
||||
ANSISYSSC_CursorSave = VTID("s"), // NOTE: Overlaps with DECLRMM/DECSLRM. Fix when/if implemented.
|
||||
DTTERM_WindowManipulation = VTID("t"), // NOTE: Overlaps with DECSLPP. Fix when/if implemented.
|
||||
ANSISYSRC_CursorRestore = VTID("u"),
|
||||
DECSCUSR_SetCursorStyle = VTID(" q"),
|
||||
DECSTR_SoftReset = VTID("!p"),
|
||||
DECSCPP_SetColumnsPerPage = VTID("$|")
|
||||
};
|
||||
|
||||
enum Vt52ActionCodes : uint64_t
|
||||
{
|
||||
CursorUp = VTID("A"),
|
||||
CursorDown = VTID("B"),
|
||||
CursorRight = VTID("C"),
|
||||
CursorLeft = VTID("D"),
|
||||
EnterGraphicsMode = VTID("F"),
|
||||
ExitGraphicsMode = VTID("G"),
|
||||
CursorToHome = VTID("H"),
|
||||
ReverseLineFeed = VTID("I"),
|
||||
EraseToEndOfScreen = VTID("J"),
|
||||
EraseToEndOfLine = VTID("K"),
|
||||
DirectCursorAddress = VTID("Y"),
|
||||
Identify = VTID("Z"),
|
||||
EnterAlternateKeypadMode = VTID("="),
|
||||
ExitAlternateKeypadMode = VTID(">"),
|
||||
ExitVt52Mode = VTID("<")
|
||||
};
|
||||
|
||||
enum OscActionCodes : unsigned int
|
||||
|
|
|
@ -15,7 +15,6 @@ StateMachine::StateMachine(std::unique_ptr<IStateMachineEngine> engine) :
|
|||
_state(VTStates::Ground),
|
||||
_trace(Microsoft::Console::VirtualTerminal::ParserTracing()),
|
||||
_isInAnsiMode(true),
|
||||
_intermediates{},
|
||||
_parameters{},
|
||||
_oscString{},
|
||||
_cachedSequence{ std::nullopt },
|
||||
|
@ -422,7 +421,7 @@ void StateMachine::_ActionEscDispatch(const wchar_t wch)
|
|||
{
|
||||
_trace.TraceOnAction(L"EscDispatch");
|
||||
|
||||
const bool success = _engine->ActionEscDispatch(wch, { _intermediates.data(), _intermediates.size() });
|
||||
const bool success = _engine->ActionEscDispatch(_identifier.Finalize(wch));
|
||||
|
||||
// Trace the result.
|
||||
_trace.DispatchSequenceTrace(success);
|
||||
|
@ -445,8 +444,7 @@ void StateMachine::_ActionVt52EscDispatch(const wchar_t wch)
|
|||
{
|
||||
_trace.TraceOnAction(L"Vt52EscDispatch");
|
||||
|
||||
const bool success = _engine->ActionVt52EscDispatch(wch,
|
||||
{ _intermediates.data(), _intermediates.size() },
|
||||
const bool success = _engine->ActionVt52EscDispatch(_identifier.Finalize(wch),
|
||||
{ _parameters.data(), _parameters.size() });
|
||||
|
||||
// Trace the result.
|
||||
|
@ -470,8 +468,7 @@ void StateMachine::_ActionCsiDispatch(const wchar_t wch)
|
|||
{
|
||||
_trace.TraceOnAction(L"CsiDispatch");
|
||||
|
||||
const bool success = _engine->ActionCsiDispatch(wch,
|
||||
{ _intermediates.data(), _intermediates.size() },
|
||||
const bool success = _engine->ActionCsiDispatch(_identifier.Finalize(wch),
|
||||
{ _parameters.data(), _parameters.size() });
|
||||
|
||||
// Trace the result.
|
||||
|
@ -490,12 +487,12 @@ void StateMachine::_ActionCsiDispatch(const wchar_t wch)
|
|||
// - wch - Character to dispatch.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void StateMachine::_ActionCollect(const wchar_t wch)
|
||||
void StateMachine::_ActionCollect(const wchar_t wch) noexcept
|
||||
{
|
||||
_trace.TraceOnAction(L"Collect");
|
||||
|
||||
// store collect data
|
||||
_intermediates.push_back(wch);
|
||||
_identifier.AddIntermediate(wch);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -541,7 +538,7 @@ void StateMachine::_ActionClear()
|
|||
_trace.TraceOnAction(L"Clear");
|
||||
|
||||
// clear all internal stored state.
|
||||
_intermediates.clear();
|
||||
_identifier.Clear();
|
||||
|
||||
_parameters.clear();
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
void _ActionPrint(const wchar_t wch);
|
||||
void _ActionEscDispatch(const wchar_t wch);
|
||||
void _ActionVt52EscDispatch(const wchar_t wch);
|
||||
void _ActionCollect(const wchar_t wch);
|
||||
void _ActionCollect(const wchar_t wch) noexcept;
|
||||
void _ActionParam(const wchar_t wch);
|
||||
void _ActionCsiDispatch(const wchar_t wch);
|
||||
void _ActionOscParam(const wchar_t wch) noexcept;
|
||||
|
@ -142,7 +142,7 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
|
||||
std::wstring_view _run;
|
||||
|
||||
std::vector<wchar_t> _intermediates;
|
||||
VTIDBuilder _identifier;
|
||||
std::vector<size_t> _parameters;
|
||||
|
||||
std::wstring _oscString;
|
||||
|
|
|
@ -222,7 +222,7 @@ class Microsoft::Console::VirtualTerminal::InputEngineTest
|
|||
std::wstring GenerateSgrMouseSequence(const CsiMouseButtonCodes button,
|
||||
const unsigned short modifiers,
|
||||
const COORD position,
|
||||
const CsiActionCodes direction);
|
||||
const VTID direction);
|
||||
|
||||
// SGR_PARAMS serves as test input
|
||||
// - the state of the buttons (constructed via InputStateMachineEngine::CsiActionMouseCodes)
|
||||
|
@ -1089,7 +1089,7 @@ void InputEngineTest::AltBackspaceEnterTest()
|
|||
std::wstring InputEngineTest::GenerateSgrMouseSequence(const CsiMouseButtonCodes button,
|
||||
const unsigned short modifiers,
|
||||
const COORD position,
|
||||
const CsiActionCodes direction)
|
||||
const VTID direction)
|
||||
{
|
||||
// we first need to convert "button" and "modifiers" into an 8 bit sequence
|
||||
unsigned int actionCode = 0;
|
||||
|
@ -1102,7 +1102,11 @@ std::wstring InputEngineTest::GenerateSgrMouseSequence(const CsiMouseButtonCodes
|
|||
// modifiers represents the middle 4 bits
|
||||
actionCode |= modifiers;
|
||||
|
||||
return wil::str_printf_failfast<std::wstring>(L"\x1b[<%d;%d;%d%c", static_cast<int>(actionCode), position.X, position.Y, direction);
|
||||
// mouse sequence identifiers consist of a private parameter prefix and a final character
|
||||
const wchar_t prefixChar = direction[0];
|
||||
const wchar_t finalChar = direction[1];
|
||||
|
||||
return wil::str_printf_failfast<std::wstring>(L"\x1b[%c%d;%d;%d%c", prefixChar, static_cast<int>(actionCode), position.X, position.Y, finalChar);
|
||||
}
|
||||
|
||||
void InputEngineTest::VerifySGRMouseData(const std::vector<std::tuple<SGR_PARAMS, MOUSE_EVENT_PARAMS>> testData)
|
||||
|
|
|
@ -50,12 +50,9 @@ public:
|
|||
return true;
|
||||
};
|
||||
|
||||
bool ActionEscDispatch(const wchar_t /* wch */,
|
||||
const gsl::span<const wchar_t> /* intermediates */) override { return true; };
|
||||
bool ActionEscDispatch(const VTID /* id */) override { return true; };
|
||||
|
||||
bool ActionVt52EscDispatch(const wchar_t /*wch*/,
|
||||
const gsl::span<const wchar_t> /*intermediates*/,
|
||||
const gsl::span<const size_t> /*parameters*/) override { return true; };
|
||||
bool ActionVt52EscDispatch(const VTID /*id*/, const gsl::span<const size_t> /*parameters*/) override { return true; };
|
||||
|
||||
bool ActionClear() override { return true; };
|
||||
|
||||
|
@ -82,9 +79,7 @@ public:
|
|||
bool DispatchIntermediatesFromEscape() const override { return false; };
|
||||
|
||||
// ActionCsiDispatch is the only method that's actually implemented.
|
||||
bool ActionCsiDispatch(const wchar_t /*wch*/,
|
||||
const gsl::span<const wchar_t> /*intermediates*/,
|
||||
const gsl::span<const size_t> parameters) override
|
||||
bool ActionCsiDispatch(const VTID /*id*/, const gsl::span<const size_t> parameters) override
|
||||
{
|
||||
// If flush to terminal is registered for a test, then use it.
|
||||
if (pfnFlushToTerminal)
|
||||
|
|
Loading…
Reference in a new issue