|
1 | 1 | import type { ElementHandle, Page, BoundingBox, CDPSession, Protocol } from 'puppeteer'
|
2 | 2 | import debug from 'debug'
|
| 3 | +import { type PathOptions, path } from './core' |
3 | 4 | import {
|
4 | 5 | type Vector,
|
5 |
| - type TimedVector, |
6 |
| - bezierCurve, |
7 |
| - bezierCurveSpeed, |
8 | 6 | direction,
|
9 | 7 | magnitude,
|
10 | 8 | origin,
|
11 | 9 | overshoot,
|
12 | 10 | add,
|
13 | 11 | clamp,
|
14 |
| - scale, |
15 |
| - extrapolate |
| 12 | + scale |
16 | 13 | } from './math'
|
17 | 14 | import { installMouseHelper } from './mouse-helper'
|
18 | 15 |
|
19 | 16 | // TODO: remove in next major version, is now wrapped in the GhostCursor class.
|
20 |
| -export { installMouseHelper } |
| 17 | +export { type PathOptions, path, installMouseHelper } |
21 | 18 |
|
22 | 19 | const log = debug('ghost-cursor')
|
23 | 20 |
|
@@ -128,23 +125,6 @@ export interface ClickOptions extends MoveOptions {
|
128 | 125 | readonly clickCount?: number
|
129 | 126 | }
|
130 | 127 |
|
131 |
| -export interface PathOptions { |
132 |
| - /** |
133 |
| - * Override the spread of the generated path. |
134 |
| - */ |
135 |
| - readonly spreadOverride?: number |
136 |
| - /** |
137 |
| - * Speed of mouse movement. |
138 |
| - * Default is random. |
139 |
| - */ |
140 |
| - readonly moveSpeed?: number |
141 |
| - |
142 |
| - /** |
143 |
| - * Generate timestamps for each point in the path. |
144 |
| - */ |
145 |
| - readonly useTimestamps?: boolean |
146 |
| -} |
147 |
| - |
148 | 128 | export interface RandomMoveOptions extends Pick<MoveOptions, 'moveDelay' | 'randomizeMoveDelay' | 'moveSpeed'> {
|
149 | 129 | /**
|
150 | 130 | * @default 2000
|
@@ -205,18 +185,6 @@ const delay = async (ms: number): Promise<void> => {
|
205 | 185 | return await new Promise((resolve) => setTimeout(resolve, ms))
|
206 | 186 | }
|
207 | 187 |
|
208 |
| -/** |
209 |
| - * Calculate the amount of time needed to move from (x1, y1) to (x2, y2) |
210 |
| - * given the width of the element being clicked on |
211 |
| - * https://en.wikipedia.org/wiki/Fitts%27s_law |
212 |
| - */ |
213 |
| -const fitts = (distance: number, width: number): number => { |
214 |
| - const a = 0 |
215 |
| - const b = 2 |
216 |
| - const id = Math.log2(distance / width + 1) |
217 |
| - return a + b * id |
218 |
| -} |
219 |
| - |
220 | 188 | /** Get a random point on a box */
|
221 | 189 | const getRandomBoxPoint = (
|
222 | 190 | { x, y, width, height }: BoundingBox,
|
@@ -310,81 +278,6 @@ export const getElementBox = async (
|
310 | 278 | }
|
311 | 279 | }
|
312 | 280 |
|
313 |
| -/** Generates a set of points for mouse movement between two coordinates. */ |
314 |
| -export function path ( |
315 |
| - start: Vector, |
316 |
| - end: Vector | BoundingBox, |
317 |
| - /** |
318 |
| - * Additional options for generating the path. |
319 |
| - * Can also be a number which will set `spreadOverride`. |
320 |
| - */ |
321 |
| - // TODO: remove number arg in next major version change, fine to just allow `spreadOverride` in object. |
322 |
| - options?: number | PathOptions): Vector[] | TimedVector[] { |
323 |
| - const optionsResolved: PathOptions = typeof options === 'number' |
324 |
| - ? { spreadOverride: options } |
325 |
| - : { ...options } |
326 |
| - |
327 |
| - const DEFAULT_WIDTH = 100 |
328 |
| - const MIN_STEPS = 25 |
329 |
| - const width = 'width' in end && end.width !== 0 ? end.width : DEFAULT_WIDTH |
330 |
| - const curve = bezierCurve(start, end, optionsResolved.spreadOverride) |
331 |
| - const length = curve.length() * 0.8 |
332 |
| - |
333 |
| - const speed = optionsResolved.moveSpeed !== undefined && optionsResolved.moveSpeed > 0 |
334 |
| - ? (25 / optionsResolved.moveSpeed) |
335 |
| - : Math.random() |
336 |
| - const baseTime = speed * MIN_STEPS |
337 |
| - const steps = Math.ceil((Math.log2(fitts(length, width) + 1) + baseTime) * 3) |
338 |
| - const re = curve.getLUT(steps) |
339 |
| - return clampPositive(re, optionsResolved) |
340 |
| -} |
341 |
| - |
342 |
| -const clampPositive = (vectors: Vector[], options?: PathOptions): Vector[] | TimedVector[] => { |
343 |
| - const clampedVectors = vectors.map((vector) => ({ |
344 |
| - x: Math.max(0, vector.x), |
345 |
| - y: Math.max(0, vector.y) |
346 |
| - })) |
347 |
| - |
348 |
| - return options?.useTimestamps === true ? generateTimestamps(clampedVectors, options) : clampedVectors |
349 |
| -} |
350 |
| - |
351 |
| -const generateTimestamps = (vectors: Vector[], options?: PathOptions): TimedVector[] => { |
352 |
| - const speed = options?.moveSpeed ?? (Math.random() * 0.5 + 0.5) |
353 |
| - const timeToMove = (P0: Vector, P1: Vector, P2: Vector, P3: Vector, samples: number): number => { |
354 |
| - let total = 0 |
355 |
| - const dt = 1 / samples |
356 |
| - |
357 |
| - for (let t = 0; t < 1; t += dt) { |
358 |
| - const v1 = bezierCurveSpeed(t * dt, P0, P1, P2, P3) |
359 |
| - const v2 = bezierCurveSpeed(t, P0, P1, P2, P3) |
360 |
| - total += (v1 + v2) * dt / 2 |
361 |
| - } |
362 |
| - |
363 |
| - return Math.round(total / speed) |
364 |
| - } |
365 |
| - |
366 |
| - const timedVectors: TimedVector[] = [] |
367 |
| - |
368 |
| - for (let i = 0; i < vectors.length; i++) { |
369 |
| - if (i === 0) { |
370 |
| - timedVectors.push({ ...vectors[i], timestamp: Date.now() }) |
371 |
| - } else { |
372 |
| - const P0 = vectors[i - 1] |
373 |
| - const P1 = vectors[i] |
374 |
| - const P2 = i + 1 < vectors.length ? vectors[i + 1] : extrapolate(P0, P1) |
375 |
| - const P3 = i + 2 < vectors.length ? vectors[i + 2] : extrapolate(P1, P2) |
376 |
| - const time = timeToMove(P0, P1, P2, P3, vectors.length) |
377 |
| - |
378 |
| - timedVectors.push({ |
379 |
| - ...vectors[i], |
380 |
| - timestamp: timedVectors[i - 1].timestamp + time |
381 |
| - }) |
382 |
| - } |
383 |
| - } |
384 |
| - |
385 |
| - return timedVectors |
386 |
| -} |
387 |
| - |
388 | 281 | const shouldOvershoot = (a: Vector, b: Vector, threshold: number): boolean =>
|
389 | 282 | magnitude(direction(a, b)) > threshold
|
390 | 283 |
|
|
0 commit comments