dispatchTap method

Future<void> dispatchTap(
  1. double x,
  2. double y, {
  3. int holdMs = 40,
})

Dispatch a synthetic tap at (x, y) through Flutter's GestureBinding pointer pipeline — the same path a real pointer takes. Copied from ui_control_tools._dispatchTap.

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,
  );
}