-
Notifications
You must be signed in to change notification settings - Fork 42
feat: add human-like Bezier mouse movement #148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Add mousetrajectory lib with Bernstein Bezier curves, jitter, easeOutQuad - MoveMouse supports smooth=true for curved path, smooth=false for instant - OpenAPI: smooth, steps (5-80), step_delay_ms (3-30) on MoveMouseRequest - Add cursor-trail demo (before/after instant vs Bezier) Co-authored-by: Cursor <[email protected]>
c1534a3 to
1c0a302
Compare
rgarcia
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesn't compile (see build)
- Fix demo README: kernel-images or kernel-images-private (not just private) - Use await browser.close() for clean demo script shutdown - Add named constants in mousetrajectory (boundsPadding, knotsCount, etc.) - Avoid mutating opts.MaxPoints; use local var instead - Add ctx.Done() check and sleepWithContext in Bezier step loop for cancellation - Clarify OpenAPI: steps/step_delay_ms ignored when smooth=false - Add TestHumanizeMouseTrajectory_ZeroLengthPath edge case Co-authored-by: Cursor <[email protected]>
Demo not needed in this repo. Co-authored-by: Cursor <[email protected]>
Co-authored-by: Cursor <[email protected]>
Align with Camoufox humanize:minTime/maxTime. Steps and delay auto-computed from path length and target duration. Co-authored-by: Cursor <[email protected]>
Co-authored-by: Cursor <[email protected]>
The deferred modifier key release was using the request context, which fails if cancelled mid-movement, leaving keys stuck. Use context.Background() to match the established cleanup pattern. Co-authored-by: Cursor <[email protected]>
- Eliminate duplicated validation by having MoveMouse call doMoveMouse directly instead of reimplementing resolution/bounds checks - Remove unnecessary moveMouseSmooth/moveMouseInstant wrapper functions - Compute trajectory MaxPoints from duration_sec so the requested duration is actually achievable (remove 30ms step delay upper clamp) - Skip zero-delta mousemove_relative steps to avoid no-op xdotool calls - Always pass -- to mousemove_relative for robustness with negative args - Remove redundant nil check in deferred HoldKeys cleanup - Clean up duration_sec OpenAPI description (remove internal references) - Rename defaultMaxTime/defaultMinTime to defaultMaxPoints/defaultMinPoints - Export MinPoints/MaxPoints constants from mousetrajectory package - Add clamping tests for MaxPoints below min and above max Co-authored-by: Cursor <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| dy := points[i][1] - points[i-1][1] | ||
| if dx == 0 && dy == 0 { | ||
| continue | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Skipped zero-delta steps break requested movement duration
Medium Severity
When consecutive trajectory points round to the same integer coordinates (common for short-distance moves or high point counts), the continue on dx == 0 && dy == 0 skips both the xdotool call and the sleepWithContext. The stepDelayMs was computed assuming all numSteps steps would execute a sleep, so skipping sleeps causes the actual movement duration to be significantly shorter than the requested DurationSec. For a 20-pixel move with DurationSec=2.0, the many duplicate integer points mean only a fraction of steps actually sleep, producing a sub-second movement instead of the intended 2 seconds.
Additional Locations (1)
| } | ||
| if output, err := defaultXdoTool.Run(ctx, args...); err != nil { | ||
| log.Error("xdotool keydown failed", "err", err, "output", string(output)) | ||
| return &executionError{msg: "failed to hold modifier keys"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empty HoldKeys array fails in smooth mode
Low Severity
When hold_keys is an empty array (non-nil pointer to []string{}), doMoveMouseSmooth enters the body.HoldKeys != nil block but appends no keydown args, then calls defaultXdoTool.Run(ctx) with zero arguments. This runs bare xdotool which prints help and exits with an error, causing a 500 "failed to hold modifier keys" response. doMoveMouseInstant handles this correctly since the empty loop just adds nothing to the shared args slice, which already contains mousemove x y.
| if dx == 0 && dy == 0 { | ||
| continue | ||
| } | ||
| args := []string{"mousemove_relative", "--", strconv.Itoa(dx), strconv.Itoa(dy)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Relative moves drift when Bezier goes off-screen
Medium Severity
The trajectory's boundsPadding = 80 places Bezier control knots up to 80 pixels beyond the start/end bounding box, so intermediate curve points can have negative coordinates when the mouse starts near a screen edge. Since doMoveMouseSmooth uses mousemove_relative, and the X11 server clamps the cursor at screen boundaries, the accumulated relative deltas no longer sum to the correct total displacement. The cursor ends up at the wrong final position, potentially missing subsequent click targets.


Checklist
Note
Medium Risk
Changes input simulation behavior and adds timing/cancellation logic around
xdotool, which could impact automation reliability (e.g., stuck modifiers, differing cursor paths) and is sensitive to environment-specific cursor state.Overview
MoveMousenow supports smooth cursor movement (default) using a new Bezier-based trajectory generator, falling back to instantxdotool mousemovewhensmooth=falseor trajectory generation is too short.The new smooth path uses the current cursor location, issues per-step
xdotool mousemove_relativeevents with small randomized timing jitter, and ensures held modifier keys are released even if the request context is cancelled. The OpenAPI/SDK model is updated withsmoothandduration_sec(0.05–5s) parameters, and a newserver/lib/mousetrajectorypackage (with tests) is introduced to generate the humanized point sequences.Written by Cursor Bugbot for commit 6397a13. This will update automatically on new commits. Configure here.