Usage Guide
This guide provides comprehensive examples and explanations for using WindMouse in your projects.
Basic Usage
PyAutoGUI Backend (Cross-Platform)
The PyAutoGUI backend is the recommended choice for cross-platform projects:
from windmouse.pyautogui_controller import PyautoguiMouseController
from windmouse import Coordinate
# Create a controller instance
mouse = PyautoguiMouseController()
# Set the destination coordinates
mouse.dest_position = (Coordinate(800), Coordinate(600))
# Move to the target with default settings
mouse.move_to_target()
AutoHotkey Backend (Windows)
For Windows-specific projects, the AHK backend may provide smoother movements:
from ahk import AHK
from windmouse.ahk_controller import AHKMouseController
from windmouse import Coordinate
# Initialize AHK
ahk = AHK()
# Create a controller instance with AHK
mouse = AHKMouseController(ahk)
# Set destination and move
mouse.dest_position = (Coordinate(1920), Coordinate(1080))
mouse.move_to_target()
Understanding Movement Parameters
The move_to_target() method accepts several parameters that control the movement behavior:
tick_delay
Type: float (default: 0)
Description: Sleep time in seconds between each movement step. Higher values slow down the overall movement.
Use Cases:
0 (default): Maximum speed, no delay
0.001-0.01: Natural speed for most applications
0.05-0.1: Slower, more deliberate movements
Example:
# Fast movement (no delay)
mouse.move_to_target(tick_delay=0)
# Natural speed
mouse.move_to_target(tick_delay=0.005)
# Slow, deliberate movement
mouse.move_to_target(tick_delay=0.1)
step_duration
Type: float (default: 0.1)
Description: Duration in seconds for each individual movement step. This affects the smoothness and speed of the transition between points.
Lower values (0.01-0.05): Faster, more abrupt movements
Medium values (0.1-0.2): Natural, smooth movements
Higher values (0.5-1.0): Very slow, exaggerated movements
Example:
# Quick, snappy movement
mouse.move_to_target(step_duration=0.05)
# Smooth, natural movement (default)
mouse.move_to_target(step_duration=0.1)
# Slow, deliberate movement
mouse.move_to_target(step_duration=0.5)
Fine-Tuning the Physics
The WindMouse algorithm simulates physical forces to create realistic movement. You can customize these parameters when creating the controller.
Understanding the Parameters
- gravity_magnitude (default:
9) Strength of the attractive force pulling the cursor toward the target.
Higher values (12-15): More direct paths, faster convergence
Lower values (5-7): More curved, wandering paths
- wind_magnitude (default:
3) Amount of random “wind” force creating curvature and unpredictability.
Higher values (5-10): More curved, chaotic paths
Lower values (1-2): Straighter, more predictable paths
- max_step (default:
15) Maximum velocity/speed of the cursor (measured in pixels per step).
Higher values (20-30): Faster overall movement
Lower values (5-10): Slower, more controlled movement
- damped_distance (default:
12) Distance from target (in pixels) where the movement begins to slow down and wind effects decrease.
Higher values (20-30): Slows down earlier, more cautious approach
Lower values (5-10): Maintains speed closer to target
Customization Examples
Aggressive, Fast Movement:
mouse = PyautoguiMouseController(
gravity_magnitude=15, # Strong pull toward target
wind_magnitude=1, # Minimal curvature
max_step=25, # High speed
damped_distance=8 # Late slowdown
)
Natural, Human-like Movement (Default):
mouse = PyautoguiMouseController(
gravity_magnitude=9,
wind_magnitude=3,
max_step=15,
damped_distance=12
)
Cautious, Curved Movement:
mouse = PyautoguiMouseController(
gravity_magnitude=6, # Weaker attraction
wind_magnitude=7, # High curvature
max_step=10, # Lower speed
damped_distance=25 # Early slowdown
)
Drunk/Chaotic Movement (for testing detection):
mouse = PyautoguiMouseController(
gravity_magnitude=5,
wind_magnitude=10,
max_step=8,
damped_distance=30
)
Advanced Usage Patterns
Setting Start and Destination Separately
You can set start and destination coordinates independently:
mouse = PyautoguiMouseController()
# Set start position explicitly
mouse.start_position = (Coordinate(100), Coordinate(100))
# Set destination
mouse.dest_position = (Coordinate(500), Coordinate(500))
# Or set coordinates individually
mouse.dest_x = Coordinate(800)
mouse.dest_y = Coordinate(600)
mouse.move_to_target()
If you don’t set start_position, the controller automatically uses the current mouse position.
Multiple Sequential Movements
Chain multiple movements together for complex patterns:
from windmouse.pyautogui_controller import PyautoguiMouseController
from windmouse import Coordinate
import time
mouse = PyautoguiMouseController()
# Define a series of waypoints
waypoints = [
(Coordinate(200), Coordinate(200)),
(Coordinate(600), Coordinate(200)),
(Coordinate(600), Coordinate(600)),
(Coordinate(200), Coordinate(600)),
(Coordinate(400), Coordinate(400)), # Return to center
]
# Move through each waypoint
for dest in waypoints:
mouse.dest_position = dest
mouse.move_to_target(tick_delay=0.005)
time.sleep(0.5) # Pause at each waypoint
Manual Tick-Based Movement
For advanced control, you can manually call tick() instead of move_to_target():
import time
mouse = PyautoguiMouseController()
mouse.dest_position = (Coordinate(800), Coordinate(600))
# Manual control loop
while mouse.tick(step_duration=0.1):
# Do something between each step
time.sleep(0.01)
# You could check conditions and break early
if some_condition:
break
This is useful when you need to:
Check conditions during movement
Synchronize with other operations
Implement custom stopping logic
Drag and Drop Operations
Complete drag-and-drop example:
from windmouse.pyautogui_controller import PyautoguiMouseController
from windmouse import Coordinate, HoldMouseButton
import time
mouse = PyautoguiMouseController()
# Move to the item to drag
mouse.dest_position = (Coordinate(300), Coordinate(300))
mouse.move_to_target()
time.sleep(0.2) # Brief pause
# Drag to destination
mouse.dest_position = (Coordinate(700), Coordinate(500))
mouse.move_to_target(hold_button=HoldMouseButton.LEFT)
time.sleep(0.1) # Brief pause after drop
Context Manager Pattern
While not built-in, you can create a context manager for cleanup:
from contextlib import contextmanager
from windmouse.pyautogui_controller import PyautoguiMouseController
@contextmanager
def windmouse_controller(**kwargs):
"""Context manager for WindMouse controller."""
controller = PyautoguiMouseController(**kwargs)
try:
yield controller
finally:
# Cleanup if needed
pass
# Usage
with windmouse_controller(gravity_magnitude=10) as mouse:
mouse.dest_position = (Coordinate(800), Coordinate(600))
mouse.move_to_target()
Performance Considerations
Movement Speed vs. Realism
There’s a trade-off between speed and realism:
Fast movements: Low
tick_delay(0-0.001), lowstep_duration(0.01-0.05)Realistic movements: Medium
tick_delay(0.005-0.01), mediumstep_duration(0.1-0.2)Exaggerated realism: Higher values, more pronounced curves (
wind_magnitude5-10)
Backend Performance
PyAutoGUI: Slight overhead from Python → OS calls, but very portable
AutoHotkey: Native Windows integration, potentially smoother on Windows systems
For maximum performance:
# Minimal delay configuration
mouse.move_to_target(tick_delay=0, step_duration=0.01)
Screen Resolution Considerations
The WindMouse algorithm scales well across resolutions, but you may want to adjust parameters for different screen sizes:
import pyautogui
# Get screen dimensions
screen_width, screen_height = pyautogui.size()
# Adjust max_step based on screen size
max_step_adjusted = int(screen_width / 100) # ~19 for 1920px width
mouse = PyautoguiMouseController(max_step=max_step_adjusted)
Best Practices
Always use Coordinate type:
# Good mouse.dest_position = (Coordinate(800), Coordinate(600)) # Avoid (type checker will complain) mouse.dest_position = (800, 600)
Add small delays between operations:
import time mouse.move_to_target() time.sleep(0.1) # Brief pause before next action # Click or other operation
Test parameter combinations:
Different applications may be more or less sensitive to mouse patterns. Experiment with physics parameters to find what works best.
Handle exceptions:
try: mouse.dest_position = (Coordinate(800), Coordinate(600)) mouse.move_to_target() except ValueError as e: print(f"Invalid coordinates: {e}") except Exception as e: print(f"Unexpected error: {e}")
Consider adding random variations:
import random # Add slight randomness to destination base_x, base_y = 800, 600 offset = 5 dest_x = Coordinate(base_x + random.randint(-offset, offset)) dest_y = Coordinate(base_y + random.randint(-offset, offset)) mouse.dest_position = (dest_x, dest_y) mouse.move_to_target()
Common Patterns
Web Scraping
from windmouse.pyautogui_controller import PyautoguiMouseController
from windmouse import Coordinate
import time
import random
def click_element(x: int, y: int):
"""Click an element with natural mouse movement."""
mouse = PyautoguiMouseController(
gravity_magnitude=9,
wind_magnitude=3,
max_step=12
)
# Add slight randomness
offset = 3
dest_x = Coordinate(x + random.randint(-offset, offset))
dest_y = Coordinate(y + random.randint(-offset, offset))
mouse.dest_position = (dest_x, dest_y)
mouse.move_to_target(tick_delay=0.003)
# Small pause before clicking
time.sleep(random.uniform(0.1, 0.3))
# Perform click
import pyautogui
pyautogui.click()
Game Automation
from windmouse.pyautogui_controller import PyautoguiMouseController
from windmouse import Coordinate
import time
class GameBot:
def __init__(self):
self.mouse = PyautoguiMouseController(
gravity_magnitude=12, # Faster response
wind_magnitude=2, # Less curvature
max_step=20 # Higher speed
)
def target_enemy(self, x: int, y: int):
"""Target and click enemy."""
self.mouse.dest_position = (Coordinate(x), Coordinate(y))
self.mouse.move_to_target(
tick_delay=0,
step_duration=0.05
)
time.sleep(0.05)
# Perform attack
def patrol(self, points: list[tuple[int, int]]):
"""Move through patrol points."""
for x, y in points:
self.mouse.dest_position = (Coordinate(x), Coordinate(y))
self.mouse.move_to_target(tick_delay=0.002)
time.sleep(1.0) # Wait at each point
Next Steps
Learn more about the algorithm internals in Algorithm Explained
Explore the complete API reference in API Reference
Check out advanced examples in the GitHub repository