Skip to content

Commit eb13993

Browse files
authored
[web] Fix right click issues (flutter#15103)
1 parent 5858519 commit eb13993

File tree

3 files changed

+513
-42
lines changed

3 files changed

+513
-42
lines changed

lib/web_ui/lib/src/engine/pointer_binding.dart

Lines changed: 73 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -288,41 +288,81 @@ class _SanitizedDetails {
288288
class _ButtonSanitizer {
289289
int _pressedButtons = 0;
290290

291-
// Transform html.PointerEvent.buttons to Flutter's PointerEvent buttons.
291+
/// Transform [html.PointerEvent.buttons] to Flutter's PointerEvent buttons.
292292
int _htmlButtonsToFlutterButtons(int buttons) {
293293
// Flutter's button definition conveniently matches that of JavaScript
294294
// from primary button (0x1) to forward button (0x10), which allows us to
295295
// avoid transforming it bit by bit.
296296
return buttons & _kButtonsMask;
297297
}
298298

299-
List<_SanitizedDetails> sanitizeDownEvent({@required int buttons}) {
300-
final List<_SanitizedDetails> result = <_SanitizedDetails>[];
301-
// TODO(flutter_web): Remove this temporary fix for right click
302-
// on web platform once context gesture is implemented.
299+
/// Given [html.PointerEvent.button] and [html.PointerEvent.buttons], tries to
300+
/// infer the correct value for Flutter buttons.
301+
int _inferDownFlutterButtons(int button, int buttons) {
302+
if (buttons == 0 && button > -1) {
303+
// In some cases, the browser sends `buttons:0` in a down event. In such
304+
// case, we try to infer the value from `button`.
305+
buttons = convertButtonToButtons(button);
306+
}
307+
return _htmlButtonsToFlutterButtons(buttons);
308+
}
309+
310+
List<_SanitizedDetails> sanitizeDownEvent({
311+
@required int button,
312+
@required int buttons,
313+
}) {
314+
// If the pointer is already down, we just send a move event with the new
315+
// `buttons` value.
303316
if (_pressedButtons != 0) {
304-
_pressedButtons = 0;
305-
result.add(_SanitizedDetails(
306-
change: ui.PointerChange.up,
307-
buttons: 0,
308-
));
317+
return sanitizeMoveEvent(buttons: buttons);
309318
}
310-
_pressedButtons = _htmlButtonsToFlutterButtons(buttons);
311-
result.add(_SanitizedDetails(
312-
change: ui.PointerChange.down,
313-
buttons: _pressedButtons,
314-
));
315-
return result;
319+
320+
_pressedButtons = _inferDownFlutterButtons(button, buttons);
321+
return <_SanitizedDetails>[
322+
_SanitizedDetails(
323+
change: ui.PointerChange.down,
324+
buttons: _pressedButtons,
325+
)
326+
];
316327
}
317328

318329
List<_SanitizedDetails> sanitizeMoveEvent({@required int buttons}) {
319-
_pressedButtons = _htmlButtonsToFlutterButtons(buttons);
320-
return <_SanitizedDetails>[_SanitizedDetails(
321-
change: _pressedButtons == 0
322-
? ui.PointerChange.hover
323-
: ui.PointerChange.move,
324-
buttons: _pressedButtons,
325-
)];
330+
final int newPressedButtons = _htmlButtonsToFlutterButtons(buttons);
331+
// This could happen when the context menu is active and the user clicks
332+
// RMB somewhere else. The browser sends a down event with `buttons:0`.
333+
//
334+
// In this case, we keep the old `buttons` value so we don't confuse the
335+
// framework.
336+
if (_pressedButtons != 0 && newPressedButtons == 0) {
337+
return <_SanitizedDetails>[
338+
_SanitizedDetails(
339+
change: ui.PointerChange.move,
340+
buttons: _pressedButtons,
341+
)
342+
];
343+
}
344+
345+
// This could happen when the user clicks RMB then moves the mouse quickly.
346+
// The brower sends a move event with `buttons:2` even though there's no
347+
// buttons down yet.
348+
if (_pressedButtons == 0 && newPressedButtons != 0) {
349+
return <_SanitizedDetails>[
350+
_SanitizedDetails(
351+
change: ui.PointerChange.hover,
352+
buttons: _pressedButtons,
353+
)
354+
];
355+
}
356+
357+
_pressedButtons = newPressedButtons;
358+
return <_SanitizedDetails>[
359+
_SanitizedDetails(
360+
change: _pressedButtons == 0
361+
? ui.PointerChange.hover
362+
: ui.PointerChange.move,
363+
buttons: _pressedButtons,
364+
)
365+
];
326366
}
327367

328368
List<_SanitizedDetails> sanitizeUpEvent() {
@@ -396,7 +436,11 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
396436
_addPointerEventListener('pointerdown', (html.PointerEvent event) {
397437
final int device = event.pointerId;
398438
final List<ui.PointerData> pointerData = <ui.PointerData>[];
399-
final List<_SanitizedDetails> detailsList = _ensureSanitizer(device).sanitizeDownEvent(buttons: event.buttons);
439+
final List<_SanitizedDetails> detailsList =
440+
_ensureSanitizer(device).sanitizeDownEvent(
441+
button: event.button,
442+
buttons: event.buttons,
443+
);
400444
_convertEventsToPointerData(data: pointerData, event: event, detailsList: detailsList);
401445
_callback(pointerData);
402446
});
@@ -697,10 +741,11 @@ class _MouseAdapter extends _BaseAdapter with _WheelEventListenerMixin {
697741
void setup() {
698742
_addMouseEventListener('mousedown', (html.MouseEvent event) {
699743
final List<ui.PointerData> pointerData = <ui.PointerData>[];
700-
final bool isStartOfDrag = event.buttons == convertButtonToButtons(event.button);
701-
final List<_SanitizedDetails> sanitizedDetails = isStartOfDrag ?
702-
_sanitizer.sanitizeDownEvent(buttons: event.buttons) :
703-
_sanitizer.sanitizeMoveEvent(buttons: event.buttons);
744+
final List<_SanitizedDetails> sanitizedDetails =
745+
_sanitizer.sanitizeDownEvent(
746+
button: event.button,
747+
buttons: event.buttons,
748+
);
704749
_convertEventsToPointerData(data: pointerData, event: event, detailsList: sanitizedDetails);
705750
_callback(pointerData);
706751
});

lib/web_ui/lib/src/engine/pointer_converter.dart

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,38 @@ class PointerDataConverter {
364364
)
365365
);
366366
}
367-
assert(!_locationHasChanged(device, physicalX, physicalY));
367+
if (_locationHasChanged(device, physicalX, physicalY)) {
368+
assert(alreadyAdded);
369+
// Synthesize a hover of the pointer to the down location before
370+
// sending the down event, if necessary.
371+
result.add(
372+
_synthesizePointerData(
373+
timeStamp: timeStamp,
374+
change: ui.PointerChange.hover,
375+
kind: kind,
376+
device: device,
377+
physicalX: physicalX,
378+
physicalY: physicalY,
379+
buttons: 0,
380+
obscured: obscured,
381+
pressure: 0.0,
382+
pressureMin: pressureMin,
383+
pressureMax: pressureMax,
384+
distance: distance,
385+
distanceMax: distanceMax,
386+
size: size,
387+
radiusMajor: radiusMajor,
388+
radiusMinor: radiusMinor,
389+
radiusMin: radiusMin,
390+
radiusMax: radiusMax,
391+
orientation: orientation,
392+
tilt: tilt,
393+
platformData: platformData,
394+
scrollDeltaX: scrollDeltaX,
395+
scrollDeltaY: scrollDeltaY,
396+
)
397+
);
398+
}
368399
state.down = true;
369400
result.add(
370401
_generateCompletePointerData(
@@ -442,7 +473,37 @@ class PointerDataConverter {
442473
physicalX = state.x;
443474
physicalY = state.y;
444475
}
445-
assert(!_locationHasChanged(device, physicalX, physicalY));
476+
if (_locationHasChanged(device, physicalX, physicalY)) {
477+
// Synthesize a move of the pointer to the up location before
478+
// sending the up event, if necessary.
479+
result.add(
480+
_synthesizePointerData(
481+
timeStamp: timeStamp,
482+
change: ui.PointerChange.move,
483+
kind: kind,
484+
device: device,
485+
physicalX: physicalX,
486+
physicalY: physicalY,
487+
buttons: buttons,
488+
obscured: obscured,
489+
pressure: pressure,
490+
pressureMin: pressureMin,
491+
pressureMax: pressureMax,
492+
distance: distance,
493+
distanceMax: distanceMax,
494+
size: size,
495+
radiusMajor: radiusMajor,
496+
radiusMinor: radiusMinor,
497+
radiusMin: radiusMin,
498+
radiusMax: radiusMax,
499+
orientation: orientation,
500+
tilt: tilt,
501+
platformData: platformData,
502+
scrollDeltaX: scrollDeltaX,
503+
scrollDeltaY: scrollDeltaY,
504+
)
505+
);
506+
}
446507
state.down = false;
447508
result.add(
448509
_generateCompletePointerData(

0 commit comments

Comments
 (0)