@@ -415,41 +415,43 @@ class _ButtonSanitizer {
415415 );
416416 }
417417
418- _SanitizedDetails ? sanitizeUpEvent () {
418+ _SanitizedDetails ? sanitizeMissingRightClickUp ({required int buttons}) {
419+ final int newPressedButtons = _htmlButtonsToFlutterButtons (buttons);
420+ // This could happen when RMB is clicked and released but no pointerup
421+ // event was received because context menu was shown.
422+ if (_pressedButtons != 0 && newPressedButtons == 0 ) {
423+ _pressedButtons = 0 ;
424+ return _SanitizedDetails (
425+ change: ui.PointerChange .up,
426+ buttons: _pressedButtons,
427+ );
428+ }
429+ return null ;
430+ }
431+
432+ _SanitizedDetails ? sanitizeUpEvent ({required int ? buttons}) {
419433 // The pointer could have been released by a `pointerout` event, in which
420434 // case `pointerup` should have no effect.
421435 if (_pressedButtons == 0 ) {
422436 return null ;
423437 }
424- _pressedButtons = 0 ;
425- return _SanitizedDetails (
426- change: ui.PointerChange .up,
427- buttons: _pressedButtons,
428- );
429- }
430438
431- _SanitizedDetails ? sanitizeUpEventWithButtons ({required int buttons}) {
432- final int newPressedButtons = _htmlButtonsToFlutterButtons (buttons);
433- // This could happen when the context menu is active and the user clicks
434- // RMB somewhere else. The browser sends a down event with `buttons:0`.
435- //
436- // In this case, we keep the old `buttons` value so we don't confuse the
437- // framework.
438- if (_pressedButtons != 0 && newPressedButtons == 0 ) {
439+ _pressedButtons = _htmlButtonsToFlutterButtons (buttons ?? 0 );
440+
441+ if (_pressedButtons == 0 ) {
442+ // All buttons have been released.
443+ return _SanitizedDetails (
444+ change: ui.PointerChange .up,
445+ buttons: _pressedButtons,
446+ );
447+ } else {
448+ // There are still some unreleased buttons, we shouldn't send an up event
449+ // yet. Instead we send a move event to update the position of the pointer.
439450 return _SanitizedDetails (
440451 change: ui.PointerChange .move,
441452 buttons: _pressedButtons,
442453 );
443454 }
444-
445- _pressedButtons = newPressedButtons;
446-
447- return _SanitizedDetails (
448- change: _pressedButtons == 0
449- ? ui.PointerChange .hover
450- : ui.PointerChange .move,
451- buttons: _pressedButtons,
452- );
453455 }
454456
455457 _SanitizedDetails sanitizeCancelEvent () {
@@ -462,7 +464,6 @@ class _ButtonSanitizer {
462464}
463465
464466typedef _PointerEventListener = dynamic Function (html.PointerEvent event);
465- const int kContextMenuButton = 2 ;
466467
467468/// Adapter class to be used with browsers that support native pointer events.
468469///
@@ -512,54 +513,45 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
512513 final int device = event.pointerId! ;
513514 final List <ui.PointerData > pointerData = < ui.PointerData > [];
514515 final _ButtonSanitizer sanitizer = _ensureSanitizer (device);
515- if (event.button == kContextMenuButton) {
516- _handleMissingRightMouseUpEvent (sanitizer,
517- sanitizer._pressedButtons,
518- sanitizer._pressedButtons & ~ kContextMenuButton,
519- event,
520- pointerData);
516+ final _SanitizedDetails ? up =
517+ sanitizer.sanitizeMissingRightClickUp (buttons: event.buttons! );
518+ if (up != null ) {
519+ _convertEventsToPointerData (data: pointerData, event: event, details: up);
521520 }
522- final _SanitizedDetails details =
521+ final _SanitizedDetails down =
523522 sanitizer.sanitizeDownEvent (
524523 button: event.button,
525524 buttons: event.buttons! ,
526525 );
527- _convertEventsToPointerData (data: pointerData, event: event, details: details );
526+ _convertEventsToPointerData (data: pointerData, event: event, details: down );
528527 _callback (pointerData);
529528 });
530529
531530 _addPointerEventListener ('pointermove' , (html.PointerEvent event) {
532531 final int device = event.pointerId! ;
533532 final _ButtonSanitizer sanitizer = _ensureSanitizer (device);
534533 final List <ui.PointerData > pointerData = < ui.PointerData > [];
535- final int buttonsBeforeEvent = sanitizer._pressedButtons;
536- final Iterable <_SanitizedDetails > detailsList = _expandEvents (event).map (
537- (html.PointerEvent expandedEvent) {
538- return sanitizer.sanitizeMoveEvent (buttons: expandedEvent.buttons! );
539- },
540- );
541- _handleMissingRightMouseUpEvent (
542- sanitizer,
543- buttonsBeforeEvent,
544- (sanitizer._inferDownFlutterButtons (event.button, event.buttons! )
545- & kContextMenuButton),
546- event,
547- pointerData);
548- for (_SanitizedDetails details in detailsList) {
549- _convertEventsToPointerData (data: pointerData, event: event, details: details);
534+ final List <html.PointerEvent > expandedEvents = _expandEvents (event);
535+ for (final html.PointerEvent event in expandedEvents) {
536+ final _SanitizedDetails ? up = sanitizer.sanitizeMissingRightClickUp (buttons: event.buttons! );
537+ if (up != null ) {
538+ _convertEventsToPointerData (data: pointerData, event: event, details: up);
539+ }
540+ final _SanitizedDetails move = sanitizer.sanitizeMoveEvent (buttons: event.buttons! );
541+ _convertEventsToPointerData (data: pointerData, event: event, details: move);
550542 }
551543 _callback (pointerData);
552544 }, acceptOutsideGlasspane: true );
553545
554546 _addPointerEventListener ('pointerup' , (html.PointerEvent event) {
555547 final int device = event.pointerId! ;
556548 final List <ui.PointerData > pointerData = < ui.PointerData > [];
557- final _SanitizedDetails ? details = _getSanitizer (device).sanitizeUpEvent ();
549+ final _SanitizedDetails ? details = _getSanitizer (device).sanitizeUpEvent (buttons : event.buttons );
558550 _removePointerIfUnhoverable (event);
559551 if (details != null ) {
560552 _convertEventsToPointerData (data: pointerData, event: event, details: details);
553+ _callback (pointerData);
561554 }
562- _callback (pointerData);
563555 }, acceptOutsideGlasspane: true );
564556
565557 // A browser fires cancel event if it concludes the pointer will no longer
@@ -578,39 +570,6 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
578570 });
579571 }
580572
581- // Handle special case where right mouse button no longer is pressed.
582- // We need to synthesize right mouse up, otherwise drag gesture will fail
583- // to complete or multiple RMB down events will lead to wrong state.
584- void _handleMissingRightMouseUpEvent (_ButtonSanitizer sanitizer,
585- int buttonsBeforeEvent, int buttonsAfterEvent, html.PointerEvent event,
586- List <ui.PointerData > pointerData) {
587- if ((buttonsBeforeEvent & kContextMenuButton) != 0 &&
588- buttonsAfterEvent == 0 ) {
589- final ui.PointerDeviceKind kind =
590- _pointerTypeToDeviceKind (event.pointerType! );
591- final int device = kind == ui.PointerDeviceKind .mouse
592- ? _mouseDeviceId : event.pointerId! ;
593- final double tilt = _computeHighestTilt (event);
594- final Duration timeStamp = _BaseAdapter ._eventTimeStampToDuration (event.timeStamp! );
595- sanitizer._pressedButtons & = ~ kContextMenuButton;
596- _pointerDataConverter.convert (
597- pointerData,
598- change: ui.PointerChange .up,
599- timeStamp: timeStamp,
600- kind: kind,
601- signalKind: ui.PointerSignalKind .none,
602- device: device,
603- physicalX: event.client.x.toDouble () * ui.window.devicePixelRatio,
604- physicalY: event.client.y.toDouble () * ui.window.devicePixelRatio,
605- buttons: sanitizer._pressedButtons,
606- pressure: event.pressure as double ,
607- pressureMin: 0.0 ,
608- pressureMax: 1.0 ,
609- tilt: tilt,
610- );
611- }
612- }
613-
614573 // For each event that is de-coalesced from `event` and described in
615574 // `details`, convert it to pointer data and store in `data`.
616575 void _convertEventsToPointerData ({
@@ -852,12 +811,10 @@ class _MouseAdapter extends _BaseAdapter with _WheelEventListenerMixin {
852811 void setup () {
853812 _addMouseEventListener ('mousedown' , (html.MouseEvent event) {
854813 final List <ui.PointerData > pointerData = < ui.PointerData > [];
855- if (event.button == kContextMenuButton) {
856- _handleMissingRightMouseUpEvent (_sanitizer,
857- _sanitizer._pressedButtons,
858- _sanitizer._pressedButtons & ~ kContextMenuButton,
859- event,
860- pointerData);
814+ final _SanitizedDetails ? up =
815+ _sanitizer.sanitizeMissingRightClickUp (buttons: event.buttons! );
816+ if (up != null ) {
817+ _convertEventsToPointerData (data: pointerData, event: event, details: up);
861818 }
862819 final _SanitizedDetails sanitizedDetails =
863820 _sanitizer.sanitizeDownEvent (
@@ -870,60 +827,29 @@ class _MouseAdapter extends _BaseAdapter with _WheelEventListenerMixin {
870827
871828 _addMouseEventListener ('mousemove' , (html.MouseEvent event) {
872829 final List <ui.PointerData > pointerData = < ui.PointerData > [];
873- final int buttonsBeforeEvent = _sanitizer._pressedButtons;
874- _handleMissingRightMouseUpEvent (
875- _sanitizer,
876- buttonsBeforeEvent,
877- (_sanitizer._inferDownFlutterButtons (event.button, event.buttons! )
878- & kContextMenuButton),
879- event,
880- pointerData);
881- final _SanitizedDetails sanitizedDetails = _sanitizer.sanitizeMoveEvent (buttons: event.buttons! );
882- _convertEventsToPointerData (data: pointerData, event: event, details: sanitizedDetails);
830+ final _SanitizedDetails ? up = _sanitizer.sanitizeMissingRightClickUp (buttons: event.buttons! );
831+ if (up != null ) {
832+ _convertEventsToPointerData (data: pointerData, event: event, details: up);
833+ }
834+ final _SanitizedDetails move = _sanitizer.sanitizeMoveEvent (buttons: event.buttons! );
835+ _convertEventsToPointerData (data: pointerData, event: event, details: move);
883836 _callback (pointerData);
884837 }, acceptOutsideGlasspane: true );
885838
886839 _addMouseEventListener ('mouseup' , (html.MouseEvent event) {
887840 final List <ui.PointerData > pointerData = < ui.PointerData > [];
888- final bool isEndOfDrag = event.buttons == 0 ;
889- final _SanitizedDetails sanitizedDetails = isEndOfDrag ?
890- _sanitizer.sanitizeUpEvent ()! :
891- _sanitizer.sanitizeUpEventWithButtons (buttons: event.buttons! )! ;
892- _convertEventsToPointerData (data: pointerData, event: event, details: sanitizedDetails);
893- _callback (pointerData);
841+ final _SanitizedDetails ? sanitizedDetails = _sanitizer.sanitizeUpEvent (buttons: event.buttons);
842+ if (sanitizedDetails != null ) {
843+ _convertEventsToPointerData (data: pointerData, event: event, details: sanitizedDetails);
844+ _callback (pointerData);
845+ }
894846 }, acceptOutsideGlasspane: true );
895847
896848 _addWheelEventListener ((html.Event event) {
897849 _handleWheelEvent (event);
898850 });
899851 }
900852
901- // Handle special case where right mouse button no longer is pressed.
902- // We need to synthesize right mouse up, otherwise drag gesture will fail
903- // to complete or multiple RMB down events will lead to wrong state.
904- void _handleMissingRightMouseUpEvent (_ButtonSanitizer sanitizer,
905- int buttonsBeforeEvent, int buttonsAfterEvent, html.MouseEvent event,
906- List <ui.PointerData > pointerData) {
907- if ((buttonsBeforeEvent & kContextMenuButton) != 0 &&
908- buttonsAfterEvent == 0 ) {
909- sanitizer._pressedButtons & = ~ 2 ;
910- _pointerDataConverter.convert (
911- pointerData,
912- change: ui.PointerChange .up,
913- timeStamp: _BaseAdapter ._eventTimeStampToDuration (event.timeStamp! ),
914- kind: ui.PointerDeviceKind .mouse,
915- signalKind: ui.PointerSignalKind .none,
916- device: _mouseDeviceId,
917- physicalX: event.client.x.toDouble () * ui.window.devicePixelRatio,
918- physicalY: event.client.y.toDouble () * ui.window.devicePixelRatio,
919- buttons: _sanitizer._pressedButtons,
920- pressure: 1.0 ,
921- pressureMin: 0.0 ,
922- pressureMax: 1.0 ,
923- );
924- }
925- }
926-
927853 // For each event that is de-coalesced from `event` and described in
928854 // `detailsList`, convert it to pointer data and store in `data`.
929855 void _convertEventsToPointerData ({
0 commit comments