import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'dart:core'; import 'dart:ui'; class MouseCursorPainter extends CustomPainter { MouseCursorPainter({required this.offset, this.factor = 64.0}); final Offset offset; final double factor; @override void paint(Canvas canvas, Size size) { final path = Path() ..moveTo(offset.dx, offset.dy) ..lineTo(offset.dx, offset.dy + 48 * factor / 64) ..lineTo(offset.dx + 34 * factor / 64, offset.dy + 34 * factor / 64) ..close(); canvas.drawPath( path, Paint() ..color = Colors.black ..style = PaintingStyle.fill, ); canvas.drawPath( path, Paint() ..color = Colors.white ..style = PaintingStyle.stroke ..strokeJoin = StrokeJoin.miter ..strokeWidth = 3.5 * factor / 64, ); } @override bool shouldRepaint(covariant MouseCursorPainter oldDelegate) { return oldDelegate.offset != offset; } } class SoftwareMouseCursor extends StatelessWidget { SoftwareMouseCursor({Key? key, required this.child}) : super(key: key); final cursorPos = ValueNotifier(Offset.zero); final Widget child; @override Widget build(BuildContext context) { return Listener( onPointerDown: (event) { if (event.kind == PointerDeviceKind.mouse) { cursorPos.value = event.position; } }, onPointerMove: (event) { if (event.kind == PointerDeviceKind.mouse) { cursorPos.value = event.position; } }, onPointerUp: (event) { if (event.kind == PointerDeviceKind.mouse) { cursorPos.value = event.position; } }, onPointerHover: (event) { if (event.kind == PointerDeviceKind.mouse) { cursorPos.value = event.position; } }, behavior: HitTestBehavior.translucent, child: ValueListenableBuilder( valueListenable: cursorPos, builder: (context, pos, child) { return CustomPaint( foregroundPainter: MouseCursorPainter( offset: pos, factor: window.devicePixelRatio * 64, ), child: child, ); }, child: RepaintBoundary( child: child, ), ), ); } }