dispatchTap method
Dispatch a synthetic tap at (x, y) through Flutter's
GestureBinding pointer pipeline — the same path a real pointer
takes.
Implementation
Future<void> dispatchTap(double x, double y, {int holdMs = 40}) async {
final binding = GestureBinding.instance;
final position = Offset(x, y);
final now = SchedulerBinding.instance.currentSystemFrameTimeStamp;
final pointer = _nextPointer++;
final kind = _pointerKind();
// Explicit hit-test → dispatchEvent so the event traverses the same
// widget chain a real pointer would. Calling `handlePointerEvent`
// alone does NOT add the pointer to the binding's `_hitTests` map, so
// the matching `up` lands without a target and `onTap` never fires.
// Two-step (hitTest + dispatchEvent) matches Flutter's
// PointerEventConverter pipeline.
final downEvent = PointerDownEvent(
timeStamp: now,
pointer: pointer,
position: position,
kind: kind,
);
final hitResult = HitTestResult();
// Load-bearing two-step (hitTest + dispatchEvent). `hitTest` is
// deprecated in favour of the view-scoped variant, but the single-view
// form is exactly what the studio recipe relies on and switching would
// change the pipeline; keep it and silence the info.
// ignore: deprecated_member_use
binding.hitTest(hitResult, position);
binding.dispatchEvent(downEvent, hitResult);
await Future<void>.delayed(Duration(milliseconds: holdMs));
binding.dispatchEvent(
PointerUpEvent(
timeStamp: now + Duration(milliseconds: holdMs),
pointer: pointer,
position: position,
kind: kind,
),
hitResult,
);
}