121 lines
4.1 KiB
TypeScript
Executable file
121 lines
4.1 KiB
TypeScript
Executable file
/**
|
||
* Mouse movement simulation for browser scripts
|
||
* Generates JavaScript code strings for realistic mouse movement
|
||
*/
|
||
|
||
export interface MouseConfig {
|
||
mouseMoveSteps: number;
|
||
mouseMoveDelay: number;
|
||
}
|
||
|
||
export function generateMouseHelpers(config: MouseConfig): string {
|
||
return `
|
||
// ============== MOUSE MOVEMENT ==============
|
||
let currentMousePos = { x: window.innerWidth / 2, y: window.innerHeight / 2 };
|
||
|
||
function easeOutCubic(t) {
|
||
return 1 - Math.pow(1 - t, 3);
|
||
}
|
||
|
||
function addJitter(value, maxJitter) {
|
||
return value + (Math.random() - 0.5) * maxJitter;
|
||
}
|
||
|
||
function dispatchMouseMove(x, y) {
|
||
const moveEvent = new MouseEvent('mousemove', {
|
||
bubbles: true, cancelable: true, view: window,
|
||
clientX: x, clientY: y, screenX: x, screenY: y,
|
||
});
|
||
// Try element at point, fallback to document
|
||
const target = document.elementFromPoint(x, y) || document.body;
|
||
target.dispatchEvent(moveEvent);
|
||
// Also dispatch on document for global listeners
|
||
document.dispatchEvent(moveEvent);
|
||
}
|
||
|
||
async function moveMouseTo(targetX, targetY, targetEl = null) {
|
||
const startX = currentMousePos.x;
|
||
const startY = currentMousePos.y;
|
||
const steps = ${config.mouseMoveSteps} + Math.floor(Math.random() * 10);
|
||
const overshootX = targetX + (Math.random() - 0.5) * 10;
|
||
const overshootY = targetY + (Math.random() - 0.5) * 10;
|
||
|
||
console.log('%c🖱️ Moving mouse...', 'color: gray; font-size: 10px');
|
||
|
||
for (let i = 0; i <= steps; i++) {
|
||
const progress = i / steps;
|
||
const easedProgress = easeOutCubic(progress);
|
||
const curveOffset = Math.sin(progress * Math.PI) * (20 + Math.random() * 30);
|
||
const x = addJitter(startX + (overshootX - startX) * easedProgress, 2);
|
||
const y = addJitter(startY + (overshootY - startY) * easedProgress + curveOffset * (1 - progress), 2);
|
||
|
||
currentMousePos = { x, y };
|
||
dispatchMouseMove(x, y);
|
||
await sleep(randomize(${config.mouseMoveDelay}));
|
||
}
|
||
|
||
// Final position on target
|
||
currentMousePos = { x: targetX, y: targetY };
|
||
if (targetEl) {
|
||
targetEl.dispatchEvent(new MouseEvent('mousemove', {
|
||
bubbles: true, cancelable: true, view: window,
|
||
clientX: targetX, clientY: targetY,
|
||
}));
|
||
}
|
||
}
|
||
|
||
async function simulateClick(el) {
|
||
const rect = el.getBoundingClientRect();
|
||
const targetX = rect.left + rect.width / 2 + (Math.random() - 0.5) * (rect.width * 0.3);
|
||
const targetY = rect.top + rect.height / 2 + (Math.random() - 0.5) * (rect.height * 0.3);
|
||
|
||
// Move mouse to element
|
||
await moveMouseTo(targetX, targetY, el);
|
||
await sleep(randomize(50));
|
||
|
||
const opts = {
|
||
bubbles: true, cancelable: true, view: window,
|
||
clientX: targetX, clientY: targetY, screenX: targetX, screenY: targetY,
|
||
button: 0, buttons: 1
|
||
};
|
||
|
||
// Hover sequence
|
||
el.dispatchEvent(new MouseEvent('mouseenter', opts));
|
||
el.dispatchEvent(new MouseEvent('mouseover', opts));
|
||
await sleep(randomize(30));
|
||
|
||
// Click sequence with proper timing
|
||
el.dispatchEvent(new MouseEvent('mousedown', opts));
|
||
await sleep(randomize(80));
|
||
el.dispatchEvent(new MouseEvent('mouseup', opts));
|
||
await sleep(randomize(10));
|
||
el.dispatchEvent(new MouseEvent('click', opts));
|
||
|
||
// Native click as backup
|
||
el.click();
|
||
|
||
console.log('%c🖱️ Clicked', 'color: gray; font-size: 10px');
|
||
}
|
||
|
||
// Random idle scrolling to simulate human behavior
|
||
async function idleScroll() {
|
||
if (Math.random() < 0.3) { // 30% chance
|
||
const amount = (Math.random() - 0.5) * 200; // -100 to +100 px
|
||
window.scrollBy({ top: amount, behavior: 'smooth' });
|
||
console.log('%c📜 Idle scroll', 'color: gray; font-size: 10px');
|
||
await sleep(randomize(300));
|
||
}
|
||
}
|
||
|
||
// Random mouse wiggle during waits
|
||
async function idleMouseWiggle() {
|
||
if (Math.random() < 0.4) { // 40% chance
|
||
const wiggleX = currentMousePos.x + (Math.random() - 0.5) * 50;
|
||
const wiggleY = currentMousePos.y + (Math.random() - 0.5) * 50;
|
||
dispatchMouseMove(wiggleX, wiggleY);
|
||
await sleep(randomize(100));
|
||
dispatchMouseMove(currentMousePos.x, currentMousePos.y);
|
||
}
|
||
}
|
||
// =============================================`;
|
||
}
|