From 590296b297c7e5a718ba2c7792febd1e61a47032 Mon Sep 17 00:00:00 2001 From: Amirhosein Akhlaghpoor Date: Tue, 28 Apr 2026 07:03:41 +0000 Subject: [PATCH] fix: iPad mouse down detection for physical mouse input (#14515) * fix: iPad mouse down detection Signed-off-by: Amirhossein Akhlaghpour * fix(ipad): remove redundant check Signed-off-by: fufesou * fix(ipad): Simple refactor Signed-off-by: fufesou --------- Signed-off-by: Amirhossein Akhlaghpour Signed-off-by: fufesou Co-authored-by: fufesou --- flutter/lib/models/input_model.dart | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart index 427072677..6fdffd796 100644 --- a/flutter/lib/models/input_model.dart +++ b/flutter/lib/models/input_model.dart @@ -1495,6 +1495,16 @@ class InputModel { return false; } + /// iOS may emit a synthesized touch event after a real mouse click. + /// This helper ignores touch-down events that arrive shortly after a mouse down, + /// even when the position is far (e.g., near the top edge). + bool _shouldIgnoreTouchAfterMouse(int nowMs) { + if (!isIOS) return false; + const int kTouchAfterMouseWindowMs = 700; + final dt = nowMs - _lastMouseDownTimeMs; + return dt >= 0 && dt < kTouchAfterMouseWindowMs; + } + void onPointDownImage(PointerDownEvent e) { debugPrint("onPointDownImage ${e.kind}"); _stopFling = true; @@ -1507,6 +1517,9 @@ class InputModel { // Track mouse down events for duplicate detection on iOS. final nowMs = DateTime.now().millisecondsSinceEpoch; if (e.kind == ui.PointerDeviceKind.mouse) { + if (!isPhysicalMouse.value) { + isPhysicalMouse.value = true; + } _lastMouseDownTimeMs = nowMs; _lastMouseDownPos = e.position; } @@ -1516,6 +1529,10 @@ class InputModel { } if (e.kind != ui.PointerDeviceKind.mouse) { + // Ignore duplicate touch events that follow a recent mouse click (iOS Magic Mouse issue). + if (isPhysicalMouse.value && _shouldIgnoreTouchAfterMouse(nowMs)) { + return; + } if (isPhysicalMouse.value) { isPhysicalMouse.value = false; }