Skip to content

Commit

Permalink
Expose pointer type and buttons in embedder.h (#9034)
Browse files Browse the repository at this point in the history
Rather than hard-coding the type of incoming events to mouse, and
synthesizing a primary button press for kDown/kUp, expose device kind
and buttons in the API.

For backwards compatibility, if the type is not set, the old behavior is
used. If an embedder sets the type to mouse explicitly, however, they
must also set correct button information.

For the touch type, the API abstracts away the framework's internal
expectation that a button is set for touch down/move for simplicity.

Fixes #32854
  • Loading branch information
stuartmorgan committed May 22, 2019
1 parent 64f18f2 commit 4dbb9ba
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 22 deletions.
66 changes: 44 additions & 22 deletions shell/platform/embedder/embedder.cc
Expand Up @@ -699,6 +699,19 @@ inline flutter::PointerData::Change ToPointerDataChange(
return flutter::PointerData::Change::kCancel;
}

// Returns the flutter::PointerData::DeviceKind for the given
// FlutterPointerDeviceKind.
inline flutter::PointerData::DeviceKind ToPointerDataKind(
FlutterPointerDeviceKind device_kind) {
switch (device_kind) {
case kFlutterPointerDeviceKindMouse:
return flutter::PointerData::DeviceKind::kMouse;
case kFlutterPointerDeviceKindTouch:
return flutter::PointerData::DeviceKind::kTouch;
}
return flutter::PointerData::DeviceKind::kMouse;
}

// Returns the flutter::PointerData::SignalKind for the given
// FlutterPointerSignaKind.
inline flutter::PointerData::SignalKind ToPointerDataSignalKind(
Expand All @@ -712,33 +725,24 @@ inline flutter::PointerData::SignalKind ToPointerDataSignalKind(
return flutter::PointerData::SignalKind::kNone;
}

// Returns the buttons for PointerData for the given buttons and change from a
// FlutterPointerEvent.
inline int64_t ToPointerDataButtons(int64_t buttons,
flutter::PointerData::Change change) {
// Returns the buttons to synthesize for a PointerData from a
// FlutterPointerEvent with no type or buttons set.
inline int64_t PointerDataButtonsForLegacyEvent(
flutter::PointerData::Change change) {
switch (change) {
case flutter::PointerData::Change::kDown:
case flutter::PointerData::Change::kMove:
// These kinds of change must have a non-zero `buttons`, otherwise gesture
// recognizers will ignore these events. To avoid breaking legacy
// embedders, it synthesizes a primary button when seeing `button = 0` and
// logs a warning to inform them to update.
if (buttons == 0) {
// TODO: Log a warning to inform the embedder to send the
// correct buttons. See
// https://github.com/flutter/flutter/issues/32052#issuecomment-489278965
return flutter::kPointerButtonMousePrimary;
}
return buttons;

// recognizers will ignore these events.
return flutter::kPointerButtonMousePrimary;
case flutter::PointerData::Change::kCancel:
case flutter::PointerData::Change::kAdd:
case flutter::PointerData::Change::kRemove:
case flutter::PointerData::Change::kHover:
case flutter::PointerData::Change::kUp:
return buttons;
return 0;
}
return buttons;
return 0;
}

FlutterEngineResult FlutterEngineSendPointerEvent(
Expand All @@ -759,18 +763,36 @@ FlutterEngineResult FlutterEngineSendPointerEvent(
pointer_data.time_stamp = SAFE_ACCESS(current, timestamp, 0);
pointer_data.change = ToPointerDataChange(
SAFE_ACCESS(current, phase, FlutterPointerPhase::kCancel));
pointer_data.kind = flutter::PointerData::DeviceKind::kMouse;
pointer_data.physical_x = SAFE_ACCESS(current, x, 0.0);
pointer_data.physical_y = SAFE_ACCESS(current, y, 0.0);
pointer_data.device = SAFE_ACCESS(current, device, 0);
pointer_data.signal_kind = ToPointerDataSignalKind(
SAFE_ACCESS(current, signal_kind, kFlutterPointerSignalKindNone));
pointer_data.scroll_delta_x = SAFE_ACCESS(current, scroll_delta_x, 0.0);
pointer_data.scroll_delta_y = SAFE_ACCESS(current, scroll_delta_y, 0.0);
// TODO: Change 0 to a SAFE_ACCESS to current.buttons once this
// field is added. See
// https://github.com/flutter/flutter/issues/32052#issuecomment-489278965
pointer_data.buttons = ToPointerDataButtons(0, pointer_data.change);
FlutterPointerDeviceKind device_kind = SAFE_ACCESS(current, device_kind, 0);
// For backwards compatibilty with embedders written before the device kind
// and buttons were exposed, if the device kind is not set treat it as a
// mouse, with a synthesized primary button state based on the phase.
if (device_kind == 0) {
pointer_data.kind = flutter::PointerData::DeviceKind::kMouse;
pointer_data.buttons =
PointerDataButtonsForLegacyEvent(pointer_data.change);

} else {
pointer_data.kind = ToPointerDataKind(device_kind);
if (pointer_data.kind == flutter::PointerData::DeviceKind::kTouch) {
// For touch events, set the button internally rather than requiring
// it at the API level, since it's a confusing construction to expose.
if (pointer_data.change == flutter::PointerData::Change::kDown ||
pointer_data.change == flutter::PointerData::Change::kMove) {
pointer_data.buttons = flutter::kPointerButtonTouchContact;
}
} else {
// Buttons use the same mask values, so pass them through directly.
pointer_data.buttons = SAFE_ACCESS(current, buttons, 0);
}
}
packet->SetPointerData(i, pointer_data);
current = reinterpret_cast<const FlutterPointerEvent*>(
reinterpret_cast<const uint8_t*>(current) + current->struct_size);
Expand Down
51 changes: 51 additions & 0 deletions shell/platform/embedder/embedder.h
Expand Up @@ -280,14 +280,57 @@ typedef struct {
// The phase of the pointer event.
typedef enum {
kCancel,
// The pointer, which must have been down (see kDown), is now up.
//
// For touch, this means that the pointer is no longer in contact with the
// screen. For a mouse, it means the last button was released. Note that if
// any other buttons are still pressed when one button is released, that
// should be sent as a kMove rather than a kUp.
kUp,
// The pointer, which must have been been up, is now down.
//
// For touch, this means that the pointer has come into contact with the
// screen. For a mouse, it means a button is now pressed. Note that if any
// other buttons are already pressed when a new button is pressed, that should
// be sent as a kMove rather than a kDown.
kDown,
// The pointer moved while down.
//
// This is also used for changes in button state that don't cause a kDown or
// kUp, such as releasing one of two pressed buttons.
kMove,
// The pointer is now sending input to Flutter. For instance, a mouse has
// entered the area where the Flutter content is displayed.
//
// A pointer should always be added before sending any other events.
kAdd,
// The pointer is no longer sending input to Flutter. For instance, a mouse
// has left the area where the Flutter content is displayed.
//
// A removed pointer should no longer send events until sending a new kAdd.
kRemove,
// The pointer moved while up.
kHover,
} FlutterPointerPhase;

// The device type that created a pointer event.
typedef enum {
kFlutterPointerDeviceKindMouse = 1,
kFlutterPointerDeviceKindTouch,
} FlutterPointerDeviceKind;

// Flags for the |buttons| field of |FlutterPointerEvent| when |device_kind|
// is |kFlutterPointerDeviceKindMouse|.
typedef enum {
kFlutterPointerButtonMousePrimary = 1 << 0,
kFlutterPointerButtonMouseSecondary = 1 << 1,
kFlutterPointerButtonMouseMiddle = 1 << 2,
kFlutterPointerButtonMouseBack = 1 << 3,
kFlutterPointerButtonMouseForward = 1 << 4,
// If a mouse has more than five buttons, send higher bit shifted values
// corresponding to the button number: 1 << 5 for the 6th, etc.
} FlutterPointerMouseButtons;

// The type of a pointer signal.
typedef enum {
kFlutterPointerSignalKindNone,
Expand All @@ -307,6 +350,14 @@ typedef struct {
FlutterPointerSignalKind signal_kind;
double scroll_delta_x;
double scroll_delta_y;
// The type of the device generating this event.
// Backwards compatibility note: If this is not set, the device will be
// treated as a mouse, with the primary button set for |kDown| and |kMove|.
// If set explicitly to |kFlutterPointerDeviceKindMouse|, you must set the
// correct buttons.
FlutterPointerDeviceKind device_kind;
// The buttons currently pressed, if any.
int64_t buttons;
} FlutterPointerEvent;

struct _FlutterPlatformMessageResponseHandle;
Expand Down

0 comments on commit 4dbb9ba

Please sign in to comment.