Skip to content

Instantly share code, notes, and snippets.

@panayotoff
Created February 27, 2025 19:38
Show Gist options
  • Save panayotoff/c8c3ff088a7c02c9e2e70715fc11889b to your computer and use it in GitHub Desktop.
Save panayotoff/c8c3ff088a7c02c9e2e70715fc11889b to your computer and use it in GitHub Desktop.
Simple mouse juggler for ESP32S3 XIAO
#include "USB.h"
#include "USBHIDMouse.h"
#include "USBHID.h"
USBHIDMouse Mouse;
// Configuration
const unsigned long MIN_INTERVAL = 30000; // 30 seconds in milliseconds
const unsigned long MAX_INTERVAL = 60000; // 60 seconds in milliseconds
const int LED_PIN = LED_BUILTIN; // Built-in LED pin
const int FLASH_DURATION = 200; // LED flash duration in milliseconds
// Mouse movement patterns
const int NUM_MOVEMENTS_PER_CYCLE = 15; // Number of small movements to make per cycle
const int MOVEMENT_DELAY = 20; // Delay between small movements (ms)
const int MAX_MOVE_DISTANCE = 5; // Maximum pixels to move in a single micro-movement
// Variables
unsigned long lastMoveTime = 0;
unsigned long nextMoveInterval = 0;
int currentX = 0;
int currentY = 0;
int targetX = 0;
int targetY = 0;
void setup() {
// Initialize serial for debugging
Serial.begin(115200);
// Set the LED pin as output
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW); // Ensure LED is off initially
// Set USB device name
USB.manufacturerName("Logitech");
USB.productName("MX Anywhere 3S");
// Initialize the USB stack
USB.begin();
// Initialize Mouse HID
Mouse.begin();
// Small delay to ensure USB is ready
delay(1000);
// Set the initial random interval
nextMoveInterval = random(MIN_INTERVAL, MAX_INTERVAL + 1);
// Initialize random seed using analog noise
randomSeed(analogRead(0));
// Serial.println("Natural mouse movement simulator started.");
// Serial.print("Next movement in ");
// Serial.print(nextMoveInterval / 1000);
// Serial.println(" seconds");
}
void flashLED(int times) {
for (int i = 0; i < times; i++) {
digitalWrite(LED_PIN, HIGH);
delay(FLASH_DURATION);
digitalWrite(LED_PIN, LOW);
// Add a small gap between flashes if not the last flash
if (i < times - 1) {
delay(FLASH_DURATION);
}
}
}
// Creates a natural-looking mouse movement pattern
void moveMouseNaturally() {
// Decide on a movement style (0-3)
int movementStyle = random(0, 4);
// Serial.print("Performing natural mouse movement (style ");
// Serial.print(movementStyle);
// Serial.println(")");
switch (movementStyle) {
case 0: // Gentle circle
for (int i = 0; i < 20; i++) {
float angle = i * (2 * PI / 20);
int dx = round(10 * cos(angle));
int dy = round(10 * sin(angle));
Mouse.move(dx - currentX, dy - currentY);
currentX = dx;
currentY = dy;
delay(MOVEMENT_DELAY);
}
// Return to origin
Mouse.move(-currentX, -currentY);
currentX = 0;
currentY = 0;
break;
case 1: // Random small movements
for (int i = 0; i < NUM_MOVEMENTS_PER_CYCLE; i++) {
int dx = random(-MAX_MOVE_DISTANCE, MAX_MOVE_DISTANCE + 1);
int dy = random(-MAX_MOVE_DISTANCE, MAX_MOVE_DISTANCE + 1);
Mouse.move(dx, dy);
currentX += dx;
currentY += dy;
delay(MOVEMENT_DELAY);
}
// Return close to starting position to avoid drifting off-screen
Mouse.move(-currentX, -currentY);
currentX = 0;
currentY = 0;
break;
case 2: // Straight line with slight jitter
targetX = random(15, 30) * (random(0, 2) ? 1 : -1);
targetY = random(15, 30) * (random(0, 2) ? 1 : -1);
for (int i = 0; i < 10; i++) {
int dx = targetX / 10 + random(-1, 2);
int dy = targetY / 10 + random(-1, 2);
Mouse.move(dx, dy);
currentX += dx;
currentY += dy;
delay(MOVEMENT_DELAY * 2);
}
// Return to origin
Mouse.move(-currentX, -currentY);
currentX = 0;
currentY = 0;
break;
case 3: // Mouse acceleration simulation
targetX = random(20, 40) * (random(0, 2) ? 1 : -1);
targetY = random(20, 40) * (random(0, 2) ? 1 : -1);
// Gradually accelerate
for (int i = 1; i <= 5; i++) {
int dx = (targetX / 15) * i / 5;
int dy = (targetY / 15) * i / 5;
Mouse.move(dx, dy);
currentX += dx;
currentY += dy;
delay(MOVEMENT_DELAY * 2);
}
// Move at max speed
for (int i = 0; i < 5; i++) {
int dx = targetX / 15;
int dy = targetY / 15;
Mouse.move(dx, dy);
currentX += dx;
currentY += dy;
delay(MOVEMENT_DELAY);
}
// Gradually decelerate
for (int i = 5; i >= 1; i--) {
int dx = (targetX / 15) * i / 5;
int dy = (targetY / 15) * i / 5;
Mouse.move(dx, dy);
currentX += dx;
currentY += dy;
delay(MOVEMENT_DELAY * 2);
}
// Return to origin
Mouse.move(-currentX, -currentY);
currentX = 0;
currentY = 0;
break;
}
}
void loop() {
// Check if it's time to move the mouse
unsigned long currentTime = millis();
if (currentTime - lastMoveTime >= nextMoveInterval) {
// Flash LED twice
flashLED(2);
// Perform natural mouse movement
moveMouseNaturally();
// Update the last move time
lastMoveTime = currentTime;
// Generate next random interval between 30 and 60 seconds
nextMoveInterval = random(MIN_INTERVAL, MAX_INTERVAL + 1);
// Serial.print("Next movement in ");
// Serial.print(nextMoveInterval / 1000);
// Serial.println(" seconds");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment