119 lines
2.6 KiB
Go
119 lines
2.6 KiB
Go
package mousemover
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"github.com/go-vgo/robotgo"
|
|
"github.com/prashantgupta24/activity-tracker/pkg/tracker"
|
|
"github.com/prashantgupta24/automatic-mouse-mover/pkg/notify"
|
|
)
|
|
|
|
var instance *MouseMover
|
|
|
|
//MouseMover is the main struct for the app
|
|
type MouseMover struct {
|
|
quit chan struct{}
|
|
mutex sync.RWMutex
|
|
runningStatus bool
|
|
}
|
|
|
|
const (
|
|
timeout = 100 //ms
|
|
)
|
|
|
|
//Start the main app
|
|
func (m *MouseMover) Start() {
|
|
if m.isRunning() {
|
|
return
|
|
}
|
|
m.quit = make(chan struct{})
|
|
|
|
frequency := 60 //value always in seconds
|
|
activityTracker := &tracker.Instance{
|
|
Frequency: frequency,
|
|
//LogLevel: "debug", //if we want verbose logging
|
|
}
|
|
|
|
heartbeatCh := activityTracker.Start()
|
|
|
|
go func(m *MouseMover) {
|
|
m.updateRunningStatus(true)
|
|
movePixel := 10
|
|
for {
|
|
select {
|
|
case heartbeat := <-heartbeatCh:
|
|
if !heartbeat.WasAnyActivity {
|
|
mouseMoveSuccessCh := make(chan bool)
|
|
go moveAndCheck(movePixel, mouseMoveSuccessCh)
|
|
select {
|
|
case wasMouseMoveSuccess := <-mouseMoveSuccessCh:
|
|
if wasMouseMoveSuccess {
|
|
log.Infof("moved mouse at : %v\n\n", time.Now())
|
|
movePixel *= -1
|
|
} else {
|
|
msg := "Mouse pointer cannot be moved. See README for details."
|
|
log.Errorf(msg)
|
|
notify.SendMessage(msg)
|
|
}
|
|
case <-time.After(timeout * time.Millisecond):
|
|
//timeout, do nothing
|
|
log.Errorf("timeout happened after %vms while trying to move mouse", timeout)
|
|
}
|
|
|
|
}
|
|
case <-m.quit:
|
|
log.Infof("stopping mouse mover")
|
|
m.updateRunningStatus(false)
|
|
activityTracker.Quit()
|
|
return
|
|
}
|
|
}
|
|
}(m)
|
|
}
|
|
|
|
func (m *MouseMover) isRunning() bool {
|
|
m.mutex.RLock()
|
|
defer m.mutex.RUnlock()
|
|
return m.runningStatus
|
|
}
|
|
func (m *MouseMover) updateRunningStatus(isRunning bool) {
|
|
m.mutex.Lock()
|
|
defer m.mutex.Unlock()
|
|
m.runningStatus = isRunning
|
|
}
|
|
|
|
func moveAndCheck(movePixel int, mouseMoveSuccessCh chan bool) {
|
|
currentX, currentY := robotgo.GetMousePos()
|
|
moveToX := currentX + movePixel
|
|
moveToY := currentY + movePixel
|
|
robotgo.MoveMouse(moveToX, moveToY)
|
|
|
|
//check if mouse moved. Sometimes mac users need to give
|
|
//extra permission for controlling the mouse
|
|
movedX, movedY := robotgo.GetMousePos()
|
|
if movedX == currentX && movedY == currentY {
|
|
mouseMoveSuccessCh <- false
|
|
} else {
|
|
mouseMoveSuccessCh <- true
|
|
}
|
|
}
|
|
|
|
//Quit the app
|
|
func (m *MouseMover) Quit() {
|
|
//making it idempotent
|
|
if m != nil && m.isRunning() {
|
|
m.quit <- struct{}{}
|
|
}
|
|
}
|
|
|
|
//GetInstance gets the singleton instance for mouse mover app
|
|
func GetInstance() *MouseMover {
|
|
if instance == nil {
|
|
instance = &MouseMover{}
|
|
}
|
|
return instance
|
|
}
|