a9c9714295
My basic idea was that `WM_CHAR` is just the better `WM_KEYDOWN`. The latter fails to properly support common dead key sequences like in #3516. As such I added some logic to `Terminal::SendKeyEvent` to make it return false if the pressed key represents a printable character. This causes us to receive a character event with a (hopefully) correctly composed code unit, which then gets sent to `Terminal::SendCharEvent`. `Terminal::SendCharEvent` in turn had to be modified to support potentially pressed modifier keys, since `Terminal::SendKeyEvent` isn't doing that for us anymore. Lastly `TerminalInput` had to be modified heavily to support character events with modifier key states. In order to do so I merged its `HandleKey` and `HandleChar` methods into a single one, that now handles both cases. Since key events will now contain character data and character events key codes the decision logic in `TerminalInput::HandleKey` had to be rewritten. ## PR Checklist * [x] CLA signed * [x] Tests added/passed * [x] I've discussed this with core contributors already. ## Validation Steps Performed * See #3516. * I don't have any keyboard that generates surrogate characters. Due to this I modified `TermControl::_SendPastedTextToConnection` to send the data to `_terminal->SendCharEvent()` instead. I then pasted the test string ""𐐌𐐜𐐬" and ensured that the new `TerminalInput::_SendChar` method still correctly assembles surrogate pairs. Closes #3516 Closes #3554 (obsoleted by this PR) Potentially impacts #391, which sounds like a duplicate of #3516
134 lines
5 KiB
C++
134 lines
5 KiB
C++
/*++
|
|
Copyright (c) Microsoft Corporation
|
|
Licensed under the MIT license.
|
|
|
|
Module Name:
|
|
- terminalInput.hpp
|
|
|
|
Abstract:
|
|
- This serves as an adapter between virtual key input from a user and the virtual terminal sequences that are
|
|
typically emitted by an xterm-compatible console.
|
|
|
|
Author(s):
|
|
- Michael Niksa (MiNiksa) 30-Oct-2015
|
|
--*/
|
|
|
|
#include <functional>
|
|
#include "../../types/inc/IInputEvent.hpp"
|
|
#pragma once
|
|
|
|
namespace Microsoft::Console::VirtualTerminal
|
|
{
|
|
class TerminalInput final
|
|
{
|
|
public:
|
|
TerminalInput(_In_ std::function<void(std::deque<std::unique_ptr<IInputEvent>>&)> pfn);
|
|
|
|
TerminalInput() = delete;
|
|
TerminalInput(const TerminalInput& old) = default;
|
|
TerminalInput(TerminalInput&& moved) = default;
|
|
|
|
TerminalInput& operator=(const TerminalInput& old) = default;
|
|
TerminalInput& operator=(TerminalInput&& moved) = default;
|
|
|
|
~TerminalInput() = default;
|
|
|
|
bool HandleKey(const IInputEvent* const pInEvent);
|
|
void ChangeKeypadMode(const bool applicationMode) noexcept;
|
|
void ChangeCursorKeysMode(const bool applicationMode) noexcept;
|
|
|
|
#pragma region MouseInput
|
|
// These methods are defined in mouseInput.cpp
|
|
bool HandleMouse(const COORD position,
|
|
const unsigned int button,
|
|
const short modifierKeyState,
|
|
const short delta);
|
|
|
|
bool IsTrackingMouseInput() const noexcept;
|
|
#pragma endregion
|
|
|
|
#pragma region MouseInputState Management
|
|
// These methods are defined in mouseInputState.cpp
|
|
void SetUtf8ExtendedMode(const bool enable) noexcept;
|
|
void SetSGRExtendedMode(const bool enable) noexcept;
|
|
|
|
void EnableDefaultTracking(const bool enable) noexcept;
|
|
void EnableButtonEventTracking(const bool enable) noexcept;
|
|
void EnableAnyEventTracking(const bool enable) noexcept;
|
|
|
|
void EnableAlternateScroll(const bool enable) noexcept;
|
|
void UseAlternateScreenBuffer() noexcept;
|
|
void UseMainScreenBuffer() noexcept;
|
|
#pragma endregion
|
|
|
|
private:
|
|
std::function<void(std::deque<std::unique_ptr<IInputEvent>>&)> _pfnWriteEvents;
|
|
|
|
// storage location for the leading surrogate of a utf-16 surrogate pair
|
|
std::optional<wchar_t> _leadingSurrogate;
|
|
|
|
bool _keypadApplicationMode = false;
|
|
bool _cursorApplicationMode = false;
|
|
|
|
void _SendChar(const wchar_t ch);
|
|
void _SendNullInputSequence(const DWORD dwControlKeyState) const;
|
|
void _SendInputSequence(const std::wstring_view sequence) const noexcept;
|
|
void _SendEscapedInputSequence(const wchar_t wch) const;
|
|
|
|
#pragma region MouseInputState Management
|
|
// These methods are defined in mouseInputState.cpp
|
|
enum class ExtendedMode : unsigned int
|
|
{
|
|
None,
|
|
Utf8,
|
|
Sgr,
|
|
Urxvt
|
|
};
|
|
|
|
enum class TrackingMode : unsigned int
|
|
{
|
|
None,
|
|
Default,
|
|
ButtonEvent,
|
|
AnyEvent
|
|
};
|
|
|
|
struct MouseInputState
|
|
{
|
|
ExtendedMode extendedMode{ ExtendedMode::None };
|
|
TrackingMode trackingMode{ TrackingMode::None };
|
|
bool alternateScroll{ false };
|
|
bool inAlternateBuffer{ false };
|
|
COORD lastPos{ -1, -1 };
|
|
unsigned int lastButton{ 0 };
|
|
};
|
|
|
|
MouseInputState _mouseInputState;
|
|
#pragma endregion
|
|
|
|
#pragma region MouseInput
|
|
static std::wstring _GenerateDefaultSequence(const COORD position,
|
|
const unsigned int button,
|
|
const bool isHover,
|
|
const short modifierKeyState,
|
|
const short delta);
|
|
static std::wstring _GenerateUtf8Sequence(const COORD position,
|
|
const unsigned int button,
|
|
const bool isHover,
|
|
const short modifierKeyState,
|
|
const short delta);
|
|
static std::wstring _GenerateSGRSequence(const COORD position,
|
|
const unsigned int button,
|
|
const bool isDown,
|
|
const bool isHover,
|
|
const short modifierKeyState,
|
|
const short delta);
|
|
|
|
bool _ShouldSendAlternateScroll(const unsigned int button, const short delta) const noexcept;
|
|
bool _SendAlternateScroll(const short delta) const noexcept;
|
|
|
|
static unsigned int s_GetPressedButton() noexcept;
|
|
#pragma endregion
|
|
};
|
|
}
|