Last active
August 15, 2024 11:14
-
-
Save vorce/04e660526473beecdc3029cf7c5a761c to your computer and use it in GitHub Desktop.
Mouse move and click test thing for macos in swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Cocoa | |
import Foundation | |
// Move around and click automatically at random places in macos, kinda human like in a cheap way. | |
// Moves the mouse pointer to `moves` random locations on the screen and runs the `action` function at | |
// each point with the point as argument. | |
func mouseMoveWithAction(moves: Int, action: (CGPoint) -> Void = defaultAction) { | |
let screenSize = NSScreen.main?.visibleFrame.size | |
let currentLocation = NSEvent.mouseLocation | |
var currentPoint = CGPoint(x: currentLocation.x, y: currentLocation.y) | |
for _ in 0 ... (moves - 1) { | |
let randomXPos = CGFloat.random(in: 0..<screenSize!.width) | |
let randomYPos = CGFloat.random(in: 0..<screenSize!.height) | |
let destination = CGPoint(x: randomXPos, y: randomYPos) | |
let easing = Float.random(in: 270..<650) | |
humanizedMouseMove(from: currentPoint, to: destination, easing: easing) | |
let pause = pauseTime() | |
print("pause: ", pause) | |
usleep(useconds_t(pause)) | |
currentPoint = destination | |
action(currentPoint) | |
} | |
print("done with \(moves) moves") | |
} | |
func defaultAction(point: CGPoint) { | |
print("<no action at \(point)>") | |
} | |
// Pause for slightly longer 20% of the time | |
func pauseTime() -> Int { | |
let pauseType = Int.random(in: 0..<100) | |
if(pauseType >= 80) { | |
let longPause = Int.random(in: 100_000..<2_000_000) | |
return longPause | |
} else { | |
let shortPause = Int.random(in: 10_000..<500_000) | |
return shortPause | |
} | |
} | |
func moveMouseTo(point: CGPoint) { | |
CGEvent(mouseEventSource: nil, mouseType: CGEventType.mouseMoved, mouseCursorPosition: point, mouseButton: CGMouseButton.left)?.post(tap: CGEventTapLocation.cghidEventTap) | |
} | |
func mouseClick(point: CGPoint, mouseButton: CGMouseButton = CGMouseButton.left) { | |
CGEvent(mouseEventSource: nil, mouseType: CGEventType.leftMouseDown, mouseCursorPosition: point, mouseButton: mouseButton)?.post(tap: CGEventTapLocation.cghidEventTap) | |
usleep(useconds_t(Int.random(in: 400_010..<600_200))) | |
CGEvent(mouseEventSource: nil, mouseType: CGEventType.leftMouseUp, mouseCursorPosition: point, mouseButton: mouseButton)?.post(tap: CGEventTapLocation.cghidEventTap) | |
} | |
// Moves the mouse from point `from` to point `to`, with some `easing` factor. | |
// Easing means ramping up the movement smoothly in the beginning, and ramping it down towards the end. | |
// The cheap "humanized" factor. | |
func humanizedMouseMove(from: CGPoint, to: CGPoint, easing: Float = 100.0) { | |
print("current location: ", from) | |
print("moving to: ", to) | |
let distance = distanceBetween(from: from, to: to) | |
let steps = Int(distance * CGFloat(easing) / 100) + 1; | |
let xDiff = to.x - from.x | |
let yDiff = to.y - from.y | |
let stepSize = 1.0 / Double(steps) | |
for i in 0 ... steps { | |
let factor = cubicEaseOut(point: Float(stepSize) * Float(i)) | |
let stepPoint = CGPoint(x: from.x + (CGFloat(factor) * xDiff), y: from.y + (CGFloat(factor) * yDiff)) | |
moveMouseTo(point: stepPoint) | |
usleep(useconds_t(stepPause())) | |
} | |
} | |
func stepPause() -> Int { | |
return Int.random(in: 200..<300) | |
} | |
func distanceBetween(from: CGPoint, to: CGPoint) -> CGFloat { | |
let distanceX = from.x - to.x | |
let distanceY = from.y - to.y | |
return sqrt(distanceX * distanceX + distanceY * distanceY) | |
} | |
// stolen from cliclick | |
func cubicEaseOut(point: Float) -> Float { | |
if(point < 0.5) { | |
return 4 * point * point * point | |
} else { | |
let f = ((2 * point) - 2) | |
return 0.5 * f * f * f + 1 | |
} | |
} | |
mouseMoveWithAction(moves: 2) { mouseClick(point: $0) } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment