From dfecb2f3f202aadbe56dbcbf7c753a3709410cd2 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Thu, 5 Mar 2020 17:13:53 -0800 Subject: [PATCH 1/7] Copy MouseInput to TerminalInput --- src/terminal/input/lib/terminalinput.vcxproj | 6 +- src/terminal/input/mouseInput.cpp | 518 +++++++++++++++++++ src/terminal/input/mouseInputState.cpp | 115 ++++ src/terminal/input/terminalInput.cpp | 2 +- src/terminal/input/terminalInput.hpp | 79 ++- 5 files changed, 716 insertions(+), 4 deletions(-) create mode 100644 src/terminal/input/mouseInput.cpp create mode 100644 src/terminal/input/mouseInputState.cpp diff --git a/src/terminal/input/lib/terminalinput.vcxproj b/src/terminal/input/lib/terminalinput.vcxproj index 9f9229cf4db..0dd6aead6ff 100644 --- a/src/terminal/input/lib/terminalinput.vcxproj +++ b/src/terminal/input/lib/terminalinput.vcxproj @@ -6,10 +6,12 @@ adapter TerminalInput TerminalInput - StaticLibrary + StaticLibrary + + Create @@ -26,4 +28,4 @@ - + \ No newline at end of file diff --git a/src/terminal/input/mouseInput.cpp b/src/terminal/input/mouseInput.cpp new file mode 100644 index 00000000000..a2d8a4b3649 --- /dev/null +++ b/src/terminal/input/mouseInput.cpp @@ -0,0 +1,518 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "precomp.h" +#include +#include "terminalInput.hpp" + +using namespace Microsoft::Console::VirtualTerminal; + +static const int s_MaxDefaultCoordinate = 94; + +// 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." +static constexpr short KeyPressed{ gsl::narrow_cast(0x8000) }; + +// Alternate scroll sequences +static constexpr std::wstring_view CursorUpSequence{ L"\x1b[A" }; +static constexpr std::wstring_view CursorDownSequence{ L"\x1b[B" }; + +// 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: +// - button - the message to decode. +// Return value: +// - true iff button is a button message to translate +static constexpr bool _isButtonMsg(const unsigned int button) noexcept +{ + bool isButton = false; + switch (button) + { + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_MBUTTONDBLCLK: + case WM_MOUSEWHEEL: + case WM_MOUSEHWHEEL: + isButton = true; + break; + } + return isButton; +} + +// Routine Description: +// - Determines if the input windows message code describes a hover event +// Parameters: +// - buttonCode - the message to decode. +// Return value: +// - true iff buttonCode is a hover enent to translate +static constexpr bool _isHoverMsg(const unsigned int buttonCode) noexcept +{ + return buttonCode == WM_MOUSEMOVE; +} + +// Routine Description: +// - Determines if the input windows message code describes a button press +// (either down or doubleclick) +// Parameters: +// - button - the message to decode. +// Return value: +// - true iff button is a button down event +static constexpr bool _isButtonDown(const unsigned int button) noexcept +{ + bool isButtonDown = false; + switch (button) + { + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_MBUTTONDBLCLK: + case WM_MOUSEWHEEL: + case WM_MOUSEHWHEEL: + isButtonDown = true; + break; + } + return isButtonDown; +} + +// 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: +// +// Return value: +// - a button corresponding to any pressed mouse buttons, else WM_LBUTTONUP if none are pressed. +unsigned int TerminalInput::s_GetPressedButton() noexcept +{ + unsigned int button = WM_LBUTTONUP; // Will be treated as a release, or no button pressed. + if (WI_IsFlagSet(GetKeyState(VK_LBUTTON), KeyPressed)) + { + button = WM_LBUTTONDOWN; + } + else if (WI_IsFlagSet(GetKeyState(VK_MBUTTON), KeyPressed)) + { + button = WM_MBUTTONDOWN; + } + else if (WI_IsFlagSet(GetKeyState(VK_RBUTTON), KeyPressed)) + { + button = WM_RBUTTONDOWN; + } + return button; +} + +// Routine Description: +// - translates the input windows mouse message into its equivalent X11 encoding. +// X Button Encoding: +// |7|6|5|4|3|2|1|0| +// | |W|H|M|C|S|B|B| +// bits 0 and 1 are used for button: +// 00 - MB1 pressed (left) +// 01 - MB2 pressed (middle) +// 10 - MB3 pressed (right) +// 11 - released (none) +// Next three bits indicate modifier keys: +// 0x04 - shift (This never makes it through, as our emulator is skipped when shift is pressed.) +// 0x08 - ctrl +// 0x10 - meta +// 32 (x20) is added for "hover" events: +// "For example, motion into cell x,y with button 1 down is reported as `CSI M @ CxCy`. +// ( @ = 32 + 0 (button 1) + 32 (motion indicator) ). +// Similarly, motion with button 3 down is reported as `CSI M B CxCy`. +// ( B = 32 + 2 (button 3) + 32 (motion indicator) ). +// 64 (x40) is added for wheel events. +// so wheel up? is 64, and wheel down? is 65. +// +// Parameters: +// - 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. +static constexpr int _windowsButtonToXEncoding(const unsigned int button, + const bool isHover, + const short modifierKeyState, + const short delta) noexcept +{ + int xvalue = 0; + switch (button) + { + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: + xvalue = 0; + break; + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + xvalue = 3; + break; + case WM_RBUTTONDOWN: + case WM_RBUTTONDBLCLK: + xvalue = 2; + break; + case WM_MBUTTONDOWN: + case WM_MBUTTONDBLCLK: + xvalue = 1; + break; + case WM_MOUSEWHEEL: + case WM_MOUSEHWHEEL: + xvalue = delta > 0 ? 0x40 : 0x41; + } + if (isHover) + { + 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 + // 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. + // xvalue += (modifierKeyState & MK_META) ? 0x10 : 0x00; + + return xvalue; +} + +// Routine Description: +// - translates the input windows mouse message into its equivalent SGR encoding. +// This is nearly identical to the X encoding, with an important difference. +// The button is always encoded as 0, 1, 2. +// 3 is reserved for mouse hovers with _no_ buttons pressed. +// See MSFT:19461988 and https://github.com/Microsoft/console/issues/296 +// Parameters: +// - button - the message to decode. +// Return value: +// - the int representing the equivalent X button encoding. +static constexpr int _windowsButtonToSGREncoding(const unsigned int button, + const bool isHover, + const short modifierKeyState, + const short delta) noexcept +{ + int xvalue = 0; + switch (button) + { + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + xvalue = 0; + break; + case WM_RBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONDBLCLK: + xvalue = 2; + break; + case WM_MBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONDBLCLK: + xvalue = 1; + break; + case WM_MOUSEMOVE: + xvalue = 3; + break; + case WM_MOUSEWHEEL: + case WM_MOUSEHWHEEL: + xvalue = delta > 0 ? 0x40 : 0x41; + } + if (isHover) + { + 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 + // 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. + // xvalue += (modifierKeyState & MK_META) ? 0x10 : 0x00; + + 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 character ' '. +// Parameters: +// - sCoordinateValue - the value to encode. +// Return value: +// - the encoded value. +static constexpr short _encodeDefaultCoordinate(const short sCoordinateValue) noexcept +{ + return sCoordinateValue + 32; +} + +// Routine Description: +// - Attempt to handle the given mouse coordinates and windows button as a VT-style mouse event. +// 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: +// - 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 TerminalInput::HandleMouse(const COORD position, + const unsigned int button, + const short modifierKeyState, + const short delta) +{ + bool success = false; + if (_ShouldSendAlternateScroll(button, delta)) + { + success = _SendAlternateScroll(delta); + } + else + { + success = (_mouseInputState.trackingMode != TrackingMode::None); + if (success) + { + // isHover is only true for WM_MOUSEMOVE events + const bool isHover = _isHoverMsg(button); + const bool isButton = _isButtonMsg(button); + + const bool sameCoord = (position.X == _mouseInputState.lastPos.X) && + (position.Y == _mouseInputState.lastPos.Y) && + (_mouseInputState.lastButton == button); + + // If we have a WM_MOUSEMOVE, we need to know if any of the mouse + // buttons are actually pressed. If they are, + // _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 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 = realButton != WM_LBUTTONUP; + + success = (isButton && _mouseInputState.trackingMode != TrackingMode::None) || + (isHover && _mouseInputState.trackingMode == TrackingMode::ButtonEvent && ((!sameCoord) && (physicalButtonPressed))) || + (isHover && _mouseInputState.trackingMode == TrackingMode::AnyEvent && !sameCoord); + + if (success) + { + std::wstring sequence; + switch (_mouseInputState.extendedMode) + { + case ExtendedMode::None: + sequence = _GenerateDefaultSequence(position, + realButton, + isHover, + modifierKeyState, + delta); + break; + case ExtendedMode::Utf8: + 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. + 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: + success = false; + break; + } + + success = !sequence.empty(); + + if (success) + { + _SendInputSequence(sequence); + success = true; + } + if (_mouseInputState.trackingMode == TrackingMode::ButtonEvent || _mouseInputState.trackingMode == TrackingMode::AnyEvent) + { + _mouseInputState.lastPos.X = position.X; + _mouseInputState.lastPos.Y = position.Y; + _mouseInputState.lastButton = button; + } + } + } + } + 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: +// - 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: +// - The generated sequence. Will be empty if we couldn't generate. +std::wstring TerminalInput::_GenerateDefaultSequence(const COORD position, + const unsigned int button, + const bool isHover, + const short modifierKeyState, + const short delta) +{ + // 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 (position.X <= s_MaxDefaultCoordinate && position.Y <= s_MaxDefaultCoordinate) + { + const COORD vtCoords = _winToVTCoord(position); + const short encodedX = _encodeDefaultCoordinate(vtCoords.X); + const short encodedY = _encodeDefaultCoordinate(vtCoords.Y); + + std::wstring format{ L"\x1b[Mbxy" }; + format.at(3) = ' ' + gsl::narrow_cast(_windowsButtonToXEncoding(button, isHover, modifierKeyState, delta)); + format.at(4) = encodedX; + format.at(5) = encodedY; + return format; + } + + 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: +// - 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: +// - The generated sequence. Will be empty if we couldn't generate. +std::wstring TerminalInput::_GenerateUtf8Sequence(const COORD position, + const unsigned int button, + const bool isHover, + const short modifierKeyState, + const short delta) +{ + // 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. + // So, if we want to emit a char > x80 here, great. bash.exe will convert the x80 into xC280 and pass that along, which is great. + // The *nix application was expecting a utf8 stream, and it got one. + // However, a normal windows program asks for utf8 mode, then it gets the utf16 encoded result. This is not what it wanted. + // It was looking for \x1b[M#\xC280y and got \x1b[M#\x0080y + // Now, I'd argue that in requesting utf8 mode, the application should be enlightened enough to not want the utf16 input stream, + // and convert it the same way bash.exe does. + // Though, the point could be made to place the utf8 bytes into the input, and read them that way. + // However, if we did this, bash.exe would translate those bytes thinking they're utf16, and x80->xC280->xC382C280 + // 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 (position.X <= (SHORT_MAX - 33) && position.Y <= (SHORT_MAX - 33)) + { + 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(_windowsButtonToXEncoding(button, isHover, modifierKeyState, delta)); + format.at(4) = encodedX; + format.at(5) = encodedY; + return format; + } + + 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: +// - position - The windows coordinates (top,left = 0,0) of the mouse event +// - button - the message to decode. WM_MOUSEMOVE is used for mouse hovers with no buttons pressed. +// - isDown - true iff a mouse button was pressed. +// - 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. +std::wstring TerminalInput::_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' + const int xbutton = _windowsButtonToSGREncoding(button, isHover, modifierKeyState, delta); + + auto format = wil::str_printf(L"\x1b[<%d;%d;%d%c", xbutton, position.X + 1, position.Y + 1, isDown ? L'M' : L'm'); + + return format; +} + +// Routine Description: +// - Returns true if we should translate the input event (button, sScrollDelta) +// into an alternate scroll event instead of the default scroll event, +// depending on if alternate scroll mode is enabled and we're in the alternate buffer. +// Parameters: +// - 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 TerminalInput::_ShouldSendAlternateScroll(const unsigned int button, const short delta) const noexcept +{ + return _mouseInputState.inAlternateBuffer && + _mouseInputState.alternateScroll && + (button == WM_MOUSEWHEEL || button == WM_MOUSEHWHEEL) && delta != 0; +} + +// Routine Description: +// - Sends a sequence to the input corresponding to cursor up / down depending on the sScrollDelta. +// Parameters: +// - delta: The scroll wheel delta of the input event +// Return value: +// True iff the input sequence was sent successfully. +bool TerminalInput::_SendAlternateScroll(const short delta) const noexcept +{ + if (delta > 0) + { + _SendInputSequence(CursorUpSequence); + } + else + { + _SendInputSequence(CursorDownSequence); + } + return true; +} diff --git a/src/terminal/input/mouseInputState.cpp b/src/terminal/input/mouseInputState.cpp new file mode 100644 index 00000000000..b1c2509de74 --- /dev/null +++ b/src/terminal/input/mouseInputState.cpp @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "precomp.h" +#include +#include "terminalInput.hpp" + +using namespace Microsoft::Console::VirtualTerminal; + +// Routine Description: +// - Either enables or disables UTF-8 extended mode encoding. This *should* cause +// the coordinates of a mouse event to be encoded as a UTF-8 byte stream, however, because windows' input is +// 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: +// - enable - either enable or disable. +// Return value: +// +void TerminalInput::SetUtf8ExtendedMode(const bool enable) noexcept +{ + _mouseInputState.extendedMode = enable ? ExtendedMode::Utf8 : ExtendedMode::None; +} + +// Routine Description: +// - Either enables or disables SGR extended mode encoding. This causes the +// coordinates of a mouse event to be emitted in a human readable format, +// eg, x,y=203,504 -> "^[[ +void TerminalInput::SetSGRExtendedMode(const bool enable) noexcept +{ + _mouseInputState.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: +// - enable - either enable or disable. +// Return value: +// +void TerminalInput::EnableDefaultTracking(const bool enable) noexcept +{ + _mouseInputState.trackingMode = enable ? TrackingMode::Default : TrackingMode::None; + _mouseInputState.lastPos = { -1, -1 }; // Clear out the last saved mouse position & button. + _mouseInputState.lastButton = 0; +} + +// Routine Description: +// - Either enables or disables ButtonEvent mouse handling. Button Event mode +// sends additional sequences when a button is pressed and the mouse changes character cells. +// Leaves the extended mode alone, so if we disable then re-enable mouse mode +// without toggling an extended mode, the mode will persist. +// Parameters: +// - enable - either enable or disable. +// Return value: +// +void TerminalInput::EnableButtonEventTracking(const bool enable) noexcept +{ + _mouseInputState.trackingMode = enable ? TrackingMode::ButtonEvent : TrackingMode::None; + _mouseInputState.lastPos = { -1, -1 }; // Clear out the last saved mouse position & button. + _mouseInputState.lastButton = 0; +} + +// Routine Description: +// - Either enables or disables AnyEvent mouse handling. Any Event mode sends sequences +// for any and every mouse event, regardless if a button is pressed or not. +// Leaves the extended mode alone, so if we disable then re-enable mouse mode +// without toggling an extended mode, the mode will persist. +// Parameters: +// - enable - either enable or disable. +// Return value: +// +void TerminalInput::EnableAnyEventTracking(const bool enable) noexcept +{ + _mouseInputState.trackingMode = enable ? TrackingMode::AnyEvent : TrackingMode::None; + _mouseInputState.lastPos = { -1, -1 }; // Clear out the last saved mouse position & button. + _mouseInputState.lastButton = 0; +} + +// Routine Description: +// - Enables alternate scroll mode. This sends Cursor Up/down sequences when in the alternate buffer +// Parameters: +// - enable - either enable or disable. +// Return value: +// +void TerminalInput::EnableAlternateScroll(const bool enable) noexcept +{ + _mouseInputState.alternateScroll = enable; +} + +// Routine Description: +// - Notify the MouseInput handler that the screen buffer has been swapped to the alternate buffer +// Parameters: +// +// Return value: +// +void TerminalInput::UseAlternateScreenBuffer() noexcept +{ + _mouseInputState.inAlternateBuffer = true; +} + +// Routine Description: +// - Notify the MouseInput handler that the screen buffer has been swapped to the alternate buffer +// Parameters: +// +// Return value: +// +void TerminalInput::UseMainScreenBuffer() noexcept +{ + _mouseInputState.inAlternateBuffer = false; +} diff --git a/src/terminal/input/terminalInput.cpp b/src/terminal/input/terminalInput.cpp index 6a87dc1cb16..9935ae08ca2 100644 --- a/src/terminal/input/terminalInput.cpp +++ b/src/terminal/input/terminalInput.cpp @@ -543,7 +543,7 @@ void TerminalInput::_SendNullInputSequence(const DWORD controlKeyState) const } } -void TerminalInput::_SendInputSequence(const std::wstring_view sequence) const +void TerminalInput::_SendInputSequence(const std::wstring_view sequence) const noexcept { if (!sequence.empty()) { diff --git a/src/terminal/input/terminalInput.hpp b/src/terminal/input/terminalInput.hpp index 7992531e596..b0b5860c128 100644 --- a/src/terminal/input/terminalInput.hpp +++ b/src/terminal/input/terminalInput.hpp @@ -38,6 +38,28 @@ namespace Microsoft::Console::VirtualTerminal 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); +#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>&)> _pfnWriteEvents; @@ -48,7 +70,62 @@ namespace Microsoft::Console::VirtualTerminal bool _cursorApplicationMode = false; void _SendNullInputSequence(const DWORD dwControlKeyState) const; - void _SendInputSequence(const std::wstring_view sequence) 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 }; } From d2016e03a6865daa5501a028fa76f48c3ceca204 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Thu, 5 Mar 2020 17:23:28 -0800 Subject: [PATCH 2/7] Fully remove MouseInput and use TerminalInput --- src/host/server.h | 4 +- src/terminal/adapter/MouseInput.cpp | 661 ------------------ src/terminal/adapter/MouseInput.hpp | 100 --- src/terminal/adapter/lib/adapter.vcxproj | 2 - .../adapter/lib/adapter.vcxproj.filters | 6 - .../adapter/ut_adapter/MouseInputTest.cpp | 10 +- 6 files changed, 7 insertions(+), 776 deletions(-) delete mode 100644 src/terminal/adapter/MouseInput.cpp delete mode 100644 src/terminal/adapter/MouseInput.hpp diff --git a/src/host/server.h b/src/host/server.h index 3d85ed45943..900a056e5ae 100644 --- a/src/host/server.h +++ b/src/host/server.h @@ -21,7 +21,7 @@ Revision History: #include "settings.hpp" #include "conimeinfo.h" -#include "..\terminal\adapter\MouseInput.hpp" +#include "..\terminal\input\terminalInput.hpp" #include "VtIo.hpp" #include "CursorBlinker.hpp" @@ -107,7 +107,7 @@ class CONSOLE_INFORMATION : ConsoleImeInfo ConsoleIme; - Microsoft::Console::VirtualTerminal::MouseInput terminalMouseInput; + Microsoft::Console::VirtualTerminal::TerminalInput terminalMouseInput; void LockConsole(); bool TryLockConsole(); diff --git a/src/terminal/adapter/MouseInput.cpp b/src/terminal/adapter/MouseInput.cpp deleted file mode 100644 index 6f4e1cb88e1..00000000000 --- a/src/terminal/adapter/MouseInput.cpp +++ /dev/null @@ -1,661 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -#include "precomp.h" -#include -#include "MouseInput.hpp" - -using namespace Microsoft::Console::VirtualTerminal; - -#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." -static constexpr short KeyPressed{ gsl::narrow_cast(0x8000) }; - -// Alternate scroll sequences -static constexpr std::wstring_view CursorUpSequence{ L"\x1b[A" }; -static constexpr std::wstring_view CursorDownSequence{ L"\x1b[B" }; - -MouseInput::MouseInput(const WriteInputEvents pfnWriteEvents) noexcept : - _pfnWriteEvents(pfnWriteEvents), - _lastPos{ -1, -1 }, - _lastButton{ 0 } -{ -} - -// 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: -// - button - the message to decode. -// Return value: -// - true iff button is a button message to translate -static constexpr bool _isButtonMsg(const unsigned int button) noexcept -{ - bool isButton = false; - switch (button) - { - case WM_LBUTTONDBLCLK: - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_MBUTTONUP: - case WM_RBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONDBLCLK: - case WM_MBUTTONDOWN: - case WM_MBUTTONDBLCLK: - case WM_MOUSEWHEEL: - case WM_MOUSEHWHEEL: - isButton = true; - break; - } - return isButton; -} - -// Routine Description: -// - Determines if the input windows message code describes a hover event -// Parameters: -// - buttonCode - the message to decode. -// Return value: -// - true iff buttonCode is a hover enent to translate -static constexpr bool _isHoverMsg(const unsigned int buttonCode) noexcept -{ - return buttonCode == WM_MOUSEMOVE; -} - -// Routine Description: -// - Determines if the input windows message code describes a button press -// (either down or doubleclick) -// Parameters: -// - button - the message to decode. -// Return value: -// - true iff button is a button down event -static constexpr bool _isButtonDown(const unsigned int button) noexcept -{ - bool isButtonDown = false; - switch (button) - { - case WM_LBUTTONDBLCLK: - case WM_LBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_RBUTTONDBLCLK: - case WM_MBUTTONDOWN: - case WM_MBUTTONDBLCLK: - case WM_MOUSEWHEEL: - case WM_MOUSEHWHEEL: - isButtonDown = true; - break; - } - return isButtonDown; -} - -// Routine Description: -// - translates the input windows mouse message into its equivalent X11 encoding. -// X Button Encoding: -// |7|6|5|4|3|2|1|0| -// | |W|H|M|C|S|B|B| -// bits 0 and 1 are used for button: -// 00 - MB1 pressed (left) -// 01 - MB2 pressed (middle) -// 10 - MB3 pressed (right) -// 11 - released (none) -// Next three bits indicate modifier keys: -// 0x04 - shift (This never makes it through, as our emulator is skipped when shift is pressed.) -// 0x08 - ctrl -// 0x10 - meta -// 32 (x20) is added for "hover" events: -// "For example, motion into cell x,y with button 1 down is reported as `CSI M @ CxCy`. -// ( @ = 32 + 0 (button 1) + 32 (motion indicator) ). -// Similarly, motion with button 3 down is reported as `CSI M B CxCy`. -// ( B = 32 + 2 (button 3) + 32 (motion indicator) ). -// 64 (x40) is added for wheel events. -// so wheel up? is 64, and wheel down? is 65. -// -// Parameters: -// - 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. -static constexpr int _windowsButtonToXEncoding(const unsigned int button, - const bool isHover, - const short modifierKeyState, - const short delta) noexcept -{ - int xvalue = 0; - switch (button) - { - case WM_LBUTTONDBLCLK: - case WM_LBUTTONDOWN: - xvalue = 0; - break; - case WM_LBUTTONUP: - case WM_MBUTTONUP: - case WM_RBUTTONUP: - xvalue = 3; - break; - case WM_RBUTTONDOWN: - case WM_RBUTTONDBLCLK: - xvalue = 2; - break; - case WM_MBUTTONDOWN: - case WM_MBUTTONDBLCLK: - xvalue = 1; - break; - case WM_MOUSEWHEEL: - case WM_MOUSEHWHEEL: - xvalue = delta > 0 ? 0x40 : 0x41; - } - if (isHover) - { - 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 - // 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. - // xvalue += (modifierKeyState & MK_META) ? 0x10 : 0x00; - - return xvalue; -} - -// Routine Description: -// - translates the input windows mouse message into its equivalent SGR encoding. -// This is nearly identical to the X encoding, with an important difference. -// The button is always encoded as 0, 1, 2. -// 3 is reserved for mouse hovers with _no_ buttons pressed. -// See MSFT:19461988 and https://github.com/Microsoft/console/issues/296 -// Parameters: -// - button - the message to decode. -// Return value: -// - the int representing the equivalent X button encoding. -static constexpr int _windowsButtonToSGREncoding(const unsigned int button, - const bool isHover, - const short modifierKeyState, - const short delta) noexcept -{ - int xvalue = 0; - switch (button) - { - case WM_LBUTTONDBLCLK: - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - xvalue = 0; - break; - case WM_RBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONDBLCLK: - xvalue = 2; - break; - case WM_MBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONDBLCLK: - xvalue = 1; - break; - case WM_MOUSEMOVE: - xvalue = 3; - break; - case WM_MOUSEWHEEL: - case WM_MOUSEHWHEEL: - xvalue = delta > 0 ? 0x40 : 0x41; - } - if (isHover) - { - 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 - // 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. - // xvalue += (modifierKeyState & MK_META) ? 0x10 : 0x00; - - 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 character ' '. -// Parameters: -// - sCoordinateValue - the value to encode. -// Return value: -// - the encoded value. -static constexpr short _encodeDefaultCoordinate(const short sCoordinateValue) noexcept -{ - return sCoordinateValue + 32; -} - -// Routine Description: -// - Attempt to handle the given mouse coordinates and windows button as a VT-style mouse event. -// 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: -// - 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 position, - const unsigned int button, - const short modifierKeyState, - const short delta) -{ - bool success = false; - if (_ShouldSendAlternateScroll(button, delta)) - { - success = _SendAlternateScroll(delta); - } - else - { - success = (_trackingMode != TrackingMode::None); - if (success) - { - // isHover is only true for WM_MOUSEMOVE events - const bool isHover = _isHoverMsg(button); - const bool isButton = _isButtonMsg(button); - - 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 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 = realButton != WM_LBUTTONUP; - - success = (isButton && _trackingMode != TrackingMode::None) || - (isHover && _trackingMode == TrackingMode::ButtonEvent && ((!sameCoord) && (physicalButtonPressed))) || - (isHover && _trackingMode == TrackingMode::AnyEvent && !sameCoord); - if (success) - { - std::wstring sequence; - switch (_extendedMode) - { - case ExtendedMode::None: - sequence = _GenerateDefaultSequence(position, - realButton, - isHover, - modifierKeyState, - delta); - break; - case ExtendedMode::Utf8: - 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. - 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: - success = false; - break; - } - - success = !sequence.empty(); - - if (success) - { - _SendInputSequence(sequence); - success = true; - } - if (_trackingMode == TrackingMode::ButtonEvent || _trackingMode == TrackingMode::AnyEvent) - { - _lastPos.X = position.X; - _lastPos.Y = position.Y; - _lastButton = button; - } - } - } - } - 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: -// - 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: -// - 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) -{ - // 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 (position.X <= MouseInput::s_MaxDefaultCoordinate && position.Y <= MouseInput::s_MaxDefaultCoordinate) - { - const COORD vtCoords = _winToVTCoord(position); - const short encodedX = _encodeDefaultCoordinate(vtCoords.X); - const short encodedY = _encodeDefaultCoordinate(vtCoords.Y); - - std::wstring format{ L"\x1b[Mbxy" }; - format.at(3) = ' ' + gsl::narrow_cast(_windowsButtonToXEncoding(button, isHover, modifierKeyState, delta)); - format.at(4) = encodedX; - format.at(5) = encodedY; - return format; - } - - 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: -// - 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: -// - 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) -{ - // 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. - // So, if we want to emit a char > x80 here, great. bash.exe will convert the x80 into xC280 and pass that along, which is great. - // The *nix application was expecting a utf8 stream, and it got one. - // However, a normal windows program asks for utf8 mode, then it gets the utf16 encoded result. This is not what it wanted. - // It was looking for \x1b[M#\xC280y and got \x1b[M#\x0080y - // Now, I'd argue that in requesting utf8 mode, the application should be enlightened enough to not want the utf16 input stream, - // and convert it the same way bash.exe does. - // Though, the point could be made to place the utf8 bytes into the input, and read them that way. - // However, if we did this, bash.exe would translate those bytes thinking they're utf16, and x80->xC280->xC382C280 - // 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 (position.X <= (SHORT_MAX - 33) && position.Y <= (SHORT_MAX - 33)) - { - 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(_windowsButtonToXEncoding(button, isHover, modifierKeyState, delta)); - format.at(4) = encodedX; - format.at(5) = encodedY; - return format; - } - - 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: -// - position - The windows coordinates (top,left = 0,0) of the mouse event -// - button - the message to decode. WM_MOUSEMOVE is used for mouse hovers with no buttons pressed. -// - isDown - true iff a mouse button was pressed. -// - 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. -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' - const int xbutton = _windowsButtonToSGREncoding(button, isHover, modifierKeyState, delta); - - auto format = wil::str_printf(L"\x1b[<%d;%d;%d%c", xbutton, position.X + 1, position.Y + 1, isDown ? L'M' : L'm'); - - return format; -} - -// Routine Description: -// - Either enables or disables UTF-8 extended mode encoding. This *should* cause -// the coordinates of a mouse event to be encoded as a UTF-8 byte stream, however, because windows' input is -// 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: -// - enable - either enable or disable. -// Return value: -// -void MouseInput::SetUtf8ExtendedMode(const bool enable) noexcept -{ - _extendedMode = enable ? ExtendedMode::Utf8 : ExtendedMode::None; -} - -// Routine Description: -// - Either enables or disables SGR extended mode encoding. This causes the -// coordinates of a mouse event to be emitted in a human readable format, -// eg, x,y=203,504 -> "^[[ -void MouseInput::SetSGRExtendedMode(const bool enable) noexcept -{ - _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: -// - enable - either enable or disable. -// Return value: -// -void MouseInput::EnableDefaultTracking(const bool enable) noexcept -{ - _trackingMode = enable ? TrackingMode::Default : TrackingMode::None; - _lastPos = { -1, -1 }; // Clear out the last saved mouse position & button. - _lastButton = 0; -} - -// Routine Description: -// - Either enables or disables ButtonEvent mouse handling. Button Event mode -// sends additional sequences when a button is pressed and the mouse changes character cells. -// Leaves the extended mode alone, so if we disable then re-enable mouse mode -// without toggling an extended mode, the mode will persist. -// Parameters: -// - enable - either enable or disable. -// Return value: -// -void MouseInput::EnableButtonEventTracking(const bool enable) noexcept -{ - _trackingMode = enable ? TrackingMode::ButtonEvent : TrackingMode::None; - _lastPos = { -1, -1 }; // Clear out the last saved mouse position & button. - _lastButton = 0; -} - -// Routine Description: -// - Either enables or disables AnyEvent mouse handling. Any Event mode sends sequences -// for any and every mouse event, regardless if a button is pressed or not. -// Leaves the extended mode alone, so if we disable then re-enable mouse mode -// without toggling an extended mode, the mode will persist. -// Parameters: -// - enable - either enable or disable. -// Return value: -// -void MouseInput::EnableAnyEventTracking(const bool enable) noexcept -{ - _trackingMode = enable ? TrackingMode::AnyEvent : TrackingMode::None; - _lastPos = { -1, -1 }; // Clear out the last saved mouse position & button. - _lastButton = 0; -} - -// Routine Description: -// - 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: -// - sequence - sequence to send to _pfnWriteEvents -// Return value: -// -void MouseInput::_SendInputSequence(const std::wstring_view sequence) const noexcept -{ - if (!sequence.empty()) - { - std::deque> events; - try - { - for (const auto& wch : sequence) - { - events.push_back(std::make_unique(true, 1ui16, 0ui16, 0ui16, wch, 0)); - } - - _pfnWriteEvents(events); - } - catch (...) - { - LOG_HR(wil::ResultFromCaughtException()); - } - } -} - -// 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: -// -// Return value: -// - a button corresponding to any pressed mouse buttons, else WM_LBUTTONUP if none are pressed. -unsigned int MouseInput::s_GetPressedButton() noexcept -{ - unsigned int button = WM_LBUTTONUP; // Will be treated as a release, or no button pressed. - if (WI_IsFlagSet(GetKeyState(VK_LBUTTON), KeyPressed)) - { - button = WM_LBUTTONDOWN; - } - else if (WI_IsFlagSet(GetKeyState(VK_MBUTTON), KeyPressed)) - { - button = WM_MBUTTONDOWN; - } - else if (WI_IsFlagSet(GetKeyState(VK_RBUTTON), KeyPressed)) - { - button = WM_RBUTTONDOWN; - } - return button; -} - -// Routine Description: -// - Enables alternate scroll mode. This sends Cursor Up/down sequences when in the alternate buffer -// Parameters: -// - enable - either enable or disable. -// Return value: -// -void MouseInput::EnableAlternateScroll(const bool enable) noexcept -{ - _alternateScroll = enable; -} - -// Routine Description: -// - Notify the MouseInput handler that the screen buffer has been swapped to the alternate buffer -// Parameters: -// -// Return value: -// -void MouseInput::UseAlternateScreenBuffer() noexcept -{ - _inAlternateBuffer = true; -} - -// Routine Description: -// - Notify the MouseInput handler that the screen buffer has been swapped to the alternate buffer -// Parameters: -// -// Return value: -// -void MouseInput::UseMainScreenBuffer() noexcept -{ - _inAlternateBuffer = false; -} - -// Routine Description: -// - Returns true if we should translate the input event (button, sScrollDelta) -// into an alternate scroll event instead of the default scroll event, -// depending on if alternate scroll mode is enabled and we're in the alternate buffer. -// Parameters: -// - 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(const unsigned int button, const short delta) const noexcept -{ - return _inAlternateBuffer && - _alternateScroll && - (button == WM_MOUSEWHEEL || button == WM_MOUSEHWHEEL) && delta != 0; -} - -// Routine Description: -// - Sends a sequence to the input corresponding to cursor up / down depending on the sScrollDelta. -// Parameters: -// - delta: The scroll wheel delta of the input event -// Return value: -// True iff the input sequence was sent successfully. -bool MouseInput::_SendAlternateScroll(const short delta) const noexcept -{ - if (delta > 0) - { - _SendInputSequence(CursorUpSequence); - } - else - { - _SendInputSequence(CursorDownSequence); - } - return true; -} diff --git a/src/terminal/adapter/MouseInput.hpp b/src/terminal/adapter/MouseInput.hpp deleted file mode 100644 index 64fc6253d4b..00000000000 --- a/src/terminal/adapter/MouseInput.hpp +++ /dev/null @@ -1,100 +0,0 @@ -/*++ -Copyright (c) Microsoft Corporation -Licensed under the MIT license. - -Module Name: -- MouseInput.hpp - -Abstract: -- This serves as an adapter between mouse input from a user and the virtual terminal sequences that are - typically emitted by an xterm-compatible console. - -Author(s): -- Mike Griese (migrie) 01-Aug-2016 ---*/ -#pragma once - -#include "../../types/inc/IInputEvent.hpp" - -#include -#include - -namespace Microsoft::Console::VirtualTerminal -{ - typedef void (*WriteInputEvents)(_Inout_ std::deque>& events); - - class MouseInput sealed - { - public: - MouseInput(const WriteInputEvents pfnWriteEvents) noexcept; - - bool HandleMouse(const COORD position, - const unsigned int button, - const short modifierKeyState, - const short delta); - - 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; - - enum class ExtendedMode : unsigned int - { - None, - Utf8, - Sgr, - Urxvt - }; - - enum class TrackingMode : unsigned int - { - None, - Default, - ButtonEvent, - AnyEvent - }; - - private: - static const int s_MaxDefaultCoordinate = 94; - - WriteInputEvents _pfnWriteEvents; - - ExtendedMode _extendedMode = ExtendedMode::None; - TrackingMode _trackingMode = TrackingMode::None; - - bool _alternateScroll = false; - bool _inAlternateBuffer = false; - - COORD _lastPos; - unsigned int _lastButton; - - 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(const unsigned int button, const short delta) const noexcept; - bool _SendAlternateScroll(const short delta) const noexcept; - - static unsigned int s_GetPressedButton() noexcept; - }; -} diff --git a/src/terminal/adapter/lib/adapter.vcxproj b/src/terminal/adapter/lib/adapter.vcxproj index fbce0914011..0c8a0e52c10 100644 --- a/src/terminal/adapter/lib/adapter.vcxproj +++ b/src/terminal/adapter/lib/adapter.vcxproj @@ -14,7 +14,6 @@ - @@ -29,7 +28,6 @@ - diff --git a/src/terminal/adapter/lib/adapter.vcxproj.filters b/src/terminal/adapter/lib/adapter.vcxproj.filters index 5fef08ea49d..4e3979bed04 100644 --- a/src/terminal/adapter/lib/adapter.vcxproj.filters +++ b/src/terminal/adapter/lib/adapter.vcxproj.filters @@ -39,9 +39,6 @@ Source Files - - Source Files - @@ -65,9 +62,6 @@ Header Files - - Header Files - Header Files diff --git a/src/terminal/adapter/ut_adapter/MouseInputTest.cpp b/src/terminal/adapter/ut_adapter/MouseInputTest.cpp index b54f9ee4837..c8823e9097e 100644 --- a/src/terminal/adapter/ut_adapter/MouseInputTest.cpp +++ b/src/terminal/adapter/ut_adapter/MouseInputTest.cpp @@ -5,7 +5,7 @@ #include #include "..\..\inc\consoletaeftemplates.hpp" -#include "MouseInput.hpp" +#include "..\terminal\input\terminalInput.hpp" using namespace WEX::Common; using namespace WEX::Logging; @@ -280,7 +280,7 @@ class MouseInputTest Log::Comment(L"Starting test..."); - std::unique_ptr mouseInput = std::make_unique(s_MouseInputTestCallback); + std::unique_ptr mouseInput = std::make_unique(s_MouseInputTestCallback); unsigned int uiModifierKeystate = 0; VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"uiModifierKeystate", uiModifierKeystate)); @@ -359,7 +359,7 @@ class MouseInputTest Log::Comment(L"Starting test..."); - std::unique_ptr mouseInput = std::make_unique(s_MouseInputTestCallback); + std::unique_ptr mouseInput = std::make_unique(s_MouseInputTestCallback); unsigned int uiModifierKeystate = 0; VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"uiModifierKeystate", uiModifierKeystate)); @@ -442,7 +442,7 @@ class MouseInputTest Log::Comment(L"Starting test..."); - std::unique_ptr mouseInput = std::make_unique(s_MouseInputTestCallback); + std::unique_ptr mouseInput = std::make_unique(s_MouseInputTestCallback); unsigned int uiModifierKeystate = 0; VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"uiModifierKeystate", uiModifierKeystate)); short sModifierKeystate = (SHORT)uiModifierKeystate; @@ -520,7 +520,7 @@ class MouseInputTest Log::Comment(L"Starting test..."); - std::unique_ptr mouseInput = std::make_unique(s_MouseInputTestCallback); + std::unique_ptr mouseInput = std::make_unique(s_MouseInputTestCallback); unsigned int uiModifierKeystate = 0; VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"uiModifierKeystate", uiModifierKeystate)); short sModifierKeystate = (SHORT)uiModifierKeystate; From 7e25e6af578bd721a8beed6bb92c3a0ec89b9e03 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Mon, 9 Mar 2020 11:14:39 -0700 Subject: [PATCH 3/7] code format + static analysis fix --- src/terminal/input/mouseInput.cpp | 26 +++++++++++++------------- src/terminal/input/terminalInput.cpp | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/terminal/input/mouseInput.cpp b/src/terminal/input/mouseInput.cpp index a2d8a4b3649..8fd67c02be6 100644 --- a/src/terminal/input/mouseInput.cpp +++ b/src/terminal/input/mouseInput.cpp @@ -379,10 +379,10 @@ bool TerminalInput::HandleMouse(const COORD position, // Return value: // - The generated sequence. Will be empty if we couldn't generate. std::wstring TerminalInput::_GenerateDefaultSequence(const COORD position, - const unsigned int button, - const bool isHover, - const short modifierKeyState, - const short delta) + const unsigned int button, + const bool isHover, + const short modifierKeyState, + const short delta) { // 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. @@ -416,10 +416,10 @@ std::wstring TerminalInput::_GenerateDefaultSequence(const COORD position, // Return value: // - The generated sequence. Will be empty if we couldn't generate. std::wstring TerminalInput::_GenerateUtf8Sequence(const COORD position, - const unsigned int button, - const bool isHover, - const short modifierKeyState, - const short delta) + const unsigned int button, + const bool isHover, + const short modifierKeyState, + const short delta) { // So we have some complications here. // The windows input stream is typically encoded as UTF16. @@ -467,11 +467,11 @@ std::wstring TerminalInput::_GenerateUtf8Sequence(const COORD position, // - true if we were able to successfully generate a sequence. // On success, caller is responsible for delete[]ing *ppwchSequence. std::wstring TerminalInput::_GenerateSGRSequence(const COORD position, - const unsigned int button, - const bool isDown, - const bool isHover, - const short modifierKeyState, - const short delta) + 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' diff --git a/src/terminal/input/terminalInput.cpp b/src/terminal/input/terminalInput.cpp index 9935ae08ca2..7965a1a78fe 100644 --- a/src/terminal/input/terminalInput.cpp +++ b/src/terminal/input/terminalInput.cpp @@ -367,7 +367,7 @@ bool TerminalInput::HandleKey(const IInputEvent* const pInEvent) const // 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); }; + const auto senderFunc = [this](const std::wstring_view seq) noexcept { _SendInputSequence(seq); }; auto keyEvent = *static_cast(pInEvent); From df35803146ed969d4b01788cd0ab8ed937277d6d Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Tue, 10 Mar 2020 11:56:10 -0700 Subject: [PATCH 4/7] add TODO and missing onecore ifdef --- src/terminal/input/mouseInput.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/terminal/input/mouseInput.cpp b/src/terminal/input/mouseInput.cpp index 8fd67c02be6..88c8ad2e64a 100644 --- a/src/terminal/input/mouseInput.cpp +++ b/src/terminal/input/mouseInput.cpp @@ -7,6 +7,9 @@ using namespace Microsoft::Console::VirtualTerminal; +#ifdef BUILD_ONECORE_INTERACTIVITY +#include "..\..\interactivity\inc\VtApiRedirection.hpp" +#endif static const int s_MaxDefaultCoordinate = 94; // This magic flag is "documented" at https://msdn.microsoft.com/en-us/library/windows/desktop/ms646301(v=vs.85).aspx @@ -93,6 +96,7 @@ static constexpr bool _isButtonDown(const unsigned int button) noexcept // - a button corresponding to any pressed mouse buttons, else WM_LBUTTONUP if none are pressed. unsigned int TerminalInput::s_GetPressedButton() noexcept { + // TODO GH#4869: Have the caller pass the mouse button state into HandleMouse unsigned int button = WM_LBUTTONUP; // Will be treated as a release, or no button pressed. if (WI_IsFlagSet(GetKeyState(VK_LBUTTON), KeyPressed)) { From 41129e532e6652c425c1e2c58dcafe1148cc07c1 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Tue, 10 Mar 2020 14:40:16 -0700 Subject: [PATCH 5/7] remove duplicate TerminalInput. Always use the InputBuffer's --- src/host/getset.cpp | 12 ++++++------ src/host/screenInfo.cpp | 4 ++-- src/host/server.h | 2 -- src/interactivity/win32/windowio.cpp | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/host/getset.cpp b/src/host/getset.cpp index cba5bc3a12e..85a8a1e4eaa 100644 --- a/src/host/getset.cpp +++ b/src/host/getset.cpp @@ -1616,7 +1616,7 @@ void DoSrvPrivateTabClear(const bool fClearAll) void DoSrvPrivateEnableVT200MouseMode(const bool fEnable) { CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); - gci.terminalMouseInput.EnableDefaultTracking(fEnable); + gci.GetActiveInputBuffer()->GetTerminalInput().EnableDefaultTracking(fEnable); } // Routine Description: @@ -1628,7 +1628,7 @@ void DoSrvPrivateEnableVT200MouseMode(const bool fEnable) void DoSrvPrivateEnableUTF8ExtendedMouseMode(const bool fEnable) { CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); - gci.terminalMouseInput.SetUtf8ExtendedMode(fEnable); + gci.GetActiveInputBuffer()->GetTerminalInput().SetUtf8ExtendedMode(fEnable); } // Routine Description: @@ -1640,7 +1640,7 @@ void DoSrvPrivateEnableUTF8ExtendedMouseMode(const bool fEnable) void DoSrvPrivateEnableSGRExtendedMouseMode(const bool fEnable) { CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); - gci.terminalMouseInput.SetSGRExtendedMode(fEnable); + gci.GetActiveInputBuffer()->GetTerminalInput().SetSGRExtendedMode(fEnable); } // Routine Description: @@ -1652,7 +1652,7 @@ void DoSrvPrivateEnableSGRExtendedMouseMode(const bool fEnable) void DoSrvPrivateEnableButtonEventMouseMode(const bool fEnable) { CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); - gci.terminalMouseInput.EnableButtonEventTracking(fEnable); + gci.GetActiveInputBuffer()->GetTerminalInput().EnableButtonEventTracking(fEnable); } // Routine Description: @@ -1664,7 +1664,7 @@ void DoSrvPrivateEnableButtonEventMouseMode(const bool fEnable) void DoSrvPrivateEnableAnyEventMouseMode(const bool fEnable) { CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); - gci.terminalMouseInput.EnableAnyEventTracking(fEnable); + gci.GetActiveInputBuffer()->GetTerminalInput().EnableAnyEventTracking(fEnable); } // Routine Description: @@ -1676,7 +1676,7 @@ void DoSrvPrivateEnableAnyEventMouseMode(const bool fEnable) void DoSrvPrivateEnableAlternateScroll(const bool fEnable) { CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); - gci.terminalMouseInput.EnableAlternateScroll(fEnable); + gci.GetActiveInputBuffer()->GetTerminalInput().EnableAlternateScroll(fEnable); } // Routine Description: diff --git a/src/host/screenInfo.cpp b/src/host/screenInfo.cpp index 8437d4999fc..477910b59e9 100644 --- a/src/host/screenInfo.cpp +++ b/src/host/screenInfo.cpp @@ -1890,7 +1890,7 @@ const SCREEN_INFORMATION& SCREEN_INFORMATION::GetMainBuffer() const ScreenBufferSizeChange(psiNewAltBuffer->GetBufferSize().Dimensions()); // Tell the VT MouseInput handler that we're in the Alt buffer now - gci.terminalMouseInput.UseAlternateScreenBuffer(); + gci.GetActiveInputBuffer()->GetTerminalInput().UseAlternateScreenBuffer(); } return Status; } @@ -1924,7 +1924,7 @@ void SCREEN_INFORMATION::UseMainScreenBuffer() // deleting the alt buffer will give the GetSet back to its main // Tell the VT MouseInput handler that we're in the main buffer now - gci.terminalMouseInput.UseMainScreenBuffer(); + gci.GetActiveInputBuffer()->GetTerminalInput().UseMainScreenBuffer(); } } diff --git a/src/host/server.h b/src/host/server.h index 900a056e5ae..985a2ed536f 100644 --- a/src/host/server.h +++ b/src/host/server.h @@ -107,8 +107,6 @@ class CONSOLE_INFORMATION : ConsoleImeInfo ConsoleIme; - Microsoft::Console::VirtualTerminal::TerminalInput terminalMouseInput; - void LockConsole(); bool TryLockConsole(); void UnlockConsole(); diff --git a/src/interactivity/win32/windowio.cpp b/src/interactivity/win32/windowio.cpp index 43e0d729d5e..ba3b0385b74 100644 --- a/src/interactivity/win32/windowio.cpp +++ b/src/interactivity/win32/windowio.cpp @@ -123,7 +123,7 @@ bool HandleTerminalMouseEvent(const COORD cMousePosition, // Virtual terminal input mode if (IsInVirtualTerminalInputMode()) { - fWasHandled = gci.terminalMouseInput.HandleMouse(cMousePosition, uiButton, sModifierKeystate, sWheelDelta); + fWasHandled = gci.GetActiveInputBuffer()->GetTerminalInput().HandleMouse(cMousePosition, uiButton, sModifierKeystate, sWheelDelta); } return fWasHandled; From fb6e6bade101e4c610bab82b4a52cd59eae799e6 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Tue, 10 Mar 2020 16:13:04 -0700 Subject: [PATCH 6/7] update sources and fix conhost build failure --- src/host/consoleInformation.cpp | 13 ------------- src/host/server.h | 3 --- src/terminal/adapter/sources.inc | 1 - src/terminal/input/sources.inc | 2 ++ 4 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/host/consoleInformation.cpp b/src/host/consoleInformation.cpp index 34d99a10c09..32ec1959ee4 100644 --- a/src/host/consoleInformation.cpp +++ b/src/host/consoleInformation.cpp @@ -35,7 +35,6 @@ CONSOLE_INFORMATION::CONSOLE_INFORMATION() : // OutputCPInfo initialized below _cookedReadData(nullptr), ConsoleIme{}, - terminalMouseInput(HandleTerminalKeyEventCallback), _vtIo(), _blinker{}, renderData{} @@ -180,18 +179,6 @@ void CONSOLE_INFORMATION::SetCookedReadData(COOKED_READ_DATA* readData) noexcept _cookedReadData = readData; } -// Routine Description: -// - Handler for inserting key sequences into the buffer when the terminal emulation layer -// has determined a key can be converted appropriately into a sequence of inputs -// Arguments: -// - events - the input events to write to the input buffer -// Return Value: -// - -void CONSOLE_INFORMATION::HandleTerminalKeyEventCallback(_Inout_ std::deque>& events) -{ - ServiceLocator::LocateGlobals().getConsoleInformation().pInputBuffer->Write(events); -} - // Method Description: // - Return the active screen buffer of the console. // Arguments: diff --git a/src/host/server.h b/src/host/server.h index 985a2ed536f..9dcb035c380 100644 --- a/src/host/server.h +++ b/src/host/server.h @@ -21,7 +21,6 @@ Revision History: #include "settings.hpp" #include "conimeinfo.h" -#include "..\terminal\input\terminalInput.hpp" #include "VtIo.hpp" #include "CursorBlinker.hpp" @@ -115,8 +114,6 @@ class CONSOLE_INFORMATION : Microsoft::Console::VirtualTerminal::VtIo* GetVtIo(); - static void HandleTerminalKeyEventCallback(_Inout_ std::deque>& events); - SCREEN_INFORMATION& GetActiveOutputBuffer() override; const SCREEN_INFORMATION& GetActiveOutputBuffer() const override; bool HasActiveOutputBuffer() const; diff --git a/src/terminal/adapter/sources.inc b/src/terminal/adapter/sources.inc index 0169a0a5746..0fadc810f99 100644 --- a/src/terminal/adapter/sources.inc +++ b/src/terminal/adapter/sources.inc @@ -34,7 +34,6 @@ SOURCES= \ ..\DispatchCommon.cpp \ ..\InteractDispatch.cpp \ ..\adaptDispatchGraphics.cpp \ - ..\MouseInput.cpp \ ..\terminalOutput.cpp \ ..\telemetry.cpp \ ..\tracing.cpp \ diff --git a/src/terminal/input/sources.inc b/src/terminal/input/sources.inc index 50ef9b0570b..8956b25c52e 100644 --- a/src/terminal/input/sources.inc +++ b/src/terminal/input/sources.inc @@ -29,6 +29,8 @@ PRECOMPILED_INCLUDE = ..\precomp.h SOURCES= \ ..\terminalInput.cpp \ + ..\mouseInput.cpp \ + ..\mouseInputState.cpp \ INCLUDES = \ $(INCLUDES); \ From 863fab40841bc4c27be40727949cb9b3c5d4748e Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Wed, 11 Mar 2020 11:07:03 -0700 Subject: [PATCH 7/7] fix conhost --- src/host/inputBuffer.cpp | 13 +++++++++++-- src/host/inputBuffer.hpp | 6 ++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/host/inputBuffer.cpp b/src/host/inputBuffer.cpp index edb7d51dec1..a794d9bf617 100644 --- a/src/host/inputBuffer.cpp +++ b/src/host/inputBuffer.cpp @@ -466,6 +466,8 @@ size_t InputBuffer::Prepend(_Inout_ std::deque>& in { try { + _vtInputShouldSuppress = true; + auto resetVtInputSupress = wil::scope_exit([&]() { _vtInputShouldSuppress = false; }); _HandleConsoleSuspensionEvents(inEvents); if (inEvents.empty()) { @@ -556,6 +558,8 @@ size_t InputBuffer::Write(_Inout_ std::deque>& inEv { try { + _vtInputShouldSuppress = true; + auto resetVtInputSuppress = wil::scope_exit([&]() { _vtInputShouldSuppress = false; }); _HandleConsoleSuspensionEvents(inEvents); if (inEvents.empty()) { @@ -841,8 +845,7 @@ bool InputBuffer::IsInVirtualTerminalInputMode() const // - Handler for inserting key sequences into the buffer when the terminal emulation layer // has determined a key can be converted appropriately into a sequence of inputs // Arguments: -// - rgInput - Series of input records to insert into the buffer -// - cInput - Length of input records array +// - inEvents - Series of input records to insert into the buffer // Return Value: // - void InputBuffer::_HandleTerminalInputCallback(std::deque>& inEvents) @@ -856,6 +859,12 @@ void InputBuffer::_HandleTerminalInputCallback(std::deque _writePartialByteSequence; Microsoft::Console::VirtualTerminal::TerminalInput _termInput; + // This flag is used in _HandleTerminalInputCallback + // If the InputBuffer leads to a _HandleTerminalInputCallback call, + // we should suppress the wakeup functions. + // Otherwise, we should be calling them. + bool _vtInputShouldSuppress{ false }; + void _ReadBuffer(_Out_ std::deque>& outEvents, const size_t readCount, _Out_ size_t& eventsRead,