Skip to content

Feature Request: add fourth and fifth mouse button to Gesture detector #115641

Open

Description

@Feichtmeier

For desktop applications it would be useful to use the mouse to navigate back and forward in the navigator with the fifths and forth mouse button. It looks like only 1., 2. and 3. mouse buttons are covered in GestureDetector

In this video I covered it with two finger trackpad gesture detector but most desktop users like mice

2022-11-18.12-02-51.mp4

Activity

  1. darshankawar commented on Nov 18, 2022

    @darshankawar
    Member

    Thanks for the report. Treating this as proposal / feature request.

    There's another proposal to support middle mouse button scrolling: #66537.

  2. added
    c: new featureNothing broken; request for a new capability
    frameworkflutter/packages/flutter repository. See also f: labels.
    f: gesturesflutter/packages/flutter/gestures repository.
    c: proposalA detailed proposal for a change to Flutter
    and removed
    in triagePresently being triaged by the triage team
    on Nov 18, 2022
  3. gspencergoog commented on Dec 1, 2022

    @gspencergoog
    Contributor

    Since we already have the data in the PointerEvent.buttons bitfield, it is still possible to find out if a tap was made using the fourth and fifth mouse button, but it's not clear that we want to add that to the higher level GestureDetector API, since it would involve increasing the number of parameters and callbacks significantly.

    (Desktop Triage)

    cc @dkwingsmt

  4. added
    P3Issues that are less important to the Flutter project
    on Dec 1, 2022
  5. dkwingsmt commented on Dec 1, 2022

    @dkwingsmt
    Contributor

    Currently TapGestureReconizer will not recognize the 4th or 5th button since they are not included in addAllowedPointer.

    Moreover, adding too many methods to GestureDetector needs careful discussion, because this class is meant to be a hub for common gestures.

    However, having tap gestures on the 4th and 5th buttons requires only trivial work already. Here's what you can do:

    Other gestures do not support buttons this way. But we can always refactor them in the same way as tap. Are there any other gestures you have in mind that need this?

  6. Feichtmeier commented on Dec 1, 2022

    @Feichtmeier
    Author

    Currently TapGestureReconizer will not recognize the 4th or 5th button since they are not included in addAllowedPointer.

    Moreover, adding too many methods to GestureDetector needs careful discussion, because this class is meant to be a hub for common gestures.

    However, having tap gestures on the 4th and 5th buttons requires only trivial work already. Here's what you can do:

    * Create a `FourthButtonTapGestureRecognizer`, which inherits `BaseTapGestureRecognizer`.
      
      * `BaseTapGestureRecognizer` is created with extensibility in mind and supports any mouse buttons. Check out [the definition for `TapGestureRecognizer`](https://github.com/flutter/flutter/blob/3b15d6a501bd89b2860c116c2ae698d96002522d/packages/flutter/lib/src/gestures/tap.dart#L554).
    
    * Build a `RawGestureDetector` with your `FourthButtonTapGestureRecognizer`.
      
      * Check out [the definition for `GestureDetector`](https://github.com/flutter/flutter/blob/3b15d6a501bd89b2860c116c2ae698d96002522d/packages/flutter/lib/src/widgets/gesture_detector.dart#L1019).
    

    Other gestures do not support buttons this way. But we can always refactor them in the same way as tap. Are there any other gestures you have in mind that need this?

    Thanks for the detailed answer! I will try this
    No, 4th and 5th mouse button tap/click should be enough here I think :)

  7. flutter-triage-bot commented on Jun 7, 2024

    @flutter-triage-bot

    The triaged-desktop label is irrelevant if there is no team-desktop label or fyi-desktop label.

  8. Feichtmeier commented on Jul 20, 2024

    @Feichtmeier
    Author

    Currently TapGestureReconizer will not recognize the 4th or 5th button since they are not included in addAllowedPointer.

    Moreover, adding too many methods to GestureDetector needs careful discussion, because this class is meant to be a hub for common gestures.

    However, having tap gestures on the 4th and 5th buttons requires only trivial work already. Here's what you can do:

    * Create a `FourthButtonTapGestureRecognizer`, which inherits `BaseTapGestureRecognizer`.
      
      * `BaseTapGestureRecognizer` is created with extensibility in mind and supports any mouse buttons. Check out [the definition for `TapGestureRecognizer`](https://github.com/flutter/flutter/blob/3b15d6a501bd89b2860c116c2ae698d96002522d/packages/flutter/lib/src/gestures/tap.dart#L554).
    
    * Build a `RawGestureDetector` with your `FourthButtonTapGestureRecognizer`.
      
      * Check out [the definition for `GestureDetector`](https://github.com/flutter/flutter/blob/3b15d6a501bd89b2860c116c2ae698d96002522d/packages/flutter/lib/src/widgets/gesture_detector.dart#L1019).
    

    Other gestures do not support buttons this way. But we can always refactor them in the same way as tap. Are there any other gestures you have in mind that need this?

    Hey 👋
    Two years later I actually tried your suggestion :)
    For some reason only the 3. button on the mouse wheel click works. Every value higher than 4 in down.buttons is not recognized at all

    class NthTap extends BaseTapGestureRecognizer {
      GestureTapDownCallback? onTapDown;
    
      final int n;
    
      NthTap({
        super.debugOwner,
        super.supportedDevices,
        super.allowedButtonsFilter,
        required this.n,
      });
    
      @override
      void handleTapCancel({
        required PointerDownEvent down,
        PointerCancelEvent? cancel,
        required String reason,
      }) {}
    
      @override
      void handleTapDown({required PointerDownEvent down}) {
        final TapDownDetails details = TapDownDetails(
          globalPosition: down.position,
          localPosition: down.localPosition,
          kind: getKindForPointer(down.pointer),
        );
    
        if (down.buttons == n && onTapDown != null) {
          invokeCallback<void>('onTapDown', () => onTapDown!(details));
        }
      }
    
      @override
      void handleTapUp({
        required PointerDownEvent down,
        required PointerUpEvent up,
      }) {}
    }
  9. bleroux commented on Jul 22, 2024

    @bleroux
    Contributor

    Hey @Feichtmeier,
    If you tried it on Linux, this is probably related to the engine not forwarding such events, see https://github.com/flutter/engine/blob/207f088f73cb00fa05aff170030df891d62cadf5/shell/platform/linux/fl_view.cc#L156-L179

  10. Feichtmeier commented on Jul 22, 2024

    @Feichtmeier
    Author

    Hey @Feichtmeier, If you tried it on Linux, this is probably related to the engine not forwarding such events, see https://github.com/flutter/engine/blob/207f088f73cb00fa05aff170030df891d62cadf5/shell/platform/linux/fl_view.cc#L156-L179

    Thanks, I created a new issue for this
    #152128

  11. Merthan commented on Aug 4, 2024

    @Merthan

    Surprising that this hasn't been added/fixed yet

    I struggled with this a bit but for other beginners I'm adding ready to go code, mainly based on dkwingsmt answer and Feichtmeiers published code here and in his other issue, all credits to them:

    kBackMouseButton is part of the events.dart class, kForwardMouseButton etc also have the correct value there.

    class MouseBackRecognizer extends BaseTapGestureRecognizer {
      GestureTapDownCallback? onTapDown;
    
      MouseBackRecognizer({
        super.debugOwner,
        super.supportedDevices,
        super.allowedButtonsFilter,
      });
    
      @override
      void handleTapCancel({
        required PointerDownEvent down,
        PointerCancelEvent? cancel,
        required String reason,
      }) {}
    
      @override
      void handleTapDown({required PointerDownEvent down}) {
        final TapDownDetails details = TapDownDetails(
          globalPosition: down.position,
          localPosition: down.localPosition,
          kind: getKindForPointer(down.pointer),
        );
    
        if (down.buttons == kBackMouseButton && onTapDown != null) {
          invokeCallback<void>('onTapDown', () => onTapDown!(details));
        }
      }
    
      @override
      void handleTapUp({
        required PointerDownEvent down,
        required PointerUpEvent up,
      }) {}
    }

    And then call it like this for example:

    child: RawGestureDetector(
            gestures: <Type, GestureRecognizerFactory>{
              MouseBackRecognizer: GestureRecognizerFactoryWithHandlers<MouseBackRecognizer>(
                    () => MouseBackRecognizer(),
                    (instance) => instance.onTapDown = (details) => _doWhateverYouWantHere(context),
              ),
            },
            child: widget.child,
          ),
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Issues that are less important to the Flutter projecta: desktopRunning on desktopc: new featureNothing broken; request for a new capabilityc: proposalA detailed proposal for a change to Flutterf: gesturesflutter/packages/flutter/gestures repository.frameworkflutter/packages/flutter repository. See also f: labels.team-frameworkOwned by Framework teamtriaged-frameworkTriaged by Framework team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions