Skip to content

Commit 9610f04

Browse files
committed
init
0 parents  commit 9610f04

4 files changed

Lines changed: 196 additions & 0 deletions

File tree

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# GoMouse
2+
3+
Library to generate human-like mouse mouvement.
4+
5+
# Usage
6+
7+
```go
8+
func TestGeneratePoints(t *testing.T) {
9+
settings := MouseSettings{
10+
StartX: math.Ceil(RandomNumberFloat() * 1920),
11+
StartY: math.Ceil(RandomNumberFloat() * 1080),
12+
EndX: math.Ceil(RandomNumberFloat() * 1920),
13+
EndY: math.Ceil(RandomNumberFloat() * 1080),
14+
Gravity: math.Ceil(RandomNumberFloat() * 10),
15+
Wind: math.Ceil(RandomNumberFloat() * 10),
16+
MinWait: 2.0,
17+
MaxWait: math.Ceil(RandomNumberFloat() * 5),
18+
MaxStep: math.Ceil(RandomNumberFloat() * 3),
19+
TargetArea: math.Ceil(RandomNumberFloat() * 10),
20+
}
21+
22+
points := GeneratePoints(settings)
23+
24+
log.Print(points)
25+
}
26+
```
27+
28+
# Credits
29+
30+
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.
31+
32+
# Visualizer
33+
34+
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.

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/obito/gomouse
2+
3+
go 1.15

gomouse.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package gomouse
2+
3+
import (
4+
cryptorand "crypto/rand"
5+
"encoding/binary"
6+
"math"
7+
"math/rand"
8+
)
9+
10+
// MouseSettings initiate the mouse settings
11+
type MouseSettings struct {
12+
StartX float64
13+
StartY float64
14+
EndX float64
15+
EndY float64
16+
Gravity float64
17+
Wind float64
18+
MinWait float64
19+
MaxWait float64
20+
MaxStep float64
21+
TargetArea float64
22+
}
23+
24+
func RandomNumberFloat() float64 {
25+
// avoid pitfalls of clock based seed value
26+
var b [8]byte
27+
_, err := cryptorand.Read(b[:])
28+
if err != nil {
29+
panic("cannot seed math/rand package with cryptographically secure random number generator")
30+
}
31+
32+
r := rand.New(rand.NewSource(int64(binary.LittleEndian.Uint64(b[:]))))
33+
return r.Float64()
34+
}
35+
36+
func hypot(dx, dy float64) float64 {
37+
return math.Sqrt(dx*dx + dy*dy)
38+
}
39+
40+
func GeneratePoints(settings MouseSettings) [][]float64 {
41+
if settings.Gravity < 1 {
42+
settings.Gravity = 1
43+
}
44+
45+
if settings.MaxStep == 0 {
46+
settings.MaxStep = 0.01
47+
}
48+
49+
windX := math.Floor(RandomNumberFloat() * 10)
50+
windY := math.Floor(RandomNumberFloat() * 10)
51+
52+
var oldX float64
53+
var oldY float64
54+
newX := math.Floor(settings.StartX)
55+
newY := math.Floor(settings.StartY)
56+
57+
waitDiff := settings.MaxWait - settings.MinWait
58+
59+
// Hardcore instead of doing math.sqrt, maybe saving us some computiong time
60+
sqrt2 := 1.4142135623730951
61+
sqrt3 := 1.7320508075688772
62+
sqrt5 := 2.23606797749979
63+
64+
var randomDist float64
65+
var velocityX float64 = 0
66+
var velocityY float64 = 0
67+
var dist float64
68+
var veloMag float64
69+
var step float64
70+
71+
var points [][]float64
72+
var currentWait float64 = 0
73+
74+
dist = hypot(settings.EndX-settings.StartX, settings.EndY-settings.StartY)
75+
76+
for dist > 1.0 {
77+
settings.Wind = math.Min(settings.Wind, dist)
78+
79+
if dist >= settings.TargetArea {
80+
w := math.Floor(RandomNumberFloat()*math.Round(settings.Wind)*2 + 1)
81+
82+
windX = windX/sqrt3 + (w-settings.Wind)/sqrt5
83+
windY = windY/sqrt3 + (w-settings.Wind)/sqrt5
84+
} else {
85+
windX = windX / sqrt2
86+
windY = windY / sqrt2
87+
88+
if settings.MaxStep < 3 {
89+
settings.MaxStep = math.Floor(RandomNumberFloat()*3) + 3.0
90+
} else {
91+
settings.MaxStep = settings.MaxStep / sqrt5
92+
}
93+
}
94+
95+
velocityX += windX
96+
velocityY += windY
97+
velocityX = velocityX + (settings.Gravity*(settings.EndX-settings.StartX))/dist
98+
velocityY = velocityY + (settings.Gravity*(settings.EndY-settings.StartY))/dist
99+
100+
if hypot(velocityX, velocityY) > settings.MaxStep {
101+
randomDist = settings.MaxStep/2.0 + math.Floor((RandomNumberFloat()*math.Round(settings.MaxStep))/2)
102+
veloMag = hypot(velocityX, velocityY)
103+
velocityX = (velocityX / veloMag) * randomDist
104+
velocityY = (velocityY / veloMag) * randomDist
105+
}
106+
107+
oldX = math.Round(settings.StartX)
108+
oldY = math.Round(settings.StartY)
109+
110+
settings.StartX += velocityX
111+
settings.StartY += velocityY
112+
113+
dist = hypot(settings.EndX-settings.StartX, settings.EndY-settings.StartY)
114+
115+
newX = math.Round(settings.StartX)
116+
newY = math.Round(settings.StartY)
117+
118+
step = hypot(settings.StartX-oldX, settings.StartY-oldY)
119+
wait := math.Round(waitDiff*(step/settings.MaxStep) + settings.MinWait)
120+
121+
currentWait += wait
122+
123+
if oldX != newY || oldY != newY {
124+
points = append(points, []float64{
125+
newX,
126+
newY,
127+
currentWait,
128+
})
129+
}
130+
}
131+
132+
return points
133+
}

gomouse_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package gomouse
2+
3+
import (
4+
"log"
5+
"math"
6+
"testing"
7+
)
8+
9+
func TestGeneratePoints(t *testing.T) {
10+
settings := MouseSettings{
11+
StartX: math.Ceil(RandomNumberFloat() * 1920),
12+
StartY: math.Ceil(RandomNumberFloat() * 1080),
13+
EndX: math.Ceil(RandomNumberFloat() * 1920),
14+
EndY: math.Ceil(RandomNumberFloat() * 1080),
15+
Gravity: math.Ceil(RandomNumberFloat() * 10),
16+
Wind: math.Ceil(RandomNumberFloat() * 10),
17+
MinWait: 2.0,
18+
MaxWait: math.Ceil(RandomNumberFloat() * 5),
19+
MaxStep: math.Ceil(RandomNumberFloat() * 3),
20+
TargetArea: math.Ceil(RandomNumberFloat() * 10),
21+
}
22+
23+
points := GeneratePoints(settings)
24+
25+
log.Print(points)
26+
}

0 commit comments

Comments
 (0)