未验证 提交 bd760768 编写于 作者: M Mouad Debbar 提交者: GitHub

[web] Detect when the mouseup occurs outside of window (#17495)

上级 ba615d52
......@@ -166,7 +166,7 @@ abstract class _BaseAdapter {
/// Remove all active event listeners.
void clearListeners() {
_listeners.forEach((String eventName, html.EventListener listener) {
glassPaneElement.removeEventListener(eventName, listener, true);
html.window.removeEventListener(eventName, listener, true);
});
// For native listener, we will need to remove it through native javascript
// api.
......@@ -183,8 +183,23 @@ abstract class _BaseAdapter {
_nativeListeners.clear();
}
void addEventListener(String eventName, html.EventListener handler) {
/// Adds a listener to the given [eventName].
///
/// The event listener is attached to [html.window] but only events that have
/// [glassPaneElement] as a target will be let through by default.
///
/// If [acceptOutsideGlasspane] is set to true, events outside of the
/// glasspane will also invoke the [handler].
void addEventListener(
String eventName,
html.EventListener handler, {
bool acceptOutsideGlasspane = false,
}) {
final html.EventListener loggedHandler = (html.Event event) {
if (!acceptOutsideGlasspane && event.target != glassPaneElement) {
return;
}
if (_debugLogPointerEvents) {
print(event.type);
}
......@@ -196,8 +211,11 @@ abstract class _BaseAdapter {
}
};
_listeners[eventName] = loggedHandler;
glassPaneElement
.addEventListener(eventName, loggedHandler, true);
// We have to attach the event listener on the window instead of the
// glasspane element. That's because "up" events that occur outside the
// browser are only reported on window, not on DOM elements.
// See: https://github.com/flutter/flutter/issues/52827
html.window.addEventListener(eventName, loggedHandler, true);
}
/// Converts a floating number timestamp (in milliseconds) to a [Duration] by
......@@ -412,11 +430,15 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
}
}
void _addPointerEventListener(String eventName, _PointerEventListener handler) {
void _addPointerEventListener(
String eventName,
_PointerEventListener handler, {
bool acceptOutsideGlasspane = false,
}) {
addEventListener(eventName, (html.Event event) {
final html.PointerEvent pointerEvent = event;
return handler(pointerEvent);
});
}, acceptOutsideGlasspane: acceptOutsideGlasspane);
}
@override
......@@ -444,7 +466,7 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
_convertEventsToPointerData(data: pointerData, event: event, details: details);
}
_callback(pointerData);
});
}, acceptOutsideGlasspane: true);
_addPointerEventListener('pointerup', (html.PointerEvent event) {
final int device = event.pointerId;
......@@ -455,7 +477,7 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
_convertEventsToPointerData(data: pointerData, event: event, details: details);
}
_callback(pointerData);
});
}, acceptOutsideGlasspane: true);
// A browser fires cancel event if it concludes the pointer will no longer
// be able to generate events (example: device is deactivated)
......@@ -706,11 +728,15 @@ class _MouseAdapter extends _BaseAdapter with _WheelEventListenerMixin {
final _ButtonSanitizer _sanitizer = _ButtonSanitizer();
void _addMouseEventListener(String eventName, _MouseEventListener handler) {
void _addMouseEventListener(
String eventName,
_MouseEventListener handler, {
bool acceptOutsideGlasspane = false,
}) {
addEventListener(eventName, (html.Event event) {
final html.MouseEvent mouseEvent = event;
return handler(mouseEvent);
});
}, acceptOutsideGlasspane: acceptOutsideGlasspane);
}
@override
......@@ -731,7 +757,7 @@ class _MouseAdapter extends _BaseAdapter with _WheelEventListenerMixin {
final _SanitizedDetails sanitizedDetails = _sanitizer.sanitizeMoveEvent(buttons: event.buttons);
_convertEventsToPointerData(data: pointerData, event: event, details: sanitizedDetails);
_callback(pointerData);
});
}, acceptOutsideGlasspane: true);
_addMouseEventListener('mouseup', (html.MouseEvent event) {
final List<ui.PointerData> pointerData = <ui.PointerData>[];
......@@ -741,7 +767,7 @@ class _MouseAdapter extends _BaseAdapter with _WheelEventListenerMixin {
_sanitizer.sanitizeMoveEvent(buttons: event.buttons);
_convertEventsToPointerData(data: pointerData, event: event, details: sanitizedDetails);
_callback(pointerData);
});
}, acceptOutsideGlasspane: true);
_addWheelEventListener((html.Event event) {
assert(event is html.WheelEvent);
......
......@@ -1446,6 +1446,67 @@ void main() {
},
);
_testEach<_ButtonedEventMixin>(
[_PointerEventContext(), _MouseEventContext()],
'correctly detects up event outside of glasspane',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
// This can happen when the up event occurs while the mouse is outside the
// browser window.
List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
// Press and drag around.
glassPane.dispatchEvent(context.primaryDown(
clientX: 10.0,
clientY: 10.0,
));
glassPane.dispatchEvent(context.primaryMove(
clientX: 12.0,
clientY: 10.0,
));
glassPane.dispatchEvent(context.primaryMove(
clientX: 15.0,
clientY: 10.0,
));
glassPane.dispatchEvent(context.primaryMove(
clientX: 20.0,
clientY: 10.0,
));
packets.clear();
// Move outside the glasspane.
html.window.dispatchEvent(context.primaryMove(
clientX: 900.0,
clientY: 1900.0,
));
expect(packets, hasLength(1));
expect(packets[0].data, hasLength(1));
expect(packets[0].data[0].change, equals(ui.PointerChange.move));
expect(packets[0].data[0].physicalX, equals(900.0));
expect(packets[0].data[0].physicalY, equals(1900.0));
packets.clear();
// Release outside the glasspane.
html.window.dispatchEvent(context.primaryUp(
clientX: 1000.0,
clientY: 2000.0,
));
expect(packets, hasLength(1));
expect(packets[0].data, hasLength(2));
expect(packets[0].data[0].change, equals(ui.PointerChange.move));
expect(packets[0].data[0].physicalX, equals(1000.0));
expect(packets[0].data[0].physicalY, equals(2000.0));
expect(packets[0].data[1].change, equals(ui.PointerChange.up));
expect(packets[0].data[1].physicalX, equals(1000.0));
expect(packets[0].data[1].physicalY, equals(2000.0));
packets.clear();
},
);
// MULTIPOINTER ADAPTERS
_testEach<_MultiPointerEventMixin>(
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册