hover method

Future<DriveStep> hover(
  1. dynamic target, {
  2. Duration? hold,
  3. Duration? settle,
})

Parks a mouse over target and holds it there, so whatever the app only shows to a mouse has time to appear.

Nothing about a live app has to cooperate for this to work: RendererBinding.dispatchEvent feeds every pointer event to MouseTracker before dispatching it, so a synthesized PointerHoverEvent drives MouseRegion, InkWell.onHover, a Tooltip and every WidgetState.hovered exactly as the platform's own mouse does. A tooltip is an OverlayEntry, which means it lands in the reply's texts like any other widget — a hover is how "does this control explain itself" becomes a question with a machine-readable answer.

hold is time on the lane's clock — real on a live app, exact on a tester — which is why it exists at all. A settle waits on frames, tickers and image decodes; the interesting half of a hover is very often a Timer — Tooltip.waitDuration — which schedules none of the three until it fires. Measured on an app whose theme sets 400ms: hover-and-settle reported settled: true at 80ms with no tooltip on screen, every time. See DriveLane.hold for what the hold actually watches.

The pointer stays where it is put. A mouse does not leave the screen because you pressed a key, so the hover outlives its step: a tap that follows still sees the control hovered, which is what you want when the thing to tap only appears on hover — and a navigate that follows leaves whatever is now under that coordinate hovered, which is not. Call unhover to end it.

Implementation

Future<DriveStep> hover(dynamic target, {Duration? hold, Duration? settle}) {
  return _act('hover', target, settle, (finder) async {
    await controller.sendEventToBinding(
      _mouse.hover(_contact(target, finder)),
    );
    _hovering = describeTarget(target);
    await lane.hold(hold ?? hoverHold);
  });
}