diff --git a/engine/src/flutter/shell/platform/windows/flutter_window_win32.cc b/engine/src/flutter/shell/platform/windows/flutter_window_win32.cc index 15c87d6ed70..6943f59c9fe 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_window_win32.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_window_win32.cc @@ -171,9 +171,11 @@ void FlutterWindowWin32::OnPointerUp(double x, } } -void FlutterWindowWin32::OnPointerLeave(FlutterPointerDeviceKind device_kind, +void FlutterWindowWin32::OnPointerLeave(double x, + double y, + FlutterPointerDeviceKind device_kind, int32_t device_id) { - binding_handler_delegate_->OnPointerLeave(device_kind, device_id); + binding_handler_delegate_->OnPointerLeave(x, y, device_kind, device_id); } void FlutterWindowWin32::OnSetCursor() { diff --git a/engine/src/flutter/shell/platform/windows/flutter_window_win32.h b/engine/src/flutter/shell/platform/windows/flutter_window_win32.h index fdcd2740298..dff83aac789 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_window_win32.h +++ b/engine/src/flutter/shell/platform/windows/flutter_window_win32.h @@ -57,7 +57,9 @@ class FlutterWindowWin32 : public WindowWin32, public WindowBindingHandler { UINT button) override; // |WindowWin32| - void OnPointerLeave(FlutterPointerDeviceKind device_kind, + void OnPointerLeave(double x, + double y, + FlutterPointerDeviceKind device_kind, int32_t device_id) override; // |WindowWin32| diff --git a/engine/src/flutter/shell/platform/windows/flutter_window_win32_unittests.cc b/engine/src/flutter/shell/platform/windows/flutter_window_win32_unittests.cc index 549a9d09be8..62b90d01255 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_window_win32_unittests.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_window_win32_unittests.cc @@ -116,7 +116,8 @@ class MockFlutterWindowWin32 : public FlutterWindowWin32 { void(double, double, FlutterPointerDeviceKind, int32_t, UINT)); MOCK_METHOD5(OnPointerUp, void(double, double, FlutterPointerDeviceKind, int32_t, UINT)); - MOCK_METHOD2(OnPointerLeave, void(FlutterPointerDeviceKind, int32_t)); + MOCK_METHOD4(OnPointerLeave, + void(double, double, FlutterPointerDeviceKind, int32_t)); MOCK_METHOD0(OnSetCursor, void()); MOCK_METHOD4(OnScroll, void(double, double, FlutterPointerDeviceKind, int32_t)); @@ -163,7 +164,8 @@ class MockWindowBindingHandlerDelegate : public WindowBindingHandlerDelegate { FlutterPointerDeviceKind, int32_t, FlutterPointerMouseButtons)); - MOCK_METHOD2(OnPointerLeave, void(FlutterPointerDeviceKind, int32_t)); + MOCK_METHOD4(OnPointerLeave, + void(double, double, FlutterPointerDeviceKind, int32_t)); MOCK_METHOD1(OnText, void(const std::u16string&)); MOCK_METHOD7(OnKey, void(int, int, int, char32_t, bool, bool, KeyEventCallback)); @@ -328,14 +330,17 @@ TEST(FlutterWindowWin32Test, OnPointerStarSendsDeviceType) { .Times(1); // Leave - EXPECT_CALL(delegate, OnPointerLeave(kFlutterPointerDeviceKindMouse, - kDefaultPointerDeviceId)) + EXPECT_CALL(delegate, + OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindMouse, + kDefaultPointerDeviceId)) .Times(1); - EXPECT_CALL(delegate, OnPointerLeave(kFlutterPointerDeviceKindTouch, - kDefaultPointerDeviceId)) + EXPECT_CALL(delegate, + OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindTouch, + kDefaultPointerDeviceId)) .Times(1); - EXPECT_CALL(delegate, OnPointerLeave(kFlutterPointerDeviceKindStylus, - kDefaultPointerDeviceId)) + EXPECT_CALL(delegate, + OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindStylus, + kDefaultPointerDeviceId)) .Times(1); win32window.OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindMouse, @@ -344,7 +349,7 @@ TEST(FlutterWindowWin32Test, OnPointerStarSendsDeviceType) { kDefaultPointerDeviceId, WM_LBUTTONDOWN); win32window.OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindMouse, kDefaultPointerDeviceId, WM_LBUTTONDOWN); - win32window.OnPointerLeave(kFlutterPointerDeviceKindMouse, + win32window.OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindMouse, kDefaultPointerDeviceId); // Touch @@ -354,7 +359,7 @@ TEST(FlutterWindowWin32Test, OnPointerStarSendsDeviceType) { kDefaultPointerDeviceId, WM_LBUTTONDOWN); win32window.OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindTouch, kDefaultPointerDeviceId, WM_LBUTTONDOWN); - win32window.OnPointerLeave(kFlutterPointerDeviceKindTouch, + win32window.OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindTouch, kDefaultPointerDeviceId); // Pen @@ -364,7 +369,7 @@ TEST(FlutterWindowWin32Test, OnPointerStarSendsDeviceType) { kDefaultPointerDeviceId, WM_LBUTTONDOWN); win32window.OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindStylus, kDefaultPointerDeviceId, WM_LBUTTONDOWN); - win32window.OnPointerLeave(kFlutterPointerDeviceKindStylus, + win32window.OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindStylus, kDefaultPointerDeviceId); } diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_view.cc b/engine/src/flutter/shell/platform/windows/flutter_windows_view.cc index 0e5e5541e55..baf9389e541 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_view.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_view.cc @@ -196,9 +196,11 @@ void FlutterWindowsView::OnPointerUp( } } -void FlutterWindowsView::OnPointerLeave(FlutterPointerDeviceKind device_kind, +void FlutterWindowsView::OnPointerLeave(double x, + double y, + FlutterPointerDeviceKind device_kind, int32_t device_id) { - SendPointerLeave(GetOrCreatePointerState(device_kind, device_id)); + SendPointerLeave(x, y, GetOrCreatePointerState(device_kind, device_id)); } void FlutterWindowsView::OnText(const std::u16string& text) { @@ -369,8 +371,12 @@ void FlutterWindowsView::SendPointerUp(double x, } } -void FlutterWindowsView::SendPointerLeave(PointerState* state) { +void FlutterWindowsView::SendPointerLeave(double x, + double y, + PointerState* state) { FlutterPointerEvent event = {}; + event.x = x; + event.y = y; event.phase = FlutterPointerPhase::kRemove; SendPointerEventWithData(event, state); } diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_view.h b/engine/src/flutter/shell/platform/windows/flutter_windows_view.h index 51a4a6ca2bb..33da447b7d2 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_view.h +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_view.h @@ -120,7 +120,9 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate, FlutterPointerMouseButtons button) override; // |WindowBindingHandlerDelegate| - void OnPointerLeave(FlutterPointerDeviceKind device_kind, + void OnPointerLeave(double x, + double y, + FlutterPointerDeviceKind device_kind, int32_t device_id = 0) override; // |WindowBindingHandlerDelegate| @@ -243,7 +245,7 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate, // Win32 api doesn't have "mouse enter" event. Therefore, there is no // SendPointerEnter method. A mouse enter event is tracked then the "move" // event is called. - void SendPointerLeave(PointerState* state); + void SendPointerLeave(double x, double y, PointerState* state); // Reports a keyboard character to Flutter engine. void SendText(const std::u16string&); diff --git a/engine/src/flutter/shell/platform/windows/testing/mock_window_win32.h b/engine/src/flutter/shell/platform/windows/testing/mock_window_win32.h index 2bc1991f2f3..cfd7bac65c3 100644 --- a/engine/src/flutter/shell/platform/windows/testing/mock_window_win32.h +++ b/engine/src/flutter/shell/platform/windows/testing/mock_window_win32.h @@ -43,7 +43,8 @@ class MockWin32Window : public WindowWin32 { void(double, double, FlutterPointerDeviceKind, int32_t, UINT)); MOCK_METHOD5(OnPointerUp, void(double, double, FlutterPointerDeviceKind, int32_t, UINT)); - MOCK_METHOD2(OnPointerLeave, void(FlutterPointerDeviceKind, int32_t)); + MOCK_METHOD4(OnPointerLeave, + void(double, double, FlutterPointerDeviceKind, int32_t)); MOCK_METHOD0(OnSetCursor, void()); MOCK_METHOD1(OnText, void(const std::u16string&)); MOCK_METHOD7(OnKey, diff --git a/engine/src/flutter/shell/platform/windows/window_binding_handler_delegate.h b/engine/src/flutter/shell/platform/windows/window_binding_handler_delegate.h index 1f971ce1510..b69d8a6369c 100644 --- a/engine/src/flutter/shell/platform/windows/window_binding_handler_delegate.h +++ b/engine/src/flutter/shell/platform/windows/window_binding_handler_delegate.h @@ -47,7 +47,9 @@ class WindowBindingHandlerDelegate { // Notifies delegate that backing window mouse pointer has left the window. // Typically called by currently configured WindowBindingHandler - virtual void OnPointerLeave(FlutterPointerDeviceKind device_kind, + virtual void OnPointerLeave(double x, + double y, + FlutterPointerDeviceKind device_kind, int32_t device_id) = 0; // Notifies delegate that backing window has received text. diff --git a/engine/src/flutter/shell/platform/windows/window_win32.cc b/engine/src/flutter/shell/platform/windows/window_win32.cc index d3a8ecf134c..0240137f9bb 100644 --- a/engine/src/flutter/shell/platform/windows/window_win32.cc +++ b/engine/src/flutter/shell/platform/windows/window_win32.cc @@ -332,7 +332,7 @@ WindowWin32::HandleMessage(UINT const message, } else if (touch.dwFlags & TOUCHEVENTF_UP) { OnPointerUp(x, y, kFlutterPointerDeviceKindTouch, touch_id, WM_LBUTTONDOWN); - OnPointerLeave(kFlutterPointerDeviceKindTouch, touch_id); + OnPointerLeave(x, y, kFlutterPointerDeviceKindTouch, touch_id); touch_id_generator_.ReleaseNumber(touch.dwID); } } @@ -347,15 +347,17 @@ WindowWin32::HandleMessage(UINT const message, xPos = GET_X_LPARAM(lparam); yPos = GET_Y_LPARAM(lparam); + mouse_x_ = static_cast(xPos); + mouse_y_ = static_cast(yPos); - OnPointerMove(static_cast(xPos), static_cast(yPos), - device_kind, kDefaultPointerDeviceId); + OnPointerMove(mouse_x_, mouse_y_, device_kind, kDefaultPointerDeviceId); } break; case WM_MOUSELEAVE: device_kind = GetFlutterPointerDeviceKind(); if (device_kind == kFlutterPointerDeviceKindMouse) { - OnPointerLeave(device_kind, kDefaultPointerDeviceId); + OnPointerLeave(mouse_x_, mouse_y_, device_kind, + kDefaultPointerDeviceId); } // Once the tracked event is received, the TrackMouseEvent function diff --git a/engine/src/flutter/shell/platform/windows/window_win32.h b/engine/src/flutter/shell/platform/windows/window_win32.h index 4c30275fcf3..ee916879874 100644 --- a/engine/src/flutter/shell/platform/windows/window_win32.h +++ b/engine/src/flutter/shell/platform/windows/window_win32.h @@ -118,7 +118,9 @@ class WindowWin32 : public KeyboardManagerWin32::WindowDelegate { UINT button) = 0; // Called when the mouse leaves the window. - virtual void OnPointerLeave(FlutterPointerDeviceKind device_kind, + virtual void OnPointerLeave(double x, + double y, + FlutterPointerDeviceKind device_kind, int32_t device_id) = 0; // Called when the cursor should be set for the client area. @@ -243,6 +245,10 @@ class WindowWin32 : public KeyboardManagerWin32::WindowDelegate { // message. int keycode_for_char_message_ = 0; + // Keeps track of the last mouse coordinates by a WM_MOUSEMOVE message. + double mouse_x_ = 0; + double mouse_y_ = 0; + // Manages IME state. std::unique_ptr text_input_manager_; diff --git a/engine/src/flutter/shell/platform/windows/window_win32_unittests.cc b/engine/src/flutter/shell/platform/windows/window_win32_unittests.cc index fe16edd77d1..e3bb83c48a5 100644 --- a/engine/src/flutter/shell/platform/windows/window_win32_unittests.cc +++ b/engine/src/flutter/shell/platform/windows/window_win32_unittests.cc @@ -143,6 +143,22 @@ TEST(MockWin32Window, HorizontalScroll) { window.InjectWindowMessage(WM_MOUSEHWHEEL, MAKEWPARAM(0, scroll_amount), 0); } +TEST(MockWin32Window, MouseLeave) { + MockWin32Window window; + const double mouse_x = 10.0; + const double mouse_y = 20.0; + + EXPECT_CALL(window, OnPointerMove(mouse_x, mouse_y, + kFlutterPointerDeviceKindMouse, 0)) + .Times(1); + EXPECT_CALL(window, OnPointerLeave(mouse_x, mouse_y, + kFlutterPointerDeviceKindMouse, 0)) + .Times(1); + + window.InjectWindowMessage(WM_MOUSEMOVE, 0, MAKELPARAM(mouse_x, mouse_y)); + window.InjectWindowMessage(WM_MOUSELEAVE, 0, 0); +} + TEST(MockWin32Window, KeyDown) { MockWin32Window window; EXPECT_CALL(window, OnKey(_, _, _, _, _, _, _)).Times(1);