cardboard-sikuli/runscript.go

117 lines
2.7 KiB
Go

package main
import (
"bytes"
"errors"
"fmt"
"image/png"
"log"
"os"
"time"
"github.com/dop251/goja"
"github.com/go-vgo/robotgo"
qt "github.com/mappu/miqt/qt6"
"github.com/vcaesar/gcv"
)
const (
jsWait string = `SIKULI_WAIT`
jsTimeout string = `SIKULI_TIMEOUT`
jsThreshold string = `SIKULI_THRESHOLD`
DefaultWait = 200 * time.Millisecond
DefaultTimeout = 30 * time.Second
DefaultThreshold = float64(0.9)
)
func runScript() {
mw.MainWindow.Hide()
defer mw.MainWindow.Show()
startTime := time.Now()
time.Sleep(DefaultWait)
rt := goja.New()
rt.GlobalObject().Set("ClickAt", func(filepath string, x, y int) error {
// Load image
bb, err := os.ReadFile(filepath)
if err != nil {
return fmt.Errorf("Opening file %q: %v", filepath, err)
}
searchImg, err := png.Decode(bytes.NewReader(bb))
if err != nil {
return fmt.Errorf("Parsing PNG file %q: %v", filepath, err)
}
wait := time.Duration(rt.Get(jsWait).ToInteger()) * time.Millisecond
timeout := time.Duration(rt.Get(jsTimeout).ToInteger()) * time.Millisecond
threshold := rt.Get(jsThreshold).ToFloat()
if threshold > 1 || threshold < 0 {
return fmt.Errorf("SIKULI_THRESHOLD should be between 0 and 1, got %.2f", threshold)
}
// Loop and wait for target to appear
startTime := time.Now()
for {
// Take screen capture
bmp := robotgo.CaptureScreen(0)
fullScreenImg := robotgo.ToImage(bmp)
robotgo.FreeBitmap(bmp)
// Load into gocv
// FindImg() uses TM_CCOEFF_NORMED, which puts the best match in _max_ not _min_
_, maxV, _, maxP := gcv.FindImg(searchImg, fullScreenImg)
// Check if the maxV is within our wanted bounds
if float64(maxV) > threshold {
ok := robotgo.MoveMouseSmooth(maxP.X+x, maxP.Y+y)
if !ok {
return errors.New("MoveMouse failure")
}
robotgo.MouseClick()
// Success
return nil
}
// Didn't find a match
// If there's still time left, then keep waiting a bit longer
if time.Now().Sub(startTime) > timeout {
return fmt.Errorf("Image %q not found (timed out after %s)", filepath, timeout.Truncate(100*time.Millisecond).String())
}
time.Sleep(wait)
}
})
log.Print(mw.textEdit.ToPlainText()) // n.b. missing img tag
src := html_to_src(mw.textEdit.ToHtml()) // n.b. lots of extra junk
rt.Set(jsWait, DefaultWait.Milliseconds())
rt.Set(jsTimeout, DefaultTimeout.Milliseconds())
rt.Set(jsThreshold, DefaultThreshold)
_, err := rt.RunString(src)
simpleDuration := time.Now().Sub(startTime).Truncate(100 * time.Millisecond)
mw.statusbar.ShowMessage(fmt.Sprintf("Script execution completed in %s", simpleDuration.String()))
if err != nil {
mw.MainWindow.Show()
qt.QMessageBox_Critical(mw.MainWindow.QWidget, "Script error", err.Error())
}
}