terminal/src/terminal/parser/InputStateMachineEngine.hpp
2021-03-29 16:03:16 +00:00

214 lines
7.2 KiB
C++

/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- InputStateMachineEngine.hpp
Abstract:
- This is the implementation of the client VT input state machine engine.
This generates InputEvents from a stream of VT sequences emitted by a
client "terminal" application.
Author(s):
- Mike Griese (migrie) 18 Aug 2017
--*/
#pragma once
#include "telemetry.hpp"
#include "IStateMachineEngine.hpp"
#include <functional>
#include "../../types/inc/IInputEvent.hpp"
#include "../adapter/IInteractDispatch.hpp"
namespace Microsoft::Console::VirtualTerminal
{
// The values used by VkKeyScan to encode modifiers in the high order byte
constexpr short KEYSCAN_SHIFT = 1;
constexpr short KEYSCAN_CTRL = 2;
constexpr short KEYSCAN_ALT = 4;
// The values with which VT encodes modifier values.
constexpr short VT_SHIFT = 1;
constexpr short VT_ALT = 2;
constexpr short VT_CTRL = 4;
// The assumed values for SGR Mouse Scroll Wheel deltas
constexpr DWORD SCROLL_DELTA_BACKWARD = 0xFF800000;
constexpr DWORD SCROLL_DELTA_FORWARD = 0x00800000;
constexpr size_t WRAPPED_SEQUENCE_MAX_LENGTH = 8;
// For reference, the equivalent INPUT_RECORD values are:
// RIGHT_ALT_PRESSED 0x0001
// LEFT_ALT_PRESSED 0x0002
// RIGHT_CTRL_PRESSED 0x0004
// LEFT_CTRL_PRESSED 0x0008
// SHIFT_PRESSED 0x0010
// NUMLOCK_ON 0x0020
// SCROLLLOCK_ON 0x0040
// CAPSLOCK_ON 0x0080
// ENHANCED_KEY 0x0100
enum CsiActionCodes : uint64_t
{
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
{
Left = 0,
Middle = 1,
Right = 2,
Released = 3,
ScrollForward = 4,
ScrollBack = 5,
};
constexpr unsigned short CsiMouseModifierCode_Drag = 32;
enum CsiMouseModifierCodes : unsigned short
{
Shift = 4,
Meta = 8,
Ctrl = 16,
Drag = 32,
};
// Sequences ending in '~' use these numbers as identifiers.
enum class GenericKeyIdentifiers : size_t
{
GenericHome = 1,
Insert = 2,
Delete = 3,
GenericEnd = 4,
Prior = 5, //PgUp
Next = 6, //PgDn
F5 = 15,
F6 = 17,
F7 = 18,
F8 = 19,
F9 = 20,
F10 = 21,
F11 = 23,
F12 = 24,
};
enum class Ss3ActionCodes : wchar_t
{
ArrowUp = L'A',
ArrowDown = L'B',
ArrowRight = L'C',
ArrowLeft = L'D',
Home = L'H',
End = L'F',
SS3_F1 = L'P',
SS3_F2 = L'Q',
SS3_F3 = L'R',
SS3_F4 = L'S',
};
class InputStateMachineEngine : public IStateMachineEngine
{
public:
InputStateMachineEngine(std::unique_ptr<IInteractDispatch> pDispatch);
InputStateMachineEngine(std::unique_ptr<IInteractDispatch> pDispatch,
const bool lookingForDSR);
bool ActionExecute(const wchar_t wch) override;
bool ActionExecuteFromEscape(const wchar_t wch) override;
bool ActionPrint(const wchar_t wch) override;
bool ActionPrintString(const std::wstring_view string) override;
bool ActionPassThroughString(const std::wstring_view string) override;
bool ActionEscDispatch(const VTID id) override;
bool ActionVt52EscDispatch(const VTID id, const VTParameters parameters) noexcept override;
bool ActionCsiDispatch(const VTID id, const VTParameters parameters) override;
bool ActionClear() noexcept override;
bool ActionIgnore() noexcept override;
bool ActionOscDispatch(const wchar_t wch,
const size_t parameter,
const std::wstring_view string) noexcept override;
bool ActionSs3Dispatch(const wchar_t wch, const VTParameters parameters) override;
bool ParseControlSequenceAfterSs3() const noexcept override;
bool FlushAtEndOfString() const noexcept override;
bool DispatchControlCharsFromEscape() const noexcept override;
bool DispatchIntermediatesFromEscape() const noexcept override;
void SetFlushToInputQueueCallback(std::function<bool()> pfnFlushToInputQueue);
private:
const std::unique_ptr<IInteractDispatch> _pDispatch;
std::function<bool()> _pfnFlushToInputQueue;
bool _lookingForDSR;
DWORD _mouseButtonState = 0;
DWORD _GetCursorKeysModifierState(const VTParameters parameters, const VTID id) noexcept;
DWORD _GetGenericKeysModifierState(const VTParameters parameters) noexcept;
DWORD _GetSGRMouseModifierState(const size_t modifierParam) noexcept;
bool _GenerateKeyFromChar(const wchar_t wch, short& vkey, DWORD& modifierState) noexcept;
DWORD _GetModifier(const size_t parameter) noexcept;
bool _UpdateSGRMouseButtonState(const VTID id,
const size_t sgrEncoding,
DWORD& buttonState,
DWORD& eventFlags) noexcept;
bool _GetGenericVkey(const GenericKeyIdentifiers identifier, 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);
bool _WriteSingleKey(const wchar_t wch, const short vkey, const DWORD modifierState);
bool _WriteMouseEvent(const size_t column, const size_t line, const DWORD buttonState, const DWORD controlKeyState, const DWORD eventFlags);
void _GenerateWrappedSequence(const wchar_t wch,
const short vkey,
const DWORD modifierState,
std::vector<INPUT_RECORD>& input);
void _GetSingleKeypress(const wchar_t wch,
const short vkey,
const DWORD modifierState,
std::vector<INPUT_RECORD>& input);
bool _GetWindowManipulationType(const gsl::span<const size_t> parameters,
unsigned int& function) const noexcept;
KeyEvent _GenerateWin32Key(const VTParameters parameters);
bool _DoControlCharacter(const wchar_t wch, const bool writeAlt);
#ifdef UNIT_TESTING
friend class InputEngineTest;
#endif
};
}