Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Account for WHEEL_DELTA when dispatching VT mouse wheel events #6843

Merged
3 commits merged into from
Jul 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 1 addition & 14 deletions src/interactivity/win32/windowio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,20 +630,7 @@ BOOL HandleMouseEvent(const SCREEN_INFORMATION& ScreenInfo,
short sDelta = 0;
if (Message == WM_MOUSEWHEEL)
{
short sWheelDelta = GET_WHEEL_DELTA_WPARAM(wParam);
// For most devices, we'll get mouse events as multiples of
// WHEEL_DELTA, where WHEEL_DELTA represents a single scroll unit
// But sometimes, things like trackpads will scroll in finer
// measurements. In this case, the VT mouse scrolling wouldn't work.
// So if that happens, ensure we scroll at least one time.
if (abs(sWheelDelta) < WHEEL_DELTA)
{
sDelta = sWheelDelta < 0 ? -1 : 1;
}
else
{
sDelta = sWheelDelta / WHEEL_DELTA;
}
sDelta = GET_WHEEL_DELTA_WPARAM(wParam);
}

if (HandleTerminalMouseEvent(MousePosition, Message, GET_KEYSTATE_WPARAM(wParam), sDelta))
Expand Down
14 changes: 7 additions & 7 deletions src/terminal/adapter/ut_adapter/MouseInputTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ class MouseInputTest
TEST_METHOD(ScrollWheelTests)
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"Data:sScrollDelta", L"{0, -1, 1, 100, -10000, 32736}")
TEST_METHOD_PROPERTY(L"Data:sScrollDelta", L"{-120, 120, -10000, 32736}")
TEST_METHOD_PROPERTY(L"Data:uiModifierKeystate", L"{0x0000, 0x0004, 0x0008}")
END_TEST_METHOD_PROPERTIES()

Expand Down Expand Up @@ -606,31 +606,31 @@ class MouseInputTest

Log::Comment(L"Test mouse wheel scrolling up");
s_pwszInputExpected = L"\x1B[A";
VERIFY_IS_TRUE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, 1));
VERIFY_IS_TRUE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, WHEEL_DELTA));

Log::Comment(L"Test mouse wheel scrolling down");
s_pwszInputExpected = L"\x1B[B";
VERIFY_IS_TRUE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, -1));
VERIFY_IS_TRUE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, -WHEEL_DELTA));

Log::Comment(L"Enable cursor keys mode");
mouseInput->ChangeCursorKeysMode(true);

Log::Comment(L"Test mouse wheel scrolling up");
s_pwszInputExpected = L"\x1BOA";
VERIFY_IS_TRUE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, 1));
VERIFY_IS_TRUE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, WHEEL_DELTA));

Log::Comment(L"Test mouse wheel scrolling down");
s_pwszInputExpected = L"\x1BOB";
VERIFY_IS_TRUE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, -1));
VERIFY_IS_TRUE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, -WHEEL_DELTA));

Log::Comment(L"Confirm no effect when scroll mode is disabled");
mouseInput->UseAlternateScreenBuffer();
mouseInput->EnableAlternateScroll(false);
VERIFY_IS_FALSE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, 1));
VERIFY_IS_FALSE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, WHEEL_DELTA));

Log::Comment(L"Confirm no effect when using the main buffer");
mouseInput->UseMainScreenBuffer();
mouseInput->EnableAlternateScroll(true);
VERIFY_IS_FALSE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, 1));
VERIFY_IS_FALSE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, WHEEL_DELTA));
}
};
38 changes: 38 additions & 0 deletions src/terminal/input/mouseInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "precomp.h"
#include <windows.h>
#include "terminalInput.hpp"
#include "../types/inc/utils.hpp"

using namespace Microsoft::Console::VirtualTerminal;

Expand Down Expand Up @@ -63,6 +64,17 @@ static constexpr bool _isHoverMsg(const unsigned int buttonCode) noexcept
return buttonCode == WM_MOUSEMOVE;
}

// Routine Description:
// - Determines if the input windows message code describes a mouse wheel event
// Parameters:
// - buttonCode - the message to decode.
// Return value:
// - true iff buttonCode is a wheel event to translate
static constexpr bool _isWheelMsg(const unsigned int buttonCode) noexcept
{
return buttonCode == WM_MOUSEWHEEL || buttonCode == WM_MOUSEHWHEEL;
}

// Routine Description:
// - Determines if the input windows message code describes a button press
// (either down or doubleclick)
Expand Down Expand Up @@ -293,6 +305,32 @@ bool TerminalInput::HandleMouse(const COORD position,
const short modifierKeyState,
const short delta)
{
if (Utils::Sign(delta) != Utils::Sign(_mouseInputState.accumulatedDelta))
{
// This works for wheel and non-wheel events and transitioning between wheel/non-wheel.
// Non-wheel events have a delta of 0, which will fail to match the sign on
// a real wheel event or the accumulated delta. Wheel events will be either + or -
// and we only want to accumulate them if they match in sign.
_mouseInputState.accumulatedDelta = 0;
}

if (_isWheelMsg(button))
{
_mouseInputState.accumulatedDelta += delta;
if (std::abs(_mouseInputState.accumulatedDelta) < WHEEL_DELTA)
{
// If we're accumulating button presses of the same type, *and* those presses are
// on the wheel, accumulate delta until we hit the amount required to dispatch one
// "line" worth of scroll.
// Mark the event as "handled" if we would have otherwise emitted a scroll event.
return IsTrackingMouseInput() || _ShouldSendAlternateScroll(button, delta);
}

// We're ready to send this event through, but first we need to clear the accumulated;
// delta. Otherwise, we'll dispatch every subsequent sub-delta event as its own event.
_mouseInputState.accumulatedDelta = 0;
}

bool success = false;
if (_ShouldSendAlternateScroll(button, delta))
{
Expand Down
1 change: 1 addition & 0 deletions src/terminal/input/terminalInput.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ namespace Microsoft::Console::VirtualTerminal
bool inAlternateBuffer{ false };
COORD lastPos{ -1, -1 };
unsigned int lastButton{ 0 };
int accumulatedDelta{ 0 };
};

MouseInputState _mouseInputState;
Expand Down
8 changes: 8 additions & 0 deletions src/types/inc/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ Author(s):

namespace Microsoft::Console::Utils
{
// Function Description:
// - Returns -1, 0 or +1 to indicate the sign of the passed-in value.
template<typename T>
constexpr int Sign(T val) noexcept
{
return (T{ 0 } < val) - (val < T{ 0 });
}

bool IsValidHandle(const HANDLE handle) noexcept;

// Function Description:
Expand Down