未验证 提交 4b05f544 编写于 作者: N Niklas Schulze 提交者: GitHub

Windows: Add multi-touch support (#27863)

上级 87324283
......@@ -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
......
......@@ -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",
......@@ -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",
......
......@@ -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
......@@ -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() {
......@@ -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) {
......
......@@ -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;
......@@ -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;
......
......@@ -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.
......@@ -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&));
......@@ -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
......@@ -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
......
......@@ -9,6 +9,11 @@ namespace flutter {
// Multipler used to map controller velocity to an appropriate scroll input.
static constexpr double kControllerScrollMultiplier = 3;
// TODO(clarkezone): Determine pointer ID in
// OnPointerPressed/OnPointerReleased/OnPointerMoved in order to support multi
// touch. See https://github.com/flutter/flutter/issues/70201
static constexpr int32_t kDefaultPointerDeviceId = 0;
FlutterWindowWinUWP::FlutterWindowWinUWP(
ABI::Windows::ApplicationModel::Core::CoreApplicationView*
applicationview) {
......@@ -146,7 +151,7 @@ void FlutterWindowWinUWP::OnPointerPressed(
FlutterPointerDeviceKind device_kind = GetPointerDeviceKind(args);
binding_handler_delegate_->OnPointerDown(
x, y, device_kind,
x, y, device_kind, kDefaultPointerDeviceId,
FlutterPointerMouseButtons::kFlutterPointerButtonMousePrimary);
}
......@@ -158,7 +163,7 @@ void FlutterWindowWinUWP::OnPointerReleased(
FlutterPointerDeviceKind device_kind = GetPointerDeviceKind(args);
binding_handler_delegate_->OnPointerUp(
x, y, device_kind,
x, y, device_kind, kDefaultPointerDeviceId,
FlutterPointerMouseButtons::kFlutterPointerButtonMousePrimary);
}
......@@ -169,7 +174,8 @@ void FlutterWindowWinUWP::OnPointerMoved(
double y = GetPosY(args);
FlutterPointerDeviceKind device_kind = GetPointerDeviceKind(args);
binding_handler_delegate_->OnPointerMove(x, y, device_kind);
binding_handler_delegate_->OnPointerMove(x, y, device_kind,
kDefaultPointerDeviceId);
}
void FlutterWindowWinUWP::OnPointerWheelChanged(
......@@ -177,8 +183,10 @@ void FlutterWindowWinUWP::OnPointerWheelChanged(
winrt::Windows::UI::Core::PointerEventArgs const& args) {
double x = GetPosX(args);
double y = GetPosY(args);
FlutterPointerDeviceKind device_kind = GetPointerDeviceKind(args);
int delta = args.CurrentPoint().Properties().MouseWheelDelta();
binding_handler_delegate_->OnScroll(x, y, 0, -delta, 1);
binding_handler_delegate_->OnScroll(x, y, 0, -delta, 1, device_kind,
kDefaultPointerDeviceId);
}
double FlutterWindowWinUWP::GetPosX(
......
......@@ -172,19 +172,21 @@ void FlutterWindowsView::OnWindowSizeChanged(size_t width, size_t height) {
void FlutterWindowsView::OnPointerMove(double x,
double y,
FlutterPointerDeviceKind device_kind) {
SendPointerMove(x, y, device_kind);
FlutterPointerDeviceKind device_kind,
int32_t device_id) {
SendPointerMove(x, y, GetOrCreatePointerState(device_kind, device_id));
}
void FlutterWindowsView::OnPointerDown(
double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id,
FlutterPointerMouseButtons flutter_button) {
if (flutter_button != 0) {
uint64_t mouse_buttons = mouse_state_.buttons | flutter_button;
SetMouseButtons(mouse_buttons);
SendPointerDown(x, y, device_kind);
auto state = GetOrCreatePointerState(device_kind, device_id);
state->buttons |= flutter_button;
SendPointerDown(x, y, state);
}
}
......@@ -192,16 +194,18 @@ void FlutterWindowsView::OnPointerUp(
double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id,
FlutterPointerMouseButtons flutter_button) {
if (flutter_button != 0) {
uint64_t mouse_buttons = mouse_state_.buttons & ~flutter_button;
SetMouseButtons(mouse_buttons);
SendPointerUp(x, y, device_kind);
auto state = GetOrCreatePointerState(device_kind, device_id);
state->buttons &= ~flutter_button;
SendPointerUp(x, y, state);
}
}
void FlutterWindowsView::OnPointerLeave(FlutterPointerDeviceKind device_kind) {
SendPointerLeave(device_kind);
void FlutterWindowsView::OnPointerLeave(FlutterPointerDeviceKind device_kind,
int32_t device_id) {
SendPointerLeave(GetOrCreatePointerState(device_kind, device_id));
}
void FlutterWindowsView::OnText(const std::u16string& text) {
......@@ -238,8 +242,11 @@ void FlutterWindowsView::OnScroll(double x,
double y,
double delta_x,
double delta_y,
int scroll_offset_multiplier) {
SendScroll(x, y, delta_x, delta_y, scroll_offset_multiplier);
int scroll_offset_multiplier,
FlutterPointerDeviceKind device_kind,
int32_t device_id) {
SendScroll(x, y, delta_x, delta_y, scroll_offset_multiplier, device_kind,
device_id);
}
void FlutterWindowsView::OnCursorRectUpdated(const Rect& rect) {
......@@ -265,18 +272,38 @@ void FlutterWindowsView::SendInitialBounds() {
binding_handler_->GetDpiScale());
}
FlutterWindowsView::PointerState* FlutterWindowsView::GetOrCreatePointerState(
FlutterPointerDeviceKind device_kind,
int32_t device_id) {
// Create a virtual pointer ID that is unique across all device types
// to prevent pointers from clashing in the engine's converter
// (lib/ui/window/pointer_data_packet_converter.cc)
int32_t pointer_id = (static_cast<int32_t>(device_kind) << 28) | device_id;
auto [it, added] = pointer_states_.try_emplace(pointer_id, nullptr);
if (added) {
auto state = std::make_unique<PointerState>();
state->device_kind = device_kind;
state->pointer_id = pointer_id;
it->second = std::move(state);
}
return it->second.get();
}
// Set's |event_data|'s phase to either kMove or kHover depending on the current
// primary mouse button state.
void FlutterWindowsView::SetEventPhaseFromCursorButtonState(
FlutterPointerEvent* event_data) const {
FlutterPointerEvent* event_data,
const PointerState* state) const {
// For details about this logic, see FlutterPointerPhase in the embedder.h
// file.
if (mouse_state_.buttons == 0) {
event_data->phase = mouse_state_.flutter_state_is_down
if (state->buttons == 0) {
event_data->phase = state->flutter_state_is_down
? FlutterPointerPhase::kUp
: FlutterPointerPhase::kHover;
} else {
event_data->phase = mouse_state_.flutter_state_is_down
event_data->phase = state->flutter_state_is_down
? FlutterPointerPhase::kMove
: FlutterPointerPhase::kDown;
}
......@@ -284,47 +311,46 @@ void FlutterWindowsView::SetEventPhaseFromCursorButtonState(
void FlutterWindowsView::SendPointerMove(double x,
double y,
FlutterPointerDeviceKind device_kind) {
PointerState* state) {
FlutterPointerEvent event = {};
event.x = x;
event.y = y;
event.device_kind = device_kind;
SetEventPhaseFromCursorButtonState(&event);
SendPointerEventWithData(event);
SetEventPhaseFromCursorButtonState(&event, state);
SendPointerEventWithData(event, state);
}
void FlutterWindowsView::SendPointerDown(double x,
double y,
FlutterPointerDeviceKind device_kind) {
PointerState* state) {
FlutterPointerEvent event = {};
SetEventPhaseFromCursorButtonState(&event);
event.x = x;
event.y = y;
event.device_kind = device_kind;
SendPointerEventWithData(event);
SetMouseFlutterStateDown(true);
SetEventPhaseFromCursorButtonState(&event, state);
SendPointerEventWithData(event, state);
state->flutter_state_is_down = true;
}
void FlutterWindowsView::SendPointerUp(double x,
double y,
FlutterPointerDeviceKind device_kind) {
PointerState* state) {
FlutterPointerEvent event = {};
SetEventPhaseFromCursorButtonState(&event);
event.x = x;
event.y = y;
event.device_kind = device_kind;
SendPointerEventWithData(event);
SetEventPhaseFromCursorButtonState(&event, state);
SendPointerEventWithData(event, state);
if (event.phase == FlutterPointerPhase::kUp) {
SetMouseFlutterStateDown(false);
state->flutter_state_is_down = false;
}
}
void FlutterWindowsView::SendPointerLeave(
FlutterPointerDeviceKind device_kind) {
void FlutterWindowsView::SendPointerLeave(PointerState* state) {
FlutterPointerEvent event = {};
event.device_kind = device_kind;
event.phase = FlutterPointerPhase::kRemove;
SendPointerEventWithData(event);
SendPointerEventWithData(event, state);
}
void FlutterWindowsView::SendText(const std::u16string& text) {
......@@ -378,39 +404,47 @@ void FlutterWindowsView::SendScroll(double x,
double y,
double delta_x,
double delta_y,
int scroll_offset_multiplier) {
int scroll_offset_multiplier,
FlutterPointerDeviceKind device_kind,
int32_t device_id) {
auto state = GetOrCreatePointerState(device_kind, device_id);
FlutterPointerEvent event = {};
SetEventPhaseFromCursorButtonState(&event);
event.signal_kind = FlutterPointerSignalKind::kFlutterPointerSignalKindScroll;
event.x = x;
event.y = y;
event.signal_kind = FlutterPointerSignalKind::kFlutterPointerSignalKindScroll;
event.scroll_delta_x = delta_x * scroll_offset_multiplier;
event.scroll_delta_y = delta_y * scroll_offset_multiplier;
SendPointerEventWithData(event);
SetEventPhaseFromCursorButtonState(&event, state);
SendPointerEventWithData(event, state);
}
void FlutterWindowsView::SendPointerEventWithData(
const FlutterPointerEvent& event_data) {
const FlutterPointerEvent& event_data,
PointerState* state) {
// If sending anything other than an add, and the pointer isn't already added,
// synthesize an add to satisfy Flutter's expectations about events.
if (!mouse_state_.flutter_state_is_added &&
if (!state->flutter_state_is_added &&
event_data.phase != FlutterPointerPhase::kAdd) {
FlutterPointerEvent event = {};
event.phase = FlutterPointerPhase::kAdd;
event.x = event_data.x;
event.y = event_data.y;
event.buttons = 0;
SendPointerEventWithData(event);
SendPointerEventWithData(event, state);
}
// Don't double-add (e.g., if events are delivered out of order, so an add has
// already been synthesized).
if (mouse_state_.flutter_state_is_added &&
if (state->flutter_state_is_added &&
event_data.phase == FlutterPointerPhase::kAdd) {
return;
}
FlutterPointerEvent event = event_data;
event.buttons = mouse_state_.buttons;
event.device_kind = state->device_kind;
event.device = state->pointer_id;
event.buttons = state->buttons;
// Set metadata that's always the same regardless of the event.
event.struct_size = sizeof(event);
......@@ -422,10 +456,12 @@ void FlutterWindowsView::SendPointerEventWithData(
engine_->SendPointerEvent(event);
if (event_data.phase == FlutterPointerPhase::kAdd) {
SetMouseFlutterStateAdded(true);
state->flutter_state_is_added = true;
} else if (event_data.phase == FlutterPointerPhase::kRemove) {
SetMouseFlutterStateAdded(false);
ResetMouseState();
auto it = pointer_states_.find(state->pointer_id);
if (it != pointer_states_.end()) {
pointer_states_.erase(it);
}
}
}
......
......@@ -10,6 +10,8 @@
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "flutter/shell/platform/common/client_wrapper/include/flutter/plugin_registrar.h"
......@@ -94,22 +96,26 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate,
// |WindowBindingHandlerDelegate|
void OnPointerMove(double x,
double y,
FlutterPointerDeviceKind device_kind) override;
FlutterPointerDeviceKind device_kind,
int32_t device_id) override;
// |WindowBindingHandlerDelegate|
void OnPointerDown(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id,
FlutterPointerMouseButtons button) override;
// |WindowBindingHandlerDelegate|
void OnPointerUp(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id,
FlutterPointerMouseButtons button) override;
// |WindowBindingHandlerDelegate|
void OnPointerLeave(FlutterPointerDeviceKind device_kind) override;
void OnPointerLeave(FlutterPointerDeviceKind device_kind,
int32_t device_id = 0) override;
// |WindowBindingHandlerDelegate|
void OnText(const std::u16string&) override;
......@@ -139,7 +145,9 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate,
double y,
double delta_x,
double delta_y,
int scroll_offset_multiplier) override;
int scroll_offset_multiplier,
FlutterPointerDeviceKind device_kind,
int32_t device_id) override;
// |TextInputPluginDelegate|
void OnCursorRectUpdated(const Rect& rect) override;
......@@ -161,15 +169,21 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate,
std::unique_ptr<flutter::KeyboardHandlerBase> handler);
private:
// Struct holding the mouse state. The engine doesn't keep track of which
// mouse buttons have been pressed, so it's the embedding's responsibility.
struct MouseState {
// True if the last event sent to Flutter had at least one mouse button.
// pressed.
// Struct holding the state of an individual pointer. The engine doesn't keep
// track of which buttons have been pressed, so it's the embedding's
// responsibility.
struct PointerState {
// The device kind.
FlutterPointerDeviceKind device_kind = kFlutterPointerDeviceKindMouse;
// A virtual pointer ID that is unique across all device kinds.
int32_t pointer_id = 0;
// True if the last event sent to Flutter had at least one button pressed.
bool flutter_state_is_down = false;
// True if kAdd has been sent to Flutter. Used to determine whether
// to send a kAdd event before sending an incoming mouse event, since
// to send a kAdd event before sending an incoming pointer event, since
// Flutter expects pointers to be added before events are sent for them.
bool flutter_state_is_added = false;
......@@ -195,24 +209,20 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate,
void SendWindowMetrics(size_t width, size_t height, double dpiscale) const;
// Reports a mouse movement to Flutter engine.
void SendPointerMove(double x,
double y,
FlutterPointerDeviceKind device_kind);
void SendPointerMove(double x, double y, PointerState* state);
// Reports mouse press to Flutter engine.
void SendPointerDown(double x,
double y,
FlutterPointerDeviceKind device_kind);
void SendPointerDown(double x, double y, PointerState* state);
// Reports mouse release to Flutter engine.
void SendPointerUp(double x, double y, FlutterPointerDeviceKind device_kind);
void SendPointerUp(double x, double y, PointerState* state);
// Reports mouse left the window client area.
//
// 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(FlutterPointerDeviceKind device_kind);
void SendPointerLeave(PointerState* state);
// Reports a keyboard character to Flutter engine.
void SendText(const std::u16string&);
......@@ -255,35 +265,24 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate,
double y,
double delta_x,
double delta_y,
int scroll_offset_multiplier);
int scroll_offset_multiplier,
FlutterPointerDeviceKind device_kind,
int32_t device_id);
// Creates a PointerState object unless it already exists.
PointerState* GetOrCreatePointerState(FlutterPointerDeviceKind device_kind,
int32_t device_id);
// Sets |event_data|'s phase to either kMove or kHover depending on the
// current primary mouse button state.
void SetEventPhaseFromCursorButtonState(
FlutterPointerEvent* event_data) const;
void SetEventPhaseFromCursorButtonState(FlutterPointerEvent* event_data,
const PointerState* state) const;
// Sends a pointer event to the Flutter engine based on given data. Since
// all input messages are passed in physical pixel values, no translation is
// needed before passing on to engine.
void SendPointerEventWithData(const FlutterPointerEvent& event_data);
// Resets the mouse state to its default values.
void ResetMouseState() { mouse_state_ = MouseState(); }
// Updates the mouse state to whether the last event to Flutter had at least
// one mouse button pressed.
void SetMouseFlutterStateDown(bool is_down) {
mouse_state_.flutter_state_is_down = is_down;
}
// Updates the mouse state to whether the last event to Flutter was a kAdd
// event.
void SetMouseFlutterStateAdded(bool is_added) {
mouse_state_.flutter_state_is_added = is_added;
}
// Updates the currently pressed buttons.
void SetMouseButtons(uint64_t buttons) { mouse_state_.buttons = buttons; }
void SendPointerEventWithData(const FlutterPointerEvent& event_data,
PointerState* state);
// Currently configured WindowsRenderTarget for this view used by
// surface_manager for creation of render surfaces and bound to the physical
......@@ -293,8 +292,8 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate,
// The engine associated with this view.
std::unique_ptr<FlutterWindowsEngine> engine_;
// Keeps track of mouse state in relation to the window.
MouseState mouse_state_;
// Keeps track of pointer states in relation to the window.
std::map<int32_t, std::unique_ptr<PointerState>> pointer_states_;
// The plugin registrar managing internal plugins.
std::unique_ptr<flutter::PluginRegistrar> internal_plugin_registrar_;
......
......@@ -7,6 +7,8 @@
namespace flutter {
static constexpr int32_t kDefaultPointerDeviceId = 0;
GamepadCursorWinUWP::GamepadCursorWinUWP(
WindowBindingHandlerDelegate* view,
DisplayHelperWinUWP* displayhelper,
......@@ -162,16 +164,18 @@ void GamepadCursorWinUWP::OnGamepadLeftStickMoved(double x, double y) {
// TODO(dnfield): Support for gamepad as a distinct device type?
// https://github.com/flutter/flutter/issues/80472
binding_handler_delegate_->OnPointerMove(scaled.x, scaled.y,
kFlutterPointerDeviceKindMouse);
kFlutterPointerDeviceKindMouse,
kDefaultPointerDeviceId);
}
}
void GamepadCursorWinUWP::OnGamepadRightStickMoved(double x, double y) {
winrt::Windows::Foundation::Numerics::float3 scaled =
GetScaledInput(cursor_visual_.Offset());
binding_handler_delegate_->OnScroll(scaled.x, scaled.y,
x * kControllerScrollMultiplier,
y * kControllerScrollMultiplier, 1);
binding_handler_delegate_->OnScroll(
scaled.x, scaled.y, x * kControllerScrollMultiplier,
y * kControllerScrollMultiplier, 1, kFlutterPointerDeviceKindMouse,
kDefaultPointerDeviceId);
}
void GamepadCursorWinUWP::OnGamepadButtonPressed(
......@@ -190,6 +194,7 @@ void GamepadCursorWinUWP::OnGamepadButtonPressed(
// https://github.com/flutter/flutter/issues/80472
binding_handler_delegate_->OnPointerDown(
scaled.x, scaled.y, kFlutterPointerDeviceKindMouse,
kDefaultPointerDeviceId,
FlutterPointerMouseButtons::kFlutterPointerButtonMousePrimary);
} else if ((buttons &
winrt::Windows::Gaming::Input::GamepadButtons::DPadLeft) ==
......@@ -234,6 +239,7 @@ void GamepadCursorWinUWP::OnGamepadButtonReleased(
// https://github.com/flutter/flutter/issues/80472
binding_handler_delegate_->OnPointerUp(
scaled.x, scaled.y, kFlutterPointerDeviceKindMouse,
kDefaultPointerDeviceId,
FlutterPointerMouseButtons::kFlutterPointerButtonMousePrimary);
} else if ((buttons &
winrt::Windows::Gaming::Input::GamepadButtons::DPadLeft) ==
......
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/platform/windows/sequential_id_generator.h"
namespace flutter {
namespace {
// Removes |key| from |first|, and |first[key]| from |second|.
template <typename T>
void Remove(uint32_t key, T* first, T* second) {
auto iter = first->find(key);
if (iter == first->end())
return;
uint32_t second_key = iter->second;
first->erase(iter);
iter = second->find(second_key);
second->erase(iter);
}
} // namespace
SequentialIdGenerator::SequentialIdGenerator(uint32_t min_id, uint32_t max_id)
: min_id_(min_id), min_available_id_(min_id), max_id_(max_id) {}
SequentialIdGenerator::~SequentialIdGenerator() {}
uint32_t SequentialIdGenerator::GetGeneratedId(uint32_t number) {
auto it = number_to_id_.find(number);
if (it != number_to_id_.end())
return it->second;
auto id = GetNextAvailableId();
number_to_id_.emplace(number, id);
id_to_number_.emplace(id, number);
return id;
}
bool SequentialIdGenerator::HasGeneratedIdFor(uint32_t number) const {
return number_to_id_.find(number) != number_to_id_.end();
}
void SequentialIdGenerator::ReleaseNumber(uint32_t number) {
if (number_to_id_.count(number) > 0U) {
UpdateNextAvailableIdAfterRelease(number_to_id_[number]);
Remove(number, &number_to_id_, &id_to_number_);
}
}
void SequentialIdGenerator::ReleaseId(uint32_t id) {
if (id_to_number_.count(id) > 0U) {
UpdateNextAvailableIdAfterRelease(id);
Remove(id_to_number_[id], &number_to_id_, &id_to_number_);
}
}
uint32_t SequentialIdGenerator::GetNextAvailableId() {
while (id_to_number_.count(min_available_id_) > 0 &&
min_available_id_ < max_id_) {
++min_available_id_;
}
if (min_available_id_ >= max_id_)
min_available_id_ = min_id_;
return min_available_id_;
}
void SequentialIdGenerator::UpdateNextAvailableIdAfterRelease(uint32_t id) {
if (id < min_available_id_) {
min_available_id_ = id;
}
}
} // namespace flutter
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_SEQUENTIAL_ID_GENERATOR_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_SEQUENTIAL_ID_GENERATOR_H_
#include <cstdint>
#include <unordered_map>
namespace flutter {
// This is used to generate a series of sequential ID numbers in a way that a
// new ID is always the lowest possible ID in the sequence.
//
// based on
// https://source.chromium.org/chromium/chromium/src/+/master:ui/gfx/sequential_id_generator.h
class SequentialIdGenerator {
public:
// Creates a new generator with the specified lower bound and uppoer bound for
// the IDs.
explicit SequentialIdGenerator(uint32_t min_id, uint32_t max_id);
~SequentialIdGenerator();
// Generates a unique ID to represent |number|. The generated ID is the
// smallest available ID greater than or equal to the |min_id| specified
// during creation of the generator.
uint32_t GetGeneratedId(uint32_t number);
// Checks to see if the generator currently has a unique ID generated for
// |number|.
bool HasGeneratedIdFor(uint32_t number) const;
// Removes the ID previously generated for |number| by calling
// |GetGeneratedID()| - does nothing if the number is not mapped.
void ReleaseNumber(uint32_t number);
// Releases ID previously generated by calling |GetGeneratedID()|. Does
// nothing if the ID is not mapped.
void ReleaseId(uint32_t id);
private:
typedef std::unordered_map<uint32_t, uint32_t> IdMap;
uint32_t GetNextAvailableId();
void UpdateNextAvailableIdAfterRelease(uint32_t id);
IdMap number_to_id_;
IdMap id_to_number_;
const uint32_t min_id_;
const uint32_t max_id_;
uint32_t min_available_id_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_SEQUENTIAL_ID_GENERATOR_H_
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/platform/windows/sequential_id_generator.h"
#include "gtest/gtest.h"
namespace flutter {
namespace testing {
TEST(SequentialIdGeneratorTest, RemoveMultipleNumbers) {
const uint32_t kMinId = 4;
const uint32_t kMaxId = 128;
SequentialIdGenerator generator(kMinId, kMaxId);
EXPECT_EQ(4U, generator.GetGeneratedId(45));
EXPECT_EQ(5U, generator.GetGeneratedId(55));
EXPECT_EQ(6U, generator.GetGeneratedId(15));
generator.ReleaseNumber(45);
EXPECT_FALSE(generator.HasGeneratedIdFor(45));
generator.ReleaseNumber(15);
EXPECT_FALSE(generator.HasGeneratedIdFor(15));
EXPECT_EQ(5U, generator.GetGeneratedId(55));
EXPECT_EQ(4U, generator.GetGeneratedId(12));
generator.ReleaseNumber(12);
generator.ReleaseNumber(55);
EXPECT_EQ(4U, generator.GetGeneratedId(0));
}
TEST(SequentialIdGeneratorTest, MaybeRemoveNumbers) {
const uint32_t kMinId = 0;
const uint32_t kMaxId = 128;
SequentialIdGenerator generator(kMinId, kMaxId);
EXPECT_EQ(0U, generator.GetGeneratedId(42));
generator.ReleaseNumber(42);
EXPECT_FALSE(generator.HasGeneratedIdFor(42));
generator.ReleaseNumber(42);
}
} // namespace testing
} // namespace flutter
......@@ -34,14 +34,18 @@ class MockWin32Window : public WindowWin32, public MockMessageQueue {
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_METHOD1(OnText, void(const std::u16string&));
MOCK_METHOD6(OnKey, bool(int, int, int, char32_t, bool, bool));
MOCK_METHOD2(OnScroll, void(double, double));
MOCK_METHOD4(OnScroll,
void(double, double, FlutterPointerDeviceKind, int32_t));
MOCK_METHOD0(OnComposeBegin, void());
MOCK_METHOD0(OnComposeCommit, void());
MOCK_METHOD0(OnComposeEnd, void());
......
......@@ -21,13 +21,15 @@ class WindowBindingHandlerDelegate {
// Typically called by currently configured WindowBindingHandler
virtual void OnPointerMove(double x,
double y,
FlutterPointerDeviceKind device_kind) = 0;
FlutterPointerDeviceKind device_kind,
int32_t device_id) = 0;
// Notifies delegate that backing window mouse pointer button has been
// pressed. Typically called by currently configured WindowBindingHandler
virtual void OnPointerDown(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id,
FlutterPointerMouseButtons button) = 0;
// Notifies delegate that backing window mouse pointer button has been
......@@ -35,11 +37,13 @@ class WindowBindingHandlerDelegate {
virtual void OnPointerUp(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id,
FlutterPointerMouseButtons button) = 0;
// Notifies delegate that backing window mouse pointer has left the window.
// Typically called by currently configured WindowBindingHandler
virtual void OnPointerLeave(FlutterPointerDeviceKind device_kind) = 0;
virtual void OnPointerLeave(FlutterPointerDeviceKind device_kind,
int32_t device_id) = 0;
// Notifies delegate that backing window has received text.
// Typically called by currently configured WindowBindingHandler
......@@ -88,7 +92,9 @@ class WindowBindingHandlerDelegate {
double y,
double delta_x,
double delta_y,
int scroll_offset_multiplier) = 0;
int scroll_offset_multiplier,
FlutterPointerDeviceKind device_kind,
int32_t device_id) = 0;
};
} // namespace flutter
......
......@@ -13,13 +13,39 @@
namespace flutter {
namespace {
static constexpr int32_t kDefaultPointerDeviceId = 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;
}
char32_t CodePointFromSurrogatePair(wchar_t high, wchar_t low) {
return 0x10000 + ((static_cast<char32_t>(high) & 0x000003FF) << 10) +
(low & 0x3FF);
}
static const int kMinTouchDeviceId = 0;
static const int kMaxTouchDeviceId = 128;
} // namespace
WindowWin32::WindowWin32() {
WindowWin32::WindowWin32()
: touch_id_generator_(kMinTouchDeviceId, kMaxTouchDeviceId) {
// Get the DPI of the primary monitor as the initial DPI. If Per-Monitor V2 is
// supported, |current_dpi_| should be updated in the
// kWmDpiChangedBeforeParent message.
......@@ -94,6 +120,7 @@ LRESULT CALLBACK WindowWin32::WndProc(HWND const window,
auto that = static_cast<WindowWin32*>(cs->lpCreateParams);
that->window_handle_ = window;
that->text_input_manager_.SetWindowHandle(window);
RegisterTouchWindow(window, 0);
} else if (WindowWin32* that = GetThisFromHandle(window)) {
return that->HandleMessage(message, wparam, lparam);
}
......@@ -204,6 +231,7 @@ WindowWin32::HandleMessage(UINT const message,
int xPos = 0, yPos = 0;
UINT width = 0, height = 0;
UINT button_pressed = 0;
FlutterPointerDeviceKind device_kind;
switch (message) {
case kWmDpiChangedBeforeParent:
......@@ -218,15 +246,56 @@ WindowWin32::HandleMessage(UINT const message,
current_height_ = height;
HandleResize(width, height);
break;
case WM_TOUCH: {
UINT num_points = LOWORD(wparam);
touch_points_.resize(num_points);
auto touch_input_handle = reinterpret_cast<HTOUCHINPUT>(lparam);
if (GetTouchInputInfo(touch_input_handle, num_points,
touch_points_.data(), sizeof(TOUCHINPUT))) {
for (const auto& touch : touch_points_) {
// Generate a mapped ID for the Windows-provided touch ID
auto touch_id = touch_id_generator_.GetGeneratedId(touch.dwID);
POINT pt = {TOUCH_COORD_TO_PIXEL(touch.x),
TOUCH_COORD_TO_PIXEL(touch.y)};
ScreenToClient(window_handle_, &pt);
auto x = static_cast<double>(pt.x);
auto y = static_cast<double>(pt.y);
if (touch.dwFlags & TOUCHEVENTF_DOWN) {
OnPointerDown(x, y, kFlutterPointerDeviceKindTouch, touch_id,
WM_LBUTTONDOWN);
} else if (touch.dwFlags & TOUCHEVENTF_MOVE) {
OnPointerMove(x, y, kFlutterPointerDeviceKindTouch, touch_id);
} else if (touch.dwFlags & TOUCHEVENTF_UP) {
OnPointerUp(x, y, kFlutterPointerDeviceKindTouch, touch_id,
WM_LBUTTONDOWN);
OnPointerLeave(kFlutterPointerDeviceKindTouch, touch_id);
touch_id_generator_.ReleaseNumber(touch.dwID);
}
}
CloseTouchInputHandle(touch_input_handle);
}
return 0;
}
case WM_MOUSEMOVE:
TrackMouseLeaveEvent(window_handle_);
device_kind = GetFlutterPointerDeviceKind();
if (device_kind == kFlutterPointerDeviceKindMouse) {
TrackMouseLeaveEvent(window_handle_);
xPos = GET_X_LPARAM(lparam);
yPos = GET_Y_LPARAM(lparam);
OnPointerMove(static_cast<double>(xPos), static_cast<double>(yPos));
xPos = GET_X_LPARAM(lparam);
yPos = GET_Y_LPARAM(lparam);
OnPointerMove(static_cast<double>(xPos), static_cast<double>(yPos),
device_kind, kDefaultPointerDeviceId);
}
break;
case WM_MOUSELEAVE:;
OnPointerLeave();
case WM_MOUSELEAVE:
device_kind = GetFlutterPointerDeviceKind();
if (device_kind == kFlutterPointerDeviceKindMouse) {
OnPointerLeave(device_kind, kDefaultPointerDeviceId);
}
// Once the tracked event is received, the TrackMouseEvent function
// resets. Set to false to make sure it's called once mouse movement is
// detected again.
......@@ -250,6 +319,11 @@ WindowWin32::HandleMessage(UINT const message,
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_XBUTTONDOWN:
device_kind = GetFlutterPointerDeviceKind();
if (device_kind != kFlutterPointerDeviceKindMouse) {
break;
}
if (message == WM_LBUTTONDOWN) {
// Capture the pointer in case the user drags outside the client area.
// In this case, the "mouse leave" event is delayed until the user
......@@ -265,12 +339,17 @@ WindowWin32::HandleMessage(UINT const message,
xPos = GET_X_LPARAM(lparam);
yPos = GET_Y_LPARAM(lparam);
OnPointerDown(static_cast<double>(xPos), static_cast<double>(yPos),
button_pressed);
device_kind, kDefaultPointerDeviceId, button_pressed);
break;
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
case WM_XBUTTONUP:
device_kind = GetFlutterPointerDeviceKind();
if (device_kind != kFlutterPointerDeviceKindMouse) {
break;
}
if (message == WM_LBUTTONUP) {
ReleaseCapture();
}
......@@ -281,16 +360,18 @@ WindowWin32::HandleMessage(UINT const message,
xPos = GET_X_LPARAM(lparam);
yPos = GET_Y_LPARAM(lparam);
OnPointerUp(static_cast<double>(xPos), static_cast<double>(yPos),
button_pressed);
device_kind, kDefaultPointerDeviceId, button_pressed);
break;
case WM_MOUSEWHEEL:
OnScroll(0.0, -(static_cast<short>(HIWORD(wparam)) /
static_cast<double>(WHEEL_DELTA)));
OnScroll(0.0,
-(static_cast<short>(HIWORD(wparam)) /
static_cast<double>(WHEEL_DELTA)),
kFlutterPointerDeviceKindMouse, kDefaultPointerDeviceId);
break;
case WM_MOUSEHWHEEL:
OnScroll((static_cast<short>(HIWORD(wparam)) /
static_cast<double>(WHEEL_DELTA)),
0.0);
0.0, kFlutterPointerDeviceKindMouse, kDefaultPointerDeviceId);
break;
case WM_INPUTLANGCHANGE:
// TODO(cbracken): pass this to TextInputManager to aid with
......
......@@ -11,7 +11,10 @@
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/windows/sequential_id_generator.h"
#include "flutter/shell/platform/windows/text_input_manager_win32.h"
namespace flutter {
......@@ -54,17 +57,18 @@ class WindowWin32 {
// Processes and route salient window messages for mouse handling,
// size change and DPI. Delegates handling of these to member overloads that
// inheriting classes can handle.
LRESULT
HandleMessage(UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept;
LRESULT HandleMessage(UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept;
// When WM_DPICHANGE process it using |hWnd|, |wParam|. If
// |top_level| is set, extract the suggested new size from |lParam| and resize
// the window to the new suggested size. If |top_level| is not set, the
// |lParam| will not contain a suggested size hence ignore it.
LRESULT
HandleDpiChange(HWND hWnd, WPARAM wParam, LPARAM lParam, bool top_level);
LRESULT HandleDpiChange(HWND hWnd,
WPARAM wParam,
LPARAM lParam,
bool top_level);
// Called when the DPI changes either when a
// user drags the window between monitors of differing DPI or when the user
......@@ -76,17 +80,29 @@ class WindowWin32 {
// Called when the pointer moves within the
// window bounds.
virtual void OnPointerMove(double x, double y) = 0;
virtual void OnPointerMove(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id) = 0;
// Called when the a mouse button, determined by |button|, goes down.
virtual void OnPointerDown(double x, double y, UINT button) = 0;
virtual void OnPointerDown(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id,
UINT button) = 0;
// Called when the a mouse button, determined by |button|, goes from
// down to up
virtual void OnPointerUp(double x, double y, UINT button) = 0;
virtual void OnPointerUp(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id,
UINT button) = 0;
// Called when the mouse leaves the window.
virtual void OnPointerLeave() = 0;
virtual void OnPointerLeave(FlutterPointerDeviceKind device_kind,
int32_t device_id) = 0;
// Called when the cursor should be set for the client area.
virtual void OnSetCursor() = 0;
......@@ -151,7 +167,10 @@ class WindowWin32 {
virtual void UpdateCursorRect(const Rect& rect);
// Called when mouse scrollwheel input occurs.
virtual void OnScroll(double delta_x, double delta_y) = 0;
virtual void OnScroll(double delta_x,
double delta_y,
FlutterPointerDeviceKind device_kind,
int32_t device_id) = 0;
UINT GetCurrentDPI();
......@@ -226,6 +245,12 @@ class WindowWin32 {
// Manages IME state.
TextInputManagerWin32 text_input_manager_;
// Used for temporarily storing the WM_TOUCH-provided touch points.
std::vector<TOUCHINPUT> touch_points_;
// Generates touch point IDs for touch events.
SequentialIdGenerator touch_id_generator_;
};
} // namespace flutter
......
......@@ -25,7 +25,9 @@ TEST(MockWin32Window, VerticalScroll) {
const int scroll_amount = 10;
// Vertical scroll should be passed along, adjusted for scroll tick size
// and direction.
EXPECT_CALL(window, OnScroll(0, -scroll_amount / 120.0)).Times(1);
EXPECT_CALL(window, OnScroll(0, -scroll_amount / 120.0,
kFlutterPointerDeviceKindMouse, 0))
.Times(1);
window.InjectWindowMessage(WM_MOUSEWHEEL, MAKEWPARAM(0, scroll_amount), 0);
}
......@@ -34,7 +36,9 @@ TEST(MockWin32Window, HorizontalScroll) {
MockWin32Window window;
const int scroll_amount = 10;
// Vertical scroll should be passed along, adjusted for scroll tick size.
EXPECT_CALL(window, OnScroll(scroll_amount / 120.0, 0)).Times(1);
EXPECT_CALL(window, OnScroll(scroll_amount / 120.0, 0,
kFlutterPointerDeviceKindMouse, 0))
.Times(1);
window.InjectWindowMessage(WM_MOUSEHWHEEL, MAKEWPARAM(0, scroll_amount), 0);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册