Multi-Waypoint Mouse Gestures
humanize.humanized_path and tween_drag only interpolate a single
start → end hop. Real gestures — signatures, marquee / rubber-band selections,
dragging through several drop targets, shape gestures — need an arbitrary chain
of waypoints, with the button optionally held down across the whole path.
plan_path() is pure point math (reusing the named easings from
tween_drag) and is unit-testable on its own; move_along_path() and
drag_path() dispatch through an injectable sink so the gesture is
tested without real input. Imports no PySide6.
Headless API
from je_auto_control import (
plan_path, move_along_path, drag_path, path_easings,
)
# the eased point list through every waypoint (junctions de-duplicated)
plan_path([(100, 100), (400, 150), (400, 500)], per_segment_steps=20)
move_along_path([(100, 100), (400, 150), (400, 500)]) # hover a polyline
drag_path([(50, 50), (300, 50), (300, 300)], button="mouse_left") # L-drag
plan_path interpolates each consecutive pair with per_segment_steps eased
steps (easing is any name from path_easings() — linear /
ease_in_out_quad / ease_out_cubic / ease_in_cubic) and does not
duplicate the shared junction points. move_along_path emits move events
through the path; drag_path presses at the first waypoint, moves through the
whole path, and releases at the last — for multi-stop drags. Both take a sink
override for headless testing.
Executor commands
AC_move_along_path and AC_drag_path take waypoints (a JSON
[[x, y], ...] list) plus easing / per_segment_steps (and button
for the drag). Both are exposed as MCP tools (ac_move_along_path /
ac_drag_path) and as Script Builder commands under Mouse.