-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 9610f04
Showing
4 changed files
with
196 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# GoMouse | ||
|
||
Library to generate human-like mouse mouvement. | ||
|
||
# Usage | ||
|
||
```go | ||
func TestGeneratePoints(t *testing.T) { | ||
settings := MouseSettings{ | ||
StartX: math.Ceil(RandomNumberFloat() * 1920), | ||
StartY: math.Ceil(RandomNumberFloat() * 1080), | ||
EndX: math.Ceil(RandomNumberFloat() * 1920), | ||
EndY: math.Ceil(RandomNumberFloat() * 1080), | ||
Gravity: math.Ceil(RandomNumberFloat() * 10), | ||
Wind: math.Ceil(RandomNumberFloat() * 10), | ||
MinWait: 2.0, | ||
MaxWait: math.Ceil(RandomNumberFloat() * 5), | ||
MaxStep: math.Ceil(RandomNumberFloat() * 3), | ||
TargetArea: math.Ceil(RandomNumberFloat() * 10), | ||
} | ||
|
||
points := GeneratePoints(settings) | ||
|
||
log.Print(points) | ||
} | ||
``` | ||
|
||
# Credits | ||
|
||
Thanks to [@BenLand100](https://github.com/BenLand100) for the [original WindMouse library in Java](https://github.com/BenLand100/SMART/blob/157e50691b4b63a0950fac06deccac26aae31f88/src/EventNazi.java#L201). All I did is porting it to Go. | ||
|
||
# Visualizer | ||
|
||
You can use [Mouse Data Visualizer](https://github.com/arevi/mouse-data-visualizer) made by [@arevi](https://github.com/arevi) to tune your mouse settings. |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module github.com/obito/gomouse | ||
|
||
go 1.15 |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package gomouse | ||
|
||
import ( | ||
cryptorand "crypto/rand" | ||
"encoding/binary" | ||
"math" | ||
"math/rand" | ||
) | ||
|
||
// MouseSettings initiate the mouse settings | ||
type MouseSettings struct { | ||
StartX float64 | ||
StartY float64 | ||
EndX float64 | ||
EndY float64 | ||
Gravity float64 | ||
Wind float64 | ||
MinWait float64 | ||
MaxWait float64 | ||
MaxStep float64 | ||
TargetArea float64 | ||
} | ||
|
||
func RandomNumberFloat() float64 { | ||
// avoid pitfalls of clock based seed value | ||
var b [8]byte | ||
_, err := cryptorand.Read(b[:]) | ||
if err != nil { | ||
panic("cannot seed math/rand package with cryptographically secure random number generator") | ||
} | ||
|
||
r := rand.New(rand.NewSource(int64(binary.LittleEndian.Uint64(b[:])))) | ||
return r.Float64() | ||
} | ||
|
||
func hypot(dx, dy float64) float64 { | ||
return math.Sqrt(dx*dx + dy*dy) | ||
} | ||
|
||
func GeneratePoints(settings MouseSettings) [][]float64 { | ||
if settings.Gravity < 1 { | ||
settings.Gravity = 1 | ||
} | ||
|
||
if settings.MaxStep == 0 { | ||
settings.MaxStep = 0.01 | ||
} | ||
|
||
windX := math.Floor(RandomNumberFloat() * 10) | ||
windY := math.Floor(RandomNumberFloat() * 10) | ||
|
||
var oldX float64 | ||
var oldY float64 | ||
newX := math.Floor(settings.StartX) | ||
newY := math.Floor(settings.StartY) | ||
|
||
waitDiff := settings.MaxWait - settings.MinWait | ||
|
||
// Hardcore instead of doing math.sqrt, maybe saving us some computiong time | ||
sqrt2 := 1.4142135623730951 | ||
sqrt3 := 1.7320508075688772 | ||
sqrt5 := 2.23606797749979 | ||
|
||
var randomDist float64 | ||
var velocityX float64 = 0 | ||
var velocityY float64 = 0 | ||
var dist float64 | ||
var veloMag float64 | ||
var step float64 | ||
|
||
var points [][]float64 | ||
var currentWait float64 = 0 | ||
|
||
dist = hypot(settings.EndX-settings.StartX, settings.EndY-settings.StartY) | ||
|
||
for dist > 1.0 { | ||
settings.Wind = math.Min(settings.Wind, dist) | ||
|
||
if dist >= settings.TargetArea { | ||
w := math.Floor(RandomNumberFloat()*math.Round(settings.Wind)*2 + 1) | ||
|
||
windX = windX/sqrt3 + (w-settings.Wind)/sqrt5 | ||
windY = windY/sqrt3 + (w-settings.Wind)/sqrt5 | ||
} else { | ||
windX = windX / sqrt2 | ||
windY = windY / sqrt2 | ||
|
||
if settings.MaxStep < 3 { | ||
settings.MaxStep = math.Floor(RandomNumberFloat()*3) + 3.0 | ||
} else { | ||
settings.MaxStep = settings.MaxStep / sqrt5 | ||
} | ||
} | ||
|
||
velocityX += windX | ||
velocityY += windY | ||
velocityX = velocityX + (settings.Gravity*(settings.EndX-settings.StartX))/dist | ||
velocityY = velocityY + (settings.Gravity*(settings.EndY-settings.StartY))/dist | ||
|
||
if hypot(velocityX, velocityY) > settings.MaxStep { | ||
randomDist = settings.MaxStep/2.0 + math.Floor((RandomNumberFloat()*math.Round(settings.MaxStep))/2) | ||
veloMag = hypot(velocityX, velocityY) | ||
velocityX = (velocityX / veloMag) * randomDist | ||
velocityY = (velocityY / veloMag) * randomDist | ||
} | ||
|
||
oldX = math.Round(settings.StartX) | ||
oldY = math.Round(settings.StartY) | ||
|
||
settings.StartX += velocityX | ||
settings.StartY += velocityY | ||
|
||
dist = hypot(settings.EndX-settings.StartX, settings.EndY-settings.StartY) | ||
|
||
newX = math.Round(settings.StartX) | ||
newY = math.Round(settings.StartY) | ||
|
||
step = hypot(settings.StartX-oldX, settings.StartY-oldY) | ||
wait := math.Round(waitDiff*(step/settings.MaxStep) + settings.MinWait) | ||
|
||
currentWait += wait | ||
|
||
if oldX != newY || oldY != newY { | ||
points = append(points, []float64{ | ||
newX, | ||
newY, | ||
currentWait, | ||
}) | ||
} | ||
} | ||
|
||
return points | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package gomouse | ||
|
||
import ( | ||
"log" | ||
"math" | ||
"testing" | ||
) | ||
|
||
func TestGeneratePoints(t *testing.T) { | ||
settings := MouseSettings{ | ||
StartX: math.Ceil(RandomNumberFloat() * 1920), | ||
StartY: math.Ceil(RandomNumberFloat() * 1080), | ||
EndX: math.Ceil(RandomNumberFloat() * 1920), | ||
EndY: math.Ceil(RandomNumberFloat() * 1080), | ||
Gravity: math.Ceil(RandomNumberFloat() * 10), | ||
Wind: math.Ceil(RandomNumberFloat() * 10), | ||
MinWait: 2.0, | ||
MaxWait: math.Ceil(RandomNumberFloat() * 5), | ||
MaxStep: math.Ceil(RandomNumberFloat() * 3), | ||
TargetArea: math.Ceil(RandomNumberFloat() * 10), | ||
} | ||
|
||
points := GeneratePoints(settings) | ||
|
||
log.Print(points) | ||
} |