Repository navigation
Linux: mouse click events other than primary, secondary and tertiary are not recognized #152128
Copy link
Copy link
Open
Labels
P2Important issues not at the top of the work listImportant issues not at the top of the work lista: mouseIssues related to using a mouse or mouse supportIssues related to using a mouse or mouse supportengineflutter/engine related. See also e: labels.flutter/engine related. See also e: labels.found in release: 3.22Found to occur in 3.22Found to occur in 3.22found in release: 3.24Found to occur in 3.24Found to occur in 3.24has reproducible stepsThe issue has been confirmed reproducible and is ready to work onThe issue has been confirmed reproducible and is ready to work onplatform-linuxBuilding on or for Linux specificallyBuilding on or for Linux specificallyteam-linuxOwned by the Linux platform teamOwned by the Linux platform teamtriaged-linuxTriaged by the Linux platform teamTriaged by the Linux platform team
Description
Steps to reproduce
- create a Linux Flutter app with
flutter create --platforms=linux --org com.test my_app- Create an implementation of BaseTapGestureRecognizer
class NthTap extends BaseTapGestureRecognizer {
GestureTapDownCallback? onTapDown;
NthTap({
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 (onTapDown != null) {
invokeCallback<void>('onTapDown', () => onTapDown!(details));
}
}
@override
void handleTapUp({
required PointerDownEvent down,
required PointerUpEvent up,
}) {}
}- Use it inside the widget tree
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return RawGestureDetector(
gestures: <Type, GestureRecognizerFactory>{
NthTap: GestureRecognizerFactoryWithHandlers<NthTap>(
() => NthTap(),
(instance) =>
instance.onTapDown = (details) => ScaffoldMessenger.of(context)
..clearSnackBars()
..showSnackBar(SnackBar(
content: Center(
child: Text(
details.globalPosition.toString(),
),
),
behavior: SnackBarBehavior.floating,
)),
),
},
child: const Scaffold(),
);
}
}Expected results
All mouse buttons should be recognized
Actual results
Only 1.,2. and 3. buttons are recognized. 4th and 5th arent
Code sample
Code sample
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return RawGestureDetector(
gestures: <Type, GestureRecognizerFactory>{
NthTap: GestureRecognizerFactoryWithHandlers<NthTap>(
() => NthTap(),
(instance) =>
instance.onTapDown = (details) => ScaffoldMessenger.of(context)
..clearSnackBars()
..showSnackBar(SnackBar(
content: Center(
child: Text(
details.globalPosition.toString(),
),
),
behavior: SnackBarBehavior.floating,
)),
),
},
child: const Scaffold(),
);
}
}
class NthTap extends BaseTapGestureRecognizer {
GestureTapDownCallback? onTapDown;
NthTap({
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 (onTapDown != null) {
invokeCallback<void>('onTapDown', () => onTapDown!(details));
}
}
@override
void handleTapUp({
required PointerDownEvent down,
required PointerUpEvent up,
}) {}
}
Screenshots or Video
Screenshots / Video demonstration
Bildschirmaufzeichnung.vom.2024-07-22.20-18-47.mp4
Logs
Logs
[Paste your logs here]Flutter Doctor output
Doctor output
frederik@xps:~/my_app$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.19.5, on Ubuntu 24.04 LTS 6.8.0-31-generic, locale de_DE.UTF-8)
[!] Android toolchain - develop for Android devices (Android SDK version 33.0.0-rc2)
✗ No Java Development Kit (JDK) found; You must have the environment variable JAVA_HOME set and the java binary in your PATH. You can download the JDK from
https://www.oracle.com/technetwork/java/javase/downloads/.
[✓] Chrome - develop for the web
[✓] Linux toolchain - develop for Linux desktop
[!] Android Studio (not installed)
[✓] VS Code (version 1.91.1)
[✓] Connected device (2 available)
[✓] Network resources
! Doctor found issues in 2 categories.this also happens in 3.22.2 stable
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
P2Important issues not at the top of the work listImportant issues not at the top of the work lista: mouseIssues related to using a mouse or mouse supportIssues related to using a mouse or mouse supportengineflutter/engine related. See also e: labels.flutter/engine related. See also e: labels.found in release: 3.22Found to occur in 3.22Found to occur in 3.22found in release: 3.24Found to occur in 3.24Found to occur in 3.24has reproducible stepsThe issue has been confirmed reproducible and is ready to work onThe issue has been confirmed reproducible and is ready to work onplatform-linuxBuilding on or for Linux specificallyBuilding on or for Linux specificallyteam-linuxOwned by the Linux platform teamOwned by the Linux platform teamtriaged-linuxTriaged by the Linux platform teamTriaged by the Linux platform team
Activity
danagbemava-nc commentedon Jul 23, 2024
Reproducible using the code sample provided above.
I tested the code sample on web and it worked as expected. As pointed out in #115641 (comment), it appears that the engine does not forward the events.
flutter doctor -v
robert-ancell commentedon Feb 18, 2025
Some research on this:
kPointerButtonMousePrimary,kPointerButtonMouseSecondary,kPointerButtonMouseMiddle,kPointerButtonMouseBackandkPointerButtonMouseForwardin a bitfield.1<<5.GDK_BUTTON_PRIMARY,GDK_BUTTON_MIDDLEandGDK_BUTTON_SECONDARY.BTN_FORWARDmapped to 9 andBTN_BACKmapped to 10.Open questions:
kPointerButtonMouseBackandkPointerButtonMouseForward.robert-ancell commentedon Feb 18, 2025
On my mouse (MX Anywhere 2) tested on Ubuntu 24.10
Confusingly if we reverse the Linux mapping for the Wayland codes we get button 9 mapping to
BTN_EXTRAand button 8 mapping toBTN_SIDE.robert-ancell commentedon Feb 18, 2025
I've found some prior art - Epiphany (a web browser) hard codes button 8 and 9 as back and forward.
robert-ancell commentedon Feb 18, 2025
I was originally looking in the Chromium source to see how it did forward/back. I was unable to find the Linux input code for this - if anyone knows please link it here!
hatl commentedon Feb 27, 2025
here's what i found in Chromium - the Ozone platform abstraction layer:
https://github.com/chromium/chromium/blob/3a370e4849a00fee0601a5bae7826f964fa9b044/ui/events/ozone/evdev/input_injector_evdev.cc#L45
https://github.com/chromium/chromium/blob/3a370e4849a00fee0601a5bae7826f964fa9b044/ui/ozone/platform/wayland/host/wayland_pointer.cc#L137
https://chromium.googlesource.com/chromium/src/+/main/docs/ozone_overview.md
robert-ancell commentedon Feb 28, 2025
Good confirmation - they map BTN_EXTRA to forward, which matches what I calculated. They also map BTN_FORWARD as well, so perhaps there is a case where some devices use different codes? Epiphany doesn't do this, so I expect it doesn't happen.