mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
Restore off-the-top behavior for VT mouse mode (#17779)
PR #10642 and #11290 introduced an adjustment for the cursor position used to generate VT mouse mode events. One of the decisions made in those PRs was to only send coordinates where Y was >= 0, so if you were off the top of the screen you wouldn't get any events. However, terminal emulators are expected to send _clamped_ events when the mouse is off the screen. This decision broke clamping Y to 0 when the mouse was above the screen. The other decision was to only adjust the Y coordinate if the core's `ScrollOffset` was greater than 0. It turns out that `ScrollOffset` _is 0_ when you are scrolled all the way back in teh buffer. With this check, we would clamp coordinates properly _until the top line of the scrollback was visible_, at which point we would send those coordinates over directly. This resulted in the same weird behavior as observed in #10190. I've fixed both of those things. Core is expected to receive negative coordinates and clamp them to the viewport. ScrollOffset should never be below 0, as it refers to the top visible buffer line. In addition to that, #17744 uncovered that we were allowing autoscrolling to happen even when VT mouse events were being generated. I added a way for `ControlInteractivity` to halt further event processing. It's crude. Refs #10190 Closes #17744
This commit is contained in:
parent
e006f75f6c
commit
d1a1f9836e
@ -329,7 +329,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_touchAnchor = contactPoint;
|
||||
}
|
||||
|
||||
void ControlInteractivity::PointerMoved(Control::MouseButtonState buttonState,
|
||||
bool ControlInteractivity::PointerMoved(Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const bool focused,
|
||||
@ -337,11 +337,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const bool pointerPressedInBounds)
|
||||
{
|
||||
const auto terminalPosition = _getTerminalPosition(til::point{ pixelPosition });
|
||||
// Returning true from this function indicates that the caller should do no further processing of this movement.
|
||||
bool handledCompletely = false;
|
||||
|
||||
// Short-circuit isReadOnly check to avoid warning dialog
|
||||
if (focused && !_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers))
|
||||
{
|
||||
_sendMouseEventHelper(terminalPosition, pointerUpdateKind, modifiers, 0, buttonState);
|
||||
handledCompletely = true;
|
||||
}
|
||||
// GH#4603 - don't modify the selection if the pointer press didn't
|
||||
// actually start _in_ the control bounds. Case in point - someone drags
|
||||
@ -378,6 +381,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
|
||||
_core->SetHoveredCell(terminalPosition.to_core_point());
|
||||
return handledCompletely;
|
||||
}
|
||||
|
||||
void ControlInteractivity::TouchMoved(const Core::Point newTouchPoint,
|
||||
@ -682,13 +686,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const SHORT wheelDelta,
|
||||
Control::MouseButtonState buttonState)
|
||||
{
|
||||
const auto adjustment = _core->ScrollOffset() > 0 ? _core->BufferHeight() - _core->ScrollOffset() - _core->ViewHeight() : 0;
|
||||
// If the click happened outside the active region, just don't send any mouse event
|
||||
if (const auto adjustedY = terminalPosition.y - adjustment; adjustedY >= 0)
|
||||
{
|
||||
return _core->SendMouseEvent({ terminalPosition.x, adjustedY }, pointerUpdateKind, modifiers, wheelDelta, toInternalMouseState(buttonState));
|
||||
}
|
||||
return false;
|
||||
const auto adjustment = _core->BufferHeight() - _core->ScrollOffset() - _core->ViewHeight();
|
||||
// If the click happened outside the active region, core should get a chance to filter it out or clamp it.
|
||||
const auto adjustedY = terminalPosition.y - adjustment;
|
||||
return _core->SendMouseEvent({ terminalPosition.x, adjustedY }, pointerUpdateKind, modifiers, wheelDelta, toInternalMouseState(buttonState));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@ -58,7 +58,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const Core::Point pixelPosition);
|
||||
void TouchPressed(const Core::Point contactPoint);
|
||||
|
||||
void PointerMoved(Control::MouseButtonState buttonState,
|
||||
bool PointerMoved(Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const bool focused,
|
||||
|
||||
@ -43,12 +43,12 @@ namespace Microsoft.Terminal.Control
|
||||
Microsoft.Terminal.Core.Point pixelPosition);
|
||||
void TouchPressed(Microsoft.Terminal.Core.Point contactPoint);
|
||||
|
||||
void PointerMoved(MouseButtonState buttonState,
|
||||
UInt32 pointerUpdateKind,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers,
|
||||
Boolean focused,
|
||||
Microsoft.Terminal.Core.Point pixelPosition,
|
||||
Boolean pointerPressedInBounds);
|
||||
Boolean PointerMoved(MouseButtonState buttonState,
|
||||
UInt32 pointerUpdateKind,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers,
|
||||
Boolean focused,
|
||||
Microsoft.Terminal.Core.Point pixelPosition,
|
||||
Boolean pointerPressedInBounds);
|
||||
|
||||
void TouchMoved(Microsoft.Terminal.Core.Point newTouchPoint,
|
||||
Boolean focused);
|
||||
|
||||
@ -1936,18 +1936,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
if (type == Windows::Devices::Input::PointerDeviceType::Mouse ||
|
||||
type == Windows::Devices::Input::PointerDeviceType::Pen)
|
||||
{
|
||||
_interactivity.PointerMoved(TermControl::GetPressedMouseButtons(point),
|
||||
TermControl::GetPointerUpdateKind(point),
|
||||
ControlKeyStates(args.KeyModifiers()),
|
||||
_focused,
|
||||
pixelPosition.to_core_point(),
|
||||
_pointerPressedInBounds);
|
||||
auto suppressFurtherHandling = _interactivity.PointerMoved(TermControl::GetPressedMouseButtons(point),
|
||||
TermControl::GetPointerUpdateKind(point),
|
||||
ControlKeyStates(args.KeyModifiers()),
|
||||
_focused,
|
||||
pixelPosition.to_core_point(),
|
||||
_pointerPressedInBounds);
|
||||
|
||||
// GH#9109 - Only start an auto-scroll when the drag actually
|
||||
// started within our bounds. Otherwise, someone could start a drag
|
||||
// outside the terminal control, drag into the padding, and trick us
|
||||
// into starting to scroll.
|
||||
if (_focused && _pointerPressedInBounds && point.Properties().IsLeftButtonPressed())
|
||||
if (!suppressFurtherHandling && _focused && _pointerPressedInBounds && point.Properties().IsLeftButtonPressed())
|
||||
{
|
||||
// We want to find the distance relative to the bounds of the
|
||||
// SwapChainPanel, not the entire control. If they drag out of
|
||||
|
||||
@ -998,16 +998,15 @@ namespace ControlUnitTests
|
||||
VERIFY_IS_GREATER_THAN(core->ScrollOffset(), 0);
|
||||
|
||||
// Viewport is now above the mutable viewport, so the mouse event
|
||||
// straight up won't be sent to the terminal.
|
||||
// will be clamped to the top line.
|
||||
|
||||
expectedOutput.push_back(L"sentinel"); // Clearly, it won't be this string
|
||||
expectedOutput.push_back(L"\x1b[M &!"); // 5, 1
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
cursorPosition0.to_core_point());
|
||||
// Flush it out.
|
||||
conn->WriteInput(winrt_wstring_to_array_view(L"sentinel"));
|
||||
VERIFY_ARE_EQUAL(0u, expectedOutput.size(), L"Validate we drained all the expected output");
|
||||
|
||||
// This is the part as mentioned in GH#12719
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user