Skip to content

Commit

Permalink
Windows: Add multi-touch support (flutter#27863)
Browse files Browse the repository at this point in the history
  • Loading branch information
jnschulze authored Aug 13, 2021
1 parent 8732428 commit 4b05f54
Show file tree
Hide file tree
Showing 17 changed files with 610 additions and 203 deletions.
3 changes: 3 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1662,6 +1662,9 @@ FILE: ../../../flutter/shell/platform/windows/platform_handler_win32.h
FILE: ../../../flutter/shell/platform/windows/platform_handler_winuwp.cc
FILE: ../../../flutter/shell/platform/windows/platform_handler_winuwp.h
FILE: ../../../flutter/shell/platform/windows/public/flutter_windows.h
FILE: ../../../flutter/shell/platform/windows/sequential_id_generator.cc
FILE: ../../../flutter/shell/platform/windows/sequential_id_generator.h
FILE: ../../../flutter/shell/platform/windows/sequential_id_generator_unittests.cc
FILE: ../../../flutter/shell/platform/windows/string_conversion.cc
FILE: ../../../flutter/shell/platform/windows/string_conversion.h
FILE: ../../../flutter/shell/platform/windows/string_conversion_unittests.cc
Expand Down
3 changes: 3 additions & 0 deletions shell/platform/windows/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ source_set("flutter_windows_source") {
"keyboard_key_handler.h",
"platform_handler.cc",
"platform_handler.h",
"sequential_id_generator.cc",
"sequential_id_generator.h",
"system_utils.h",
"task_runner.h",
"text_input_plugin.cc",
Expand Down Expand Up @@ -221,6 +223,7 @@ executable("flutter_windows_unittests") {
sources = [
# "flutter_project_bundle_unittests.cc", //TODO failing due to switches test failing. Blocked on https://github.com/flutter/flutter/issues/74153
# "flutter_windows_engine_unittests.cc", //TODO failing to send / receive platform message get plugins working first. Blocked on https://github.com/flutter/flutter/issues/74155
"sequential_id_generator_unittests.cc",
"string_conversion_unittests.cc",
"system_utils_unittests.cc",
"testing/engine_modifier.h",
Expand Down
54 changes: 26 additions & 28 deletions shell/platform/windows/flutter_window_win32.cc
Original file line number Diff line number Diff line change
Expand Up @@ -128,24 +128,6 @@ static uint64_t ConvertWinButtonToFlutterButton(UINT button) {
return 0;
}

// This method is only valid during a window message related to mouse/touch
// input.
// See
// https://docs.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages?redirectedfrom=MSDN#distinguishing-pen-input-from-mouse-and-touch.
static FlutterPointerDeviceKind GetFlutterPointerDeviceKind() {
constexpr LPARAM kTouchOrPenSignature = 0xFF515700;
constexpr LPARAM kTouchSignature = kTouchOrPenSignature | 0x80;
constexpr LPARAM kSignatureMask = 0xFFFFFF00;
LPARAM info = GetMessageExtraInfo();
if ((info & kSignatureMask) == kTouchOrPenSignature) {
if ((info & kTouchSignature) == kTouchSignature) {
return kFlutterPointerDeviceKindTouch;
}
return kFlutterPointerDeviceKindStylus;
}
return kFlutterPointerDeviceKindMouse;
}

void FlutterWindowWin32::OnDpiScale(unsigned int dpi){};

// When DesktopWindow notifies that a WM_Size message has come in
Expand All @@ -156,30 +138,42 @@ void FlutterWindowWin32::OnResize(unsigned int width, unsigned int height) {
}
}

void FlutterWindowWin32::OnPointerMove(double x, double y) {
binding_handler_delegate_->OnPointerMove(x, y, GetFlutterPointerDeviceKind());
void FlutterWindowWin32::OnPointerMove(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id) {
binding_handler_delegate_->OnPointerMove(x, y, device_kind, device_id);
}

void FlutterWindowWin32::OnPointerDown(double x, double y, UINT button) {
void FlutterWindowWin32::OnPointerDown(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id,
UINT button) {
uint64_t flutter_button = ConvertWinButtonToFlutterButton(button);
if (flutter_button != 0) {
binding_handler_delegate_->OnPointerDown(
x, y, GetFlutterPointerDeviceKind(),
x, y, device_kind, device_id,
static_cast<FlutterPointerMouseButtons>(flutter_button));
}
}

void FlutterWindowWin32::OnPointerUp(double x, double y, UINT button) {
void FlutterWindowWin32::OnPointerUp(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id,
UINT button) {
uint64_t flutter_button = ConvertWinButtonToFlutterButton(button);
if (flutter_button != 0) {
binding_handler_delegate_->OnPointerUp(
x, y, GetFlutterPointerDeviceKind(),
x, y, device_kind, device_id,
static_cast<FlutterPointerMouseButtons>(flutter_button));
}
}

void FlutterWindowWin32::OnPointerLeave() {
binding_handler_delegate_->OnPointerLeave(GetFlutterPointerDeviceKind());
void FlutterWindowWin32::OnPointerLeave(FlutterPointerDeviceKind device_kind,
int32_t device_id) {
binding_handler_delegate_->OnPointerLeave(device_kind, device_id);
}

void FlutterWindowWin32::OnSetCursor() {
Expand Down Expand Up @@ -217,13 +211,17 @@ void FlutterWindowWin32::OnComposeChange(const std::u16string& text,
binding_handler_delegate_->OnComposeChange(text, cursor_pos);
}

void FlutterWindowWin32::OnScroll(double delta_x, double delta_y) {
void FlutterWindowWin32::OnScroll(double delta_x,
double delta_y,
FlutterPointerDeviceKind device_kind,
int32_t device_id) {
POINT point;
GetCursorPos(&point);

ScreenToClient(GetWindowHandle(), &point);
binding_handler_delegate_->OnScroll(point.x, point.y, delta_x, delta_y,
kScrollOffsetMultiplier);
kScrollOffsetMultiplier, device_kind,
device_id);
}

void FlutterWindowWin32::OnCursorRectUpdated(const Rect& rect) {
Expand Down
25 changes: 20 additions & 5 deletions shell/platform/windows/flutter_window_win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,28 @@ class FlutterWindowWin32 : public WindowWin32, public WindowBindingHandler {
void OnResize(unsigned int width, unsigned int height) override;

// |WindowWin32|
void OnPointerMove(double x, double y) override;
void OnPointerMove(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id) override;

// |WindowWin32|
void OnPointerDown(double x, double y, UINT button) override;
void OnPointerDown(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id,
UINT button) override;

// |WindowWin32|
void OnPointerUp(double x, double y, UINT button) override;
void OnPointerUp(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id,
UINT button) override;

// |WindowWin32|
void OnPointerLeave() override;
void OnPointerLeave(FlutterPointerDeviceKind device_kind,
int32_t device_id) override;

// |WindowWin32|
void OnSetCursor() override;
Expand Down Expand Up @@ -78,7 +90,10 @@ class FlutterWindowWin32 : public WindowWin32, public WindowBindingHandler {
void OnCursorRectUpdated(const Rect& rect) override;

// |WindowWin32|
void OnScroll(double delta_x, double delta_y) override;
void OnScroll(double delta_x,
double delta_y,
FlutterPointerDeviceKind device_kind,
int32_t device_id) override;

// |FlutterWindowBindingHandler|
void SetView(WindowBindingHandlerDelegate* view) override;
Expand Down
118 changes: 76 additions & 42 deletions shell/platform/windows/flutter_window_win32_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace flutter {
namespace testing {

namespace {
static constexpr int32_t kDefaultPointerDeviceId = 0;

// A key event handler that can be spied on while it forwards calls to the real
// key event handler.
Expand Down Expand Up @@ -141,12 +142,16 @@ class MockFlutterWindowWin32 : public FlutterWindowWin32,

MOCK_METHOD1(OnDpiScale, void(unsigned int));
MOCK_METHOD2(OnResize, void(unsigned int, unsigned int));
MOCK_METHOD2(OnPointerMove, void(double, double));
MOCK_METHOD3(OnPointerDown, void(double, double, UINT));
MOCK_METHOD3(OnPointerUp, void(double, double, UINT));
MOCK_METHOD0(OnPointerLeave, void());
MOCK_METHOD4(OnPointerMove,
void(double, double, FlutterPointerDeviceKind, int32_t));
MOCK_METHOD5(OnPointerDown,
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_METHOD0(OnSetCursor, void());
MOCK_METHOD2(OnScroll, void(double, double));
MOCK_METHOD4(OnScroll,
void(double, double, FlutterPointerDeviceKind, int32_t));
MOCK_METHOD0(GetDpiScale, float());
MOCK_METHOD0(IsVisible, bool());
MOCK_METHOD1(UpdateCursorRect, void(const Rect&));
Expand Down Expand Up @@ -188,25 +193,35 @@ class MockWindowBindingHandlerDelegate : public WindowBindingHandlerDelegate {
MockWindowBindingHandlerDelegate const&) = delete;

MOCK_METHOD2(OnWindowSizeChanged, void(size_t, size_t));
MOCK_METHOD3(OnPointerMove, void(double, double, FlutterPointerDeviceKind));
MOCK_METHOD4(OnPointerDown,
MOCK_METHOD4(OnPointerMove,
void(double, double, FlutterPointerDeviceKind, int32_t));
MOCK_METHOD5(OnPointerDown,
void(double,
double,
FlutterPointerDeviceKind,
int32_t,
FlutterPointerMouseButtons));
MOCK_METHOD4(OnPointerUp,
MOCK_METHOD5(OnPointerUp,
void(double,
double,
FlutterPointerDeviceKind,
int32_t,
FlutterPointerMouseButtons));
MOCK_METHOD1(OnPointerLeave, void(FlutterPointerDeviceKind));
MOCK_METHOD2(OnPointerLeave, void(FlutterPointerDeviceKind, int32_t));
MOCK_METHOD1(OnText, void(const std::u16string&));
MOCK_METHOD6(OnKey, bool(int, int, int, char32_t, bool, bool));
MOCK_METHOD0(OnComposeBegin, void());
MOCK_METHOD0(OnComposeCommit, void());
MOCK_METHOD0(OnComposeEnd, void());
MOCK_METHOD2(OnComposeChange, void(const std::u16string&, int));
MOCK_METHOD5(OnScroll, void(double, double, double, double, int));
MOCK_METHOD7(OnScroll,
void(double,
double,
double,
double,
int,
FlutterPointerDeviceKind,
int32_t));
};

// A FlutterWindowsView that overrides the RegisterKeyboardHandlers function
Expand Down Expand Up @@ -517,69 +532,88 @@ TEST(FlutterWindowWin32Test, OnPointerStarSendsDeviceType) {
win32window.SetView(&delegate);
// Move
EXPECT_CALL(delegate,
OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindMouse))
OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindMouse,
kDefaultPointerDeviceId))
.Times(1);
EXPECT_CALL(delegate,
OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindTouch))
OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindTouch,
kDefaultPointerDeviceId))
.Times(1);
EXPECT_CALL(delegate,
OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindStylus))
OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindStylus,
kDefaultPointerDeviceId))
.Times(1);

// Down
EXPECT_CALL(delegate,
OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindMouse,
kFlutterPointerButtonMousePrimary))
EXPECT_CALL(
delegate,
OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindMouse,
kDefaultPointerDeviceId, kFlutterPointerButtonMousePrimary))
.Times(1);
EXPECT_CALL(delegate,
OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindTouch,
kFlutterPointerButtonMousePrimary))
EXPECT_CALL(
delegate,
OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindTouch,
kDefaultPointerDeviceId, kFlutterPointerButtonMousePrimary))
.Times(1);
EXPECT_CALL(delegate,
OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindStylus,
kFlutterPointerButtonMousePrimary))
EXPECT_CALL(
delegate,
OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindStylus,
kDefaultPointerDeviceId, kFlutterPointerButtonMousePrimary))
.Times(1);

// Up
EXPECT_CALL(delegate, OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindMouse,
kDefaultPointerDeviceId,
kFlutterPointerButtonMousePrimary))
.Times(1);
EXPECT_CALL(delegate, OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindTouch,
kDefaultPointerDeviceId,
kFlutterPointerButtonMousePrimary))
.Times(1);
EXPECT_CALL(delegate, OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindStylus,
kDefaultPointerDeviceId,
kFlutterPointerButtonMousePrimary))
.Times(1);

// Leave
EXPECT_CALL(delegate, OnPointerLeave(kFlutterPointerDeviceKindMouse))
EXPECT_CALL(delegate, OnPointerLeave(kFlutterPointerDeviceKindMouse,
kDefaultPointerDeviceId))
.Times(1);
EXPECT_CALL(delegate, OnPointerLeave(kFlutterPointerDeviceKindTouch))
EXPECT_CALL(delegate, OnPointerLeave(kFlutterPointerDeviceKindTouch,
kDefaultPointerDeviceId))
.Times(1);
EXPECT_CALL(delegate, OnPointerLeave(kFlutterPointerDeviceKindStylus))
EXPECT_CALL(delegate, OnPointerLeave(kFlutterPointerDeviceKindStylus,
kDefaultPointerDeviceId))
.Times(1);

win32window.OnPointerMove(10.0, 10.0);
win32window.OnPointerDown(10.0, 10.0, WM_LBUTTONDOWN);
win32window.OnPointerUp(10.0, 10.0, WM_LBUTTONDOWN);
win32window.OnPointerLeave();
win32window.OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindMouse,
kDefaultPointerDeviceId);
win32window.OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindMouse,
kDefaultPointerDeviceId, WM_LBUTTONDOWN);
win32window.OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindMouse,
kDefaultPointerDeviceId, WM_LBUTTONDOWN);
win32window.OnPointerLeave(kFlutterPointerDeviceKindMouse,
kDefaultPointerDeviceId);

// Touch
LPARAM original_lparam = SetMessageExtraInfo(0xFF51578b);
win32window.OnPointerMove(10.0, 10.0);
win32window.OnPointerDown(10.0, 10.0, WM_LBUTTONDOWN);
win32window.OnPointerUp(10.0, 10.0, WM_LBUTTONDOWN);
win32window.OnPointerLeave();
win32window.OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindTouch,
kDefaultPointerDeviceId);
win32window.OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindTouch,
kDefaultPointerDeviceId, WM_LBUTTONDOWN);
win32window.OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindTouch,
kDefaultPointerDeviceId, WM_LBUTTONDOWN);
win32window.OnPointerLeave(kFlutterPointerDeviceKindTouch,
kDefaultPointerDeviceId);

// Pen
SetMessageExtraInfo(0xFF515700);
win32window.OnPointerMove(10.0, 10.0);
win32window.OnPointerDown(10.0, 10.0, WM_LBUTTONDOWN);
win32window.OnPointerUp(10.0, 10.0, WM_LBUTTONDOWN);
win32window.OnPointerLeave();

// Reset extra info for other tests.
SetMessageExtraInfo(original_lparam);
win32window.OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindStylus,
kDefaultPointerDeviceId);
win32window.OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindStylus,
kDefaultPointerDeviceId, WM_LBUTTONDOWN);
win32window.OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindStylus,
kDefaultPointerDeviceId, WM_LBUTTONDOWN);
win32window.OnPointerLeave(kFlutterPointerDeviceKindStylus,
kDefaultPointerDeviceId);
}

} // namespace testing
Expand Down
Loading

0 comments on commit 4b05f54

Please sign in to comment.