未验证 提交 a5b23d81 编写于 作者: F Francisco Magdaleno 提交者: GitHub

Adds support for 5 mouse buttons (#12450)

上级 0018135a
......@@ -81,6 +81,27 @@ static FlutterDesktopMessage ConvertToDesktopMessage(
return message;
}
// Translates button codes from Win32 API to FlutterPointerMouseButtons.
static uint64_t ConvertWinButtonToFlutterButton(UINT button) {
switch (button) {
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
return kFlutterPointerButtonMousePrimary;
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
return kFlutterPointerButtonMouseSecondary;
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
return kFlutterPointerButtonMouseMiddle;
case XBUTTON1:
return kFlutterPointerButtonMouseBack;
case XBUTTON2:
return kFlutterPointerButtonMouseForward;
}
std::cerr << "Mouse button not recognized: " << button << std::endl;
return 0;
}
// The Flutter Engine calls out to this function when new platform messages
// are available.
void Win32FlutterWindow::HandlePlatformMessage(
......@@ -113,15 +134,25 @@ void Win32FlutterWindow::OnPointerMove(double x, double y) {
}
}
void Win32FlutterWindow::OnPointerDown(double x, double y) {
void Win32FlutterWindow::OnPointerDown(double x, double y, UINT button) {
if (process_events_) {
SendPointerDown(x, y);
uint64_t flutter_button = ConvertWinButtonToFlutterButton(button);
if (flutter_button != 0) {
uint64_t mouse_buttons = GetMouseState().buttons | flutter_button;
SetMouseButtons(mouse_buttons);
SendPointerDown(x, y);
}
}
}
void Win32FlutterWindow::OnPointerUp(double x, double y) {
void Win32FlutterWindow::OnPointerUp(double x, double y, UINT button) {
if (process_events_) {
SendPointerUp(x, y);
uint64_t flutter_button = ConvertWinButtonToFlutterButton(button);
if (flutter_button != 0) {
uint64_t mouse_buttons = GetMouseState().buttons & ~flutter_button;
SetMouseButtons(mouse_buttons);
SendPointerUp(x, y);
}
}
}
......@@ -190,8 +221,15 @@ void Win32FlutterWindow::SetEventLocationFromCursorPosition(
// primary mouse button state.
void Win32FlutterWindow::SetEventPhaseFromCursorButtonState(
FlutterPointerEvent* event_data) {
event_data->phase = pointer_is_down_ ? FlutterPointerPhase::kMove
: FlutterPointerPhase::kHover;
MouseState state = GetMouseState();
// For details about this logic, see FlutterPointerPhase in the embedder.h
// file.
event_data->phase = state.buttons == 0 ? state.flutter_state_is_down
? FlutterPointerPhase::kUp
: FlutterPointerPhase::kHover
: state.flutter_state_is_down
? FlutterPointerPhase::kMove
: FlutterPointerPhase::kDown;
}
void Win32FlutterWindow::SendPointerMove(double x, double y) {
......@@ -203,21 +241,23 @@ void Win32FlutterWindow::SendPointerMove(double x, double y) {
}
void Win32FlutterWindow::SendPointerDown(double x, double y) {
pointer_is_down_ = true;
FlutterPointerEvent event = {};
event.phase = FlutterPointerPhase::kDown;
SetEventPhaseFromCursorButtonState(&event);
event.x = x;
event.y = y;
SendPointerEventWithData(event);
SetMouseFlutterStateDown(true);
}
void Win32FlutterWindow::SendPointerUp(double x, double y) {
pointer_is_down_ = false;
FlutterPointerEvent event = {};
event.phase = FlutterPointerPhase::kUp;
SetEventPhaseFromCursorButtonState(&event);
event.x = x;
event.y = y;
SendPointerEventWithData(event);
if (event.phase == FlutterPointerPhase::kUp) {
SetMouseFlutterStateDown(false);
}
}
void Win32FlutterWindow::SendPointerLeave() {
......@@ -253,24 +293,29 @@ void Win32FlutterWindow::SendScroll(double delta_x, double delta_y) {
void Win32FlutterWindow::SendPointerEventWithData(
const FlutterPointerEvent& event_data) {
MouseState mouse_state = GetMouseState();
// 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 (!pointer_currently_added_ &&
if (!mouse_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);
}
// Don't double-add (e.g., if events are delivered out of order, so an add has
// already been synthesized).
if (pointer_currently_added_ &&
if (mouse_state.flutter_state_is_added &&
event_data.phase == FlutterPointerPhase::kAdd) {
return;
}
FlutterPointerEvent event = event_data;
event.device_kind = kFlutterPointerDeviceKindMouse;
event.buttons = mouse_state.buttons;
// Set metadata that's always the same regardless of the event.
event.struct_size = sizeof(event);
event.timestamp =
......@@ -288,9 +333,10 @@ void Win32FlutterWindow::SendPointerEventWithData(
FlutterEngineSendPointerEvent(engine_, &event, 1);
if (event_data.phase == FlutterPointerPhase::kAdd) {
pointer_currently_added_ = true;
SetMouseFlutterStateAdded(true);
} else if (event_data.phase == FlutterPointerPhase::kRemove) {
pointer_currently_added_ = false;
SetMouseFlutterStateAdded(false);
ResetMouseState();
}
}
......
......@@ -48,10 +48,10 @@ class Win32FlutterWindow : public Win32Window {
void OnPointerMove(double x, double y) override;
// |Win32Window|
void OnPointerDown(double x, double y) override;
void OnPointerDown(double x, double y, UINT button) override;
// |Win32Window|
void OnPointerUp(double x, double y) override;
void OnPointerUp(double x, double y, UINT button) override;
// |Win32Window|
void OnPointerLeave() override;
......
......@@ -118,7 +118,7 @@ Win32Window::MessageHandler(HWND hwnd,
UINT width = 0, height = 0;
auto window =
reinterpret_cast<Win32Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
UINT button_pressed = 0;
if (window != nullptr) {
switch (message) {
case WM_DPICHANGED:
......@@ -158,16 +158,41 @@ Win32Window::MessageHandler(HWND hwnd,
tracking_mouse_leave_ = false;
break;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_XBUTTONDOWN:
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
// releases the button. It's only activated on left click given that
// it's more common for apps to handle dragging with only the left
// button.
SetCapture(hwnd);
}
button_pressed = message;
if (message == WM_XBUTTONDOWN) {
button_pressed = GET_XBUTTON_WPARAM(wparam);
}
xPos = GET_X_LPARAM(lparam);
yPos = GET_Y_LPARAM(lparam);
window->OnPointerDown(static_cast<double>(xPos),
static_cast<double>(yPos));
static_cast<double>(yPos), button_pressed);
break;
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
case WM_XBUTTONUP:
if (message == WM_LBUTTONUP) {
ReleaseCapture();
}
button_pressed = message;
if (message == WM_XBUTTONUP) {
button_pressed = GET_XBUTTON_WPARAM(wparam);
}
xPos = GET_X_LPARAM(lparam);
yPos = GET_Y_LPARAM(lparam);
window->OnPointerUp(static_cast<double>(xPos),
static_cast<double>(yPos));
static_cast<double>(yPos), button_pressed);
break;
case WM_MOUSEWHEEL:
window->OnScroll(
......
......@@ -15,6 +15,22 @@
namespace flutter {
// 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.
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 Flutter
// expects pointers to be added before events are sent for them.
bool flutter_state_is_added = false;
// The currently pressed buttons, as represented in FlutterPointerEvent.
uint64_t buttons = 0;
};
// A class abstraction for a high DPI aware Win32 Window. Intended to be
// inherited from by classes that wish to specialize with custom
// rendering and input handling.
......@@ -81,12 +97,12 @@ class Win32Window {
// window bounds.
virtual void OnPointerMove(double x, double y) = 0;
// Called when the left mouse button goes down
virtual void OnPointerDown(double x, double y) = 0;
// Called when the a mouse button, determined by |button|, goes down.
virtual void OnPointerDown(double x, double y, UINT button) = 0;
// Called when the left mouse button goes from
// Called when the a mouse button, determined by |button|, goes from
// down to up
virtual void OnPointerUp(double x, double y) = 0;
virtual void OnPointerUp(double x, double y, UINT button) = 0;
// Called when the mouse leaves the window.
virtual void OnPointerLeave() = 0;
......@@ -112,6 +128,27 @@ class Win32Window {
UINT GetCurrentHeight();
// Gets the current mouse state.
MouseState GetMouseState() { return mouse_state_; }
// 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; }
private:
// Activates tracking for a "mouse leave" event.
void TrackMouseLeaveEvent(HWND hwnd);
......@@ -142,6 +179,9 @@ class Win32Window {
// Set to true to be notified when the mouse leaves the window.
bool tracking_mouse_leave_ = false;
// Keeps track of mouse state in relation to the window.
MouseState mouse_state_;
};
} // namespace flutter
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册