Track mouse movements in Flutter even when mouse button is pressed

Viewed 514

I have created a small Flutter sample app for the Linux (desktop) to display the current mouse cursor position. This works quite well, but only as long as no mouse button is pressed.

Issue: As long as a mouse button is pressed, the text is not updated with the current mouse cursor position.

The method specified in the property onHover of the MouseRegion widget is no longer called when the mouse button is pressed, which makes sense, but unfortunately I can't find another property suitable for my purpose.

What is the best way to always track mouse movements, no matter if a mouse button is currently pressed or not?

main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Mouse Tracker Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyMouseTracker(),
    );
  }
}

class MyMouseTracker extends StatefulWidget {
  MyMouseTracker({Key? key}) : super(key: key);

  @override
  _MyMouseTrackerState createState() => _MyMouseTrackerState();
}

class _MyMouseTrackerState extends State<MyMouseTracker> {
  double x = 0.0;
  double y = 0.0;

  void _updateLocation(PointerEvent details) {
    setState(() {
      x = details.position.dx;
      y = details.position.dy;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MouseRegion(
      onHover: _updateLocation,
      child: Scaffold(
        body: Center(
          child: Text(
            'The cursor is here: (${x.toStringAsFixed(2)}, ${y.toStringAsFixed(2)})',
          ),
        ),
      ),
    );
  }
}

main.dart with solution from @sydnal

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Mouse Tracker Demo',
      home: MyMouseTracker(),
    );
  }
}

class MyMouseTracker extends StatefulWidget {
  MyMouseTracker({Key? key}) : super(key: key);

  @override
  _MyMouseTrackerState createState() => _MyMouseTrackerState();
}

class _MyMouseTrackerState extends State<MyMouseTracker> {
  double x = 0.0;
  double y = 0.0;

  void _updateLocation(PointerEvent details) {
    setState(() {
      x = details.position.dx;
      y = details.position.dy;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Listener(
      behavior: HitTestBehavior.opaque,
      onPointerHover: _updateLocation, // not pressed
      onPointerMove: _updateLocation, // pressed
      child: Scaffold(
        body: Center(
          child: Text(
            'Mouse pointer position: (${x.toStringAsFixed(2)}, ${y.toStringAsFixed(2)})',
          ),
        ),
      ),
    );
  }
}
1 Answers

There is another widget called Listener that reports mouse events in both button pressed and not pressed states.

Listener(behavior: HitTestBehavior.opaque,
        onPointerHover: _onPointerHover, // not pressed
        onPointerMove: _onPointerMove,   // pressed
        child: ...);

I had to set the hit test behaviour as opaque as there weren't any children that handled the events themselves, which may or may not be applicable in your situation. (Default is deferToChild)

Related