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

Manually pass mouse wheel messages to TermControls #5131

Merged
20 commits merged into from
Apr 1, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
dae733a
try naively passing the mouse event through, but that doesn't seem to…
zadjii Mar 24, 2020
892bc58
doing this the right way still isn't right
zadjii Mar 24, 2020
b708a08
start working on manually plumbing the event through, but this feels …
zadjii Mar 24, 2020
68ace1a
This is so dumb ; I love it
zadjii-msft Mar 24, 2020
7252ab6
Hey if your laptop's clock batttery is broken, you're going to have I…
zadjii-msft Mar 24, 2020
b3da428
Boy this is such a dirty hack but hey it works
zadjii-msft Mar 25, 2020
cf9d172
So very much code cleanup
zadjii-msft Mar 25, 2020
b5a6de3
Merge remote-tracking branch 'origin/master' into dev/migrie/b/979-hp…
zadjii-msft Mar 26, 2020
47f8591
runformat
zadjii-msft Mar 26, 2020
10cb133
Appease the spelling god?
zadjii-msft Mar 26, 2020
52c94dc
fix the SA build
zadjii-msft Mar 26, 2020
6e33a0f
this wasn't that scary
zadjii-msft Mar 27, 2020
c0ed7ea
this is a handy helper for converting between the two
zadjii-msft Mar 27, 2020
f3483c2
Some minor code cleanup to make things easier to read
zadjii-msft Mar 27, 2020
c7a1e77
some last changes for making events relative to the control origin
zadjii-msft Mar 27, 2020
0de39a7
good bot
zadjii-msft Mar 27, 2020
216941a
Merge remote-tracking branch 'origin/master' into dev/migrie/b/979-hp…
zadjii-msft Mar 30, 2020
8c3e284
Wrap these exceptions up
zadjii-msft Mar 30, 2020
ff021e0
This wasn't supposed to be on this branch
zadjii-msft Mar 30, 2020
10e7baa
Update src/cascadia/TerminalControl/TermControl.cpp
zadjii-msft Apr 1, 2020
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
2 changes: 1 addition & 1 deletion src/cascadia/TerminalControl/TermControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1193,7 +1193,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
}

// Method Description:
// - Actually handle a scrolling event, with from a mouse wheel or a
// - Actually handle a scrolling event, wether from a mouse wheel or a
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
// touchpad scroll. Depending upon what modifier keys are pressed,
// different actions will take place.
// * Attempts to first dispatch the mouse scroll as a VT event
Expand Down
3 changes: 2 additions & 1 deletion src/cascadia/TerminalCore/ControlKeyStates.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ class Microsoft::Terminal::Core::ControlKeyStates
}

#ifdef WINRT_Windows_System_H
ControlKeyStates(const winrt::Windows::System::VirtualKeyModifiers& modifiers) noexcept
ControlKeyStates(const winrt::Windows::System::VirtualKeyModifiers& modifiers) noexcept :
_value{ 0 }
{
// static_cast to a uint32_t because we can't use the WI_IsFlagSet
// macro directly with a VirtualKeyModifiers
Expand Down
25 changes: 15 additions & 10 deletions src/cascadia/WindowsTerminal/AppHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,18 +362,23 @@ void AppHost::_WindowMouseWheeled(const til::point coord, const int32_t delta)
// If that element has implemented IMouseWheelListener, call OnMouseWheel on that element.
if (auto control{ e.try_as<winrt::Microsoft::Terminal::TerminalControl::IMouseWheelListener>() })
{
// Translate the event to the coordinate space of the control
// we're attempting to dispatch it to
const auto transform = e.TransformToVisual(nullptr);
const auto controlOrigin = transform.TransformPoint(til::point{ 0, 0 });
const til::point offsetPoint{ ::base::ClampSub(coord.x(), controlOrigin.X), ::base::ClampSub(coord.y(), controlOrigin.Y) };

if (control.OnMouseWheel(offsetPoint, delta))
try
{
// If the element handled the mouse wheel event, don't
// continue to iterate over the remaining controls.
break;
// Translate the event to the coordinate space of the control
// we're attempting to dispatch it to
const auto transform = e.TransformToVisual(nullptr);
const til::point controlOrigin{ til::math::flooring, transform.TransformPoint(til::point{ 0, 0 }) };

const til::point offsetPoint = coord - controlOrigin;

if (control.OnMouseWheel(offsetPoint, delta))
{
// If the element handled the mouse wheel event, don't
// continue to iterate over the remaining controls.
break;
}
}
CATCH_LOG();
}
}
}
Expand Down
64 changes: 33 additions & 31 deletions src/cascadia/WindowsTerminal/IslandWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,37 +327,39 @@ void IslandWindow::OnSize(const UINT width, const UINT height)
return 0;
}
case WM_MOUSEWHEEL:
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
{
// This whole handler is a hack for GH#979.
//
// On some laptops, their trackpads won't scroll inactive windows
// _ever_. With our entire window just being one giant XAML Island, the
// touchpad driver thinks our entire window is inactive, and won't
// scroll the XAML island. On those types of laptops, we'll get a
// WM_MOUSEWHEEL here, in our root window, when the trackpad scrolls.
// We're going to take that message and manually plumb it through to our
// TermControl's, or anything else that implements IMouseWheelListener.

// https://msdn.microsoft.com/en-us/library/windows/desktop/ms645617(v=vs.85).aspx
// Important! Do not use the LOWORD or HIWORD macros to extract the x-
// and y- coordinates of the cursor position because these macros return
// incorrect results on systems with multiple monitors. Systems with
// multiple monitors can have negative x- and y- coordinates, and LOWORD
// and HIWORD treat the coordinates as unsigned quantities.
const til::point eventPoint{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) };
// This mouse event is relative to the display origin, not the window. Convert here.
const til::rectangle windowRect{ GetWindowRect() };
const auto origin = windowRect.origin();
const auto relative = eventPoint - origin;
// Convert to logical scaling before raising the event.
const auto real = relative / GetCurrentDpiScale();

const short wheelDelta = static_cast<short>(HIWORD(wparam));

// Raise an event, so any listeners can handle the mouse wheel event manually.
_MouseScrolledHandlers(real, wheelDelta);
return 0;
}
try
{
// This whole handler is a hack for GH#979.
//
// On some laptops, their trackpads won't scroll inactive windows
// _ever_. With our entire window just being one giant XAML Island, the
// touchpad driver thinks our entire window is inactive, and won't
// scroll the XAML island. On those types of laptops, we'll get a
// WM_MOUSEWHEEL here, in our root window, when the trackpad scrolls.
// We're going to take that message and manually plumb it through to our
// TermControl's, or anything else that implements IMouseWheelListener.

// https://msdn.microsoft.com/en-us/library/windows/desktop/ms645617(v=vs.85).aspx
// Important! Do not use the LOWORD or HIWORD macros to extract the x-
// and y- coordinates of the cursor position because these macros return
// incorrect results on systems with multiple monitors. Systems with
// multiple monitors can have negative x- and y- coordinates, and LOWORD
// and HIWORD treat the coordinates as unsigned quantities.
const til::point eventPoint{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) };
// This mouse event is relative to the display origin, not the window. Convert here.
const til::rectangle windowRect{ GetWindowRect() };
const auto origin = windowRect.origin();
const auto relative = eventPoint - origin;
// Convert to logical scaling before raising the event.
const auto real = relative / GetCurrentDpiScale();

const short wheelDelta = static_cast<short>(HIWORD(wparam));

// Raise an event, so any listeners can handle the mouse wheel event manually.
_MouseScrolledHandlers(real, wheelDelta);
return 0;
}
CATCH_LOG();
}

// TODO: handle messages here...
Expand Down
6 changes: 6 additions & 0 deletions src/inc/til/point.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
return point{ x, y };
}

point& operator/=(const point& other)
{
*this = *this / other;
return *this;
}

template<typename T>
point operator*(const T& scale) const
{
Expand Down
97 changes: 97 additions & 0 deletions src/til/ut_til/PointTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -710,4 +710,101 @@ class PointTests
VERIFY_ARE_EQUAL(expected, pt / scale);
}
}

template<typename T>
struct PointTypeWith_xy
{
T x, y;
};
template<typename T>
struct PointTypeWith_XY
{
T X, Y;
};
TEST_METHOD(CastFromFloatWithMathTypes)
{
PointTypeWith_xy<float> xyFloatIntegral{ 1.f, 2.f };
PointTypeWith_xy<float> xyFloat{ 1.6f, 2.4f };
PointTypeWith_XY<double> XYDoubleIntegral{ 3., 4. };
PointTypeWith_XY<double> XYDouble{ 3.6, 4.4 };
Log::Comment(L"0.) Ceiling");
{
{
til::point converted{ til::math::ceiling, xyFloatIntegral };
VERIFY_ARE_EQUAL((til::point{ 1, 2 }), converted);
}
{
til::point converted{ til::math::ceiling, xyFloat };
VERIFY_ARE_EQUAL((til::point{ 2, 3 }), converted);
}
{
til::point converted{ til::math::ceiling, XYDoubleIntegral };
VERIFY_ARE_EQUAL((til::point{ 3, 4 }), converted);
}
{
til::point converted{ til::math::ceiling, XYDouble };
VERIFY_ARE_EQUAL((til::point{ 4, 5 }), converted);
}
}

Log::Comment(L"1.) Flooring");
{
{
til::point converted{ til::math::flooring, xyFloatIntegral };
VERIFY_ARE_EQUAL((til::point{ 1, 2 }), converted);
}
{
til::point converted{ til::math::flooring, xyFloat };
VERIFY_ARE_EQUAL((til::point{ 1, 2 }), converted);
}
{
til::point converted{ til::math::flooring, XYDoubleIntegral };
VERIFY_ARE_EQUAL((til::point{ 3, 4 }), converted);
}
{
til::point converted{ til::math::flooring, XYDouble };
VERIFY_ARE_EQUAL((til::point{ 3, 4 }), converted);
}
}

Log::Comment(L"2.) Rounding");
{
{
til::point converted{ til::math::rounding, xyFloatIntegral };
VERIFY_ARE_EQUAL((til::point{ 1, 2 }), converted);
}
{
til::point converted{ til::math::rounding, xyFloat };
VERIFY_ARE_EQUAL((til::point{ 2, 2 }), converted);
}
{
til::point converted{ til::math::rounding, XYDoubleIntegral };
VERIFY_ARE_EQUAL((til::point{ 3, 4 }), converted);
}
{
til::point converted{ til::math::rounding, XYDouble };
VERIFY_ARE_EQUAL((til::point{ 4, 4 }), converted);
}
}

Log::Comment(L"3.) Truncating");
{
{
til::point converted{ til::math::truncating, xyFloatIntegral };
VERIFY_ARE_EQUAL((til::point{ 1, 2 }), converted);
}
{
til::point converted{ til::math::truncating, xyFloat };
VERIFY_ARE_EQUAL((til::point{ 1, 2 }), converted);
}
{
til::point converted{ til::math::truncating, XYDoubleIntegral };
VERIFY_ARE_EQUAL((til::point{ 3, 4 }), converted);
}
{
til::point converted{ til::math::truncating, XYDouble };
VERIFY_ARE_EQUAL((til::point{ 3, 4 }), converted);
}
}
}
};