Last active
January 27, 2020 16:07
-
-
Save naikrovek/9cb2b06509c656c39df03614036a5630 to your computer and use it in GitHub Desktop.
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
package main | |
import ( | |
"bytes" | |
"database/sql" | |
"fmt" | |
"image" | |
"image/color" | |
"image/draw" | |
"image/png" | |
"io/ioutil" | |
"log" | |
"os" | |
"os/signal" | |
"sync" | |
"syscall" | |
"time" | |
"github.com/go-vgo/robotgo" | |
_ "github.com/mattn/go-sqlite3" | |
) | |
var wg sync.WaitGroup | |
func main() { | |
quitFlag := false | |
// channels for communication between goroutines | |
locations := make(chan image.Point, 10) | |
db, _ := sql.Open("sqlite3", "./mouse.db") | |
defer db.Close() // `defer` is very handy. | |
// storing the date as text here, because sqlite3 doesn't have a datetime datatype. | |
statement, err := db.Prepare("CREATE TABLE IF NOT EXISTS mouse (time TEXT PRIMARY KEY, x INT, y INT)") | |
check(err) | |
_, err = statement.Exec() | |
check(err) | |
defer statement.Close() | |
// set your output image resolution here. it should match your monitor | |
// geometry: primary monitor's lower left-hand corner is 0,0 so if you have | |
// monitors below and/or to the left of your primary monitor, windows will | |
// return negative numbers for the mouse position in those areas. | |
w, h := robotgo.GetScreenSize() | |
i := image.NewNRGBA(image.Rect(0, 0, w, h)) | |
// set a white background color | |
draw.Draw(i, i.Bounds(), &image.Uniform{color.Black}, image.Point{0, 0}, draw.Src) | |
// 60 times a second, capture the mouse pointer location and shove it in the | |
// channel set aside for this. | |
wg.Add(1) | |
go func() { | |
for { | |
if quitFlag { | |
close(locations) | |
break | |
} | |
// wait until the next interval. | |
time.Sleep(time.Second / 60) | |
x, y := robotgo.GetMousePos() | |
point := image.Point{x, y} | |
locations <- point | |
} | |
wg.Done() | |
}() | |
// get the mouse location from the channel and draw it onto the image in | |
// memory. also - write the date and time and X & Y location to a database. | |
wg.Add(1) | |
go func() { | |
statement, err = db.Prepare("INSERT INTO mouse (time, x, y) VALUES (?, ?, ?)") | |
check(err) | |
for { | |
if quitFlag { | |
break | |
} | |
// wait until a location is ready to be saved to the database. | |
point := <-locations | |
// get the current alpha at the point | |
c := i.NRGBAAt(point.X, point.Y) | |
newAlpha := c.A | |
// make the point less transparent if there's already a dot here. | |
if newAlpha != 0 { | |
newAlpha/=2 | |
} | |
i.Set(point.X, point.Y, color.NRGBA{1, 1, 1, newAlpha}) | |
_, err = statement.Exec(time.Now().Format("2006-01-02 15:04:05.000"), point.X, point.Y) | |
check(err) | |
} | |
statement.Close() | |
wg.Done() | |
}() | |
// once a minute, save the current image. | |
wg.Add(1) | |
go func() { | |
for { | |
if quitFlag { | |
break | |
} | |
time.Sleep(time.Second) | |
// save at the top of the minute. | |
if time.Now().Unix()%60 == 0 { | |
var buf bytes.Buffer | |
err := png.Encode(&buf, i) | |
check(err) | |
err = ioutil.WriteFile("mouse-"+time.Now().Format("2006-01-02")+".png", buf.Bytes(), 0777) | |
check(err) | |
} | |
} | |
wg.Done() | |
}() | |
// handle CTRL+C gracefully | |
sigc := make(chan os.Signal, 1) | |
signal.Notify(sigc, syscall.SIGTERM, syscall.SIGINT) | |
go func() { | |
<-sigc | |
fmt.Println("stopping.") | |
quitFlag = true | |
}() | |
wg.Wait() | |
} | |
// f*ck it, easy mode | |
func check(e error) { | |
if e != nil { | |
log.Panic(e) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment