First commit
This commit is contained in:
21
README.md
Normal file
21
README.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Mr Robotic - A cross-platform desktop automation tool
|
||||||
|
|
||||||
|
Mr Robotic is a cross-platform desktop automation tool mainly used for auto-clicking and auto-typing.
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
Mr Robotic is built on Go, and have all required libraries built-in within the binary.
|
||||||
|
|
||||||
|
To attempt to recompile the application, the following is required:
|
||||||
|
|
||||||
|
* Go
|
||||||
|
* robotgo
|
||||||
|
* Dependencies for robotgo
|
||||||
|
|
||||||
|
Cross-compilation isn't the most stable thing, so OS specific compilation is recommended.
|
||||||
|
|
||||||
|
## Authors
|
||||||
|
|
||||||
|
* **Samuel Pua** - *Initial work* - [GitHub](https://github.com/telboon)
|
||||||
|
|
||||||
|
|
||||||
16
keys.txt
Normal file
16
keys.txt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
sleep 601
|
||||||
|
mouseLeftClick 671,570
|
||||||
|
sleep 400
|
||||||
|
mouseLeftClick 900,531
|
||||||
|
sleep 300
|
||||||
|
mouseLeftClick 884,333
|
||||||
|
sleep 300
|
||||||
|
mouseLeftClick 808,493
|
||||||
|
sleep 300
|
||||||
|
mouseLeftClick 800,495
|
||||||
|
sleep 1403
|
||||||
|
mouseLeftClick 885,125
|
||||||
|
sleep 200
|
||||||
|
mouseLeftClick 885,125
|
||||||
|
sleep 300
|
||||||
|
mouseLeftClick 885,125
|
||||||
439
main.go
Normal file
439
main.go
Normal file
@@ -0,0 +1,439 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"os"
|
||||||
|
"io/ioutil"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
"runtime"
|
||||||
|
"github.com/go-vgo/robotgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MOUSELEFTCLICK = "mouseLeftClick"
|
||||||
|
MOUSERIGHTCLICK = "mouseRightClick"
|
||||||
|
MOUSEMOVE = "mouseMove"
|
||||||
|
SLEEP = "sleep"
|
||||||
|
KEYBOARD = "keyboard"
|
||||||
|
TAPESCAPE = "tapEscape"
|
||||||
|
TAPTAB = "tapTab"
|
||||||
|
TAPUP = "tabUp"
|
||||||
|
TAPDOWN = "tapDown"
|
||||||
|
TAPLEFT = "tapLeft"
|
||||||
|
TAPRIGHT = "tabRight"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
KEYQ uint16
|
||||||
|
KEYW uint16
|
||||||
|
KEYE uint16
|
||||||
|
KEYA uint16
|
||||||
|
KEYS uint16
|
||||||
|
KEYD uint16
|
||||||
|
KEYR uint16
|
||||||
|
KEYZ uint16
|
||||||
|
KEYCTRL uint16
|
||||||
|
KEYESC uint16
|
||||||
|
KEYTAB uint16
|
||||||
|
KEYUP uint16
|
||||||
|
KEYDOWN uint16
|
||||||
|
KEYLEFT uint16
|
||||||
|
KEYRIGHT uint16
|
||||||
|
)
|
||||||
|
|
||||||
|
func mainMenu(keyCommands *[]string, runCount *int) string {
|
||||||
|
exitChan := make(chan bool, 1)
|
||||||
|
go listenRun(exitChan, keyCommands, runCount)
|
||||||
|
fmt.Println(`Main Menu
|
||||||
|
|
||||||
|
l: Listening mode
|
||||||
|
f: Read from file ("keys.txt")
|
||||||
|
s: Save to file ("keys.txt")
|
||||||
|
p: Print stored command
|
||||||
|
c: Change run count
|
||||||
|
r: Run stored command (Hotkey: ctrl-r)
|
||||||
|
`)
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
fmt.Print("Enter Command: ")
|
||||||
|
command, _ := reader.ReadString('\n')
|
||||||
|
command = strings.ReplaceAll(command, "\n", "")
|
||||||
|
command = strings.ReplaceAll(command, "\r", "")
|
||||||
|
exitChan <- true
|
||||||
|
return command
|
||||||
|
}
|
||||||
|
|
||||||
|
func listenRun(exitChan chan bool, keyCommands *[]string, runCount *int) {
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
evtChan := robotgo.Start()
|
||||||
|
defer robotgo.End()
|
||||||
|
|
||||||
|
// Rawcode
|
||||||
|
// 65507, 162 - ctrl
|
||||||
|
// 114, 82 - r
|
||||||
|
|
||||||
|
// Kind
|
||||||
|
// 3 - keydown
|
||||||
|
// 5 - keyup
|
||||||
|
|
||||||
|
ctrlKey := false
|
||||||
|
rKey := false
|
||||||
|
|
||||||
|
for evt := range evtChan {
|
||||||
|
// return if exit signal is given
|
||||||
|
select {
|
||||||
|
case <- exitChan:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
if (evt.Kind == 3 || evt.Kind == 4) && (evt.Rawcode == KEYCTRL) {
|
||||||
|
ctrlKey = true
|
||||||
|
} else if evt.Kind == 5 && (evt.Rawcode == KEYCTRL) {
|
||||||
|
ctrlKey = false
|
||||||
|
} else if evt.Kind == 3 && (evt.Rawcode == KEYR) {
|
||||||
|
rKey = true
|
||||||
|
} else if evt.Kind == 5 && (evt.Rawcode == KEYR) {
|
||||||
|
rKey = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctrlKey && rKey {
|
||||||
|
ctrlKey = false
|
||||||
|
rKey = false
|
||||||
|
runKeyCommands(*keyCommands, *runCount)
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func listenMode(keyCommands *[]string, runCount *int) {
|
||||||
|
*keyCommands = nil
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
fmt.Println("Entering listening mode...")
|
||||||
|
evtChan := robotgo.Start()
|
||||||
|
defer robotgo.End()
|
||||||
|
|
||||||
|
// Rawcode
|
||||||
|
// 113, 81 - q
|
||||||
|
// 119, 87 - w
|
||||||
|
// 101, 69 - e
|
||||||
|
// 97, 65 - a
|
||||||
|
// 115, 83 - s
|
||||||
|
// 100, 68 - d
|
||||||
|
// 65307, 27 - esc
|
||||||
|
|
||||||
|
// Kind
|
||||||
|
// 3 - keydown
|
||||||
|
// 5 - keyup
|
||||||
|
|
||||||
|
leftMouseTrigger := 0
|
||||||
|
rightMouseTrigger := 0
|
||||||
|
moveMouseTrigger := 0
|
||||||
|
sleepTrigger := 0
|
||||||
|
typeTrigger := 0
|
||||||
|
escapeTrigger := 0
|
||||||
|
escapeTypeTrigger := 0
|
||||||
|
tabTrigger := 0
|
||||||
|
upTrigger := 0
|
||||||
|
downTrigger := 0
|
||||||
|
leftTrigger := 0
|
||||||
|
rightTrigger := 0
|
||||||
|
|
||||||
|
lastTime := time.Now()
|
||||||
|
others := false
|
||||||
|
var newCommand string
|
||||||
|
for evt := range evtChan {
|
||||||
|
// return if exit signal is given
|
||||||
|
if evt.Kind == 4 && (evt.Rawcode == KEYQ) {
|
||||||
|
leftMouseTrigger += 1
|
||||||
|
} else if evt.Kind == 4 && (evt.Rawcode == KEYE) {
|
||||||
|
rightMouseTrigger += 1
|
||||||
|
} else if evt.Kind == 4 && (evt.Rawcode == KEYW) {
|
||||||
|
moveMouseTrigger += 1
|
||||||
|
} else if evt.Kind == 4 && (evt.Rawcode == KEYS) {
|
||||||
|
sleepTrigger += 1
|
||||||
|
} else if evt.Kind == 4 && (evt.Rawcode == KEYD) {
|
||||||
|
typeTrigger += 1
|
||||||
|
} else if evt.Kind == 4 && (evt.Rawcode == KEYESC) {
|
||||||
|
escapeTrigger += 1
|
||||||
|
escapeTypeTrigger += 1
|
||||||
|
} else if evt.Kind == 5 && (evt.Rawcode == KEYESC) {
|
||||||
|
escapeTrigger = 0
|
||||||
|
escapeTypeTrigger = 0
|
||||||
|
} else if evt.Kind == 4 && (evt.Rawcode == KEYCTRL) {
|
||||||
|
escapeTrigger += 1
|
||||||
|
} else if evt.Kind == 5 && (evt.Rawcode == KEYCTRL) {
|
||||||
|
escapeTrigger = 0
|
||||||
|
} else if evt.Kind == 4 && (evt.Rawcode == KEYTAB) {
|
||||||
|
tabTrigger += 1
|
||||||
|
} else if evt.Kind == 4 && (evt.Rawcode == KEYUP) {
|
||||||
|
upTrigger += 1
|
||||||
|
} else if evt.Kind == 4 && (evt.Rawcode == KEYDOWN) {
|
||||||
|
downTrigger += 1
|
||||||
|
} else if evt.Kind == 4 && (evt.Rawcode == KEYLEFT) {
|
||||||
|
leftTrigger += 1
|
||||||
|
} else if evt.Kind == 4 && (evt.Rawcode == KEYRIGHT) {
|
||||||
|
rightTrigger += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if escapeTrigger == 2 {
|
||||||
|
return
|
||||||
|
} else if leftMouseTrigger == 1 {
|
||||||
|
posX, posY := robotgo.GetMousePos()
|
||||||
|
newCommand = fmt.Sprintf("%s %d,%d", MOUSELEFTCLICK, posX, posY)
|
||||||
|
leftMouseTrigger = 0
|
||||||
|
} else if rightMouseTrigger == 1 {
|
||||||
|
posX, posY := robotgo.GetMousePos()
|
||||||
|
newCommand = fmt.Sprintf("%s %d,%d", MOUSERIGHTCLICK, posX, posY)
|
||||||
|
rightMouseTrigger = 0
|
||||||
|
} else if moveMouseTrigger == 1 {
|
||||||
|
posX, posY := robotgo.GetMousePos()
|
||||||
|
newCommand = fmt.Sprintf("%s %d,%d", MOUSEMOVE, posX, posY)
|
||||||
|
moveMouseTrigger = 0
|
||||||
|
} else if sleepTrigger == 1 {
|
||||||
|
newCommand = ""
|
||||||
|
sleepTrigger = 0
|
||||||
|
} else if typeTrigger == 1 {
|
||||||
|
newCommand = fmt.Sprintf("%s \"\"", KEYBOARD)
|
||||||
|
typeTrigger = 0
|
||||||
|
} else if escapeTypeTrigger == 1 {
|
||||||
|
newCommand = TAPESCAPE
|
||||||
|
escapeTypeTrigger = 0
|
||||||
|
} else if tabTrigger == 1 {
|
||||||
|
newCommand = TAPTAB
|
||||||
|
tabTrigger = 0
|
||||||
|
} else if upTrigger == 1 {
|
||||||
|
newCommand = TAPUP
|
||||||
|
upTrigger = 0
|
||||||
|
} else if downTrigger == 1 {
|
||||||
|
newCommand = TAPDOWN
|
||||||
|
downTrigger = 0
|
||||||
|
} else if leftTrigger == 1 {
|
||||||
|
newCommand = TAPLEFT
|
||||||
|
leftTrigger = 0
|
||||||
|
} else if rightTrigger == 1 {
|
||||||
|
newCommand = TAPRIGHT
|
||||||
|
rightTrigger = 0
|
||||||
|
} else {
|
||||||
|
others = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !others {
|
||||||
|
sleepComamnd := fmt.Sprintf("%s %d", SLEEP, int(time.Since(lastTime).Seconds() * 1000))
|
||||||
|
*keyCommands = append(*keyCommands, sleepComamnd)
|
||||||
|
if newCommand != "" {
|
||||||
|
*keyCommands = append(*keyCommands, newCommand)
|
||||||
|
}
|
||||||
|
lastTime = time.Now()
|
||||||
|
} else {
|
||||||
|
others = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
initKeys()
|
||||||
|
var keyCommands []string
|
||||||
|
var runCount int
|
||||||
|
for true {
|
||||||
|
x := mainMenu(&keyCommands, &runCount)
|
||||||
|
fmt.Println(x)
|
||||||
|
if x == "f" {
|
||||||
|
keyCommands = readFile("keys.txt")
|
||||||
|
} else if x == "c" {
|
||||||
|
runCount = changeRunCount()
|
||||||
|
} else if x == "p" {
|
||||||
|
printKeyCommands(keyCommands)
|
||||||
|
} else if x == "r" {
|
||||||
|
runKeyCommands(keyCommands, runCount)
|
||||||
|
} else if x == "l" {
|
||||||
|
listenMode(&keyCommands, &runCount)
|
||||||
|
} else if x == "s" {
|
||||||
|
writeFile("keys.txt", keyCommands)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initKeys() {
|
||||||
|
// 113, 81 - q
|
||||||
|
// 119, 87 - w
|
||||||
|
// 101, 69 - e
|
||||||
|
// 97, 65 - a
|
||||||
|
// 115, 83 - s
|
||||||
|
// 100, 68 - d
|
||||||
|
// 65307, 27 - esc
|
||||||
|
// 114, 82 - r
|
||||||
|
// 122, 90 - z
|
||||||
|
// 65507, 162 - ctrl
|
||||||
|
// 65289,9 - tab
|
||||||
|
// 65361,37 - left
|
||||||
|
// 65362,38 - up
|
||||||
|
// 65363,39 - right
|
||||||
|
// 65364,40 - down
|
||||||
|
if (runtime.GOOS == "windows") {
|
||||||
|
KEYQ = 81
|
||||||
|
KEYW = 87
|
||||||
|
KEYE = 69
|
||||||
|
KEYA = 65
|
||||||
|
KEYS = 83
|
||||||
|
KEYD = 68
|
||||||
|
KEYESC = 27
|
||||||
|
KEYR = 82
|
||||||
|
KEYCTRL = 162
|
||||||
|
KEYTAB = 9
|
||||||
|
KEYUP = 38
|
||||||
|
KEYDOWN = 40
|
||||||
|
KEYLEFT = 37
|
||||||
|
KEYRIGHT = 39
|
||||||
|
KEYZ = 90
|
||||||
|
} else {
|
||||||
|
KEYQ = 113
|
||||||
|
KEYW = 119
|
||||||
|
KEYE = 101
|
||||||
|
KEYA = 97
|
||||||
|
KEYS = 115
|
||||||
|
KEYD = 100
|
||||||
|
KEYESC = 65307
|
||||||
|
KEYR = 114
|
||||||
|
KEYCTRL = 65507
|
||||||
|
KEYTAB = 65289
|
||||||
|
KEYUP = 65362
|
||||||
|
KEYDOWN = 65364
|
||||||
|
KEYLEFT = 65361
|
||||||
|
KEYRIGHT = 65363
|
||||||
|
KEYZ = 122
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readFile(filename string) []string {
|
||||||
|
filecontent, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
keyCommands := strings.Split(string(filecontent), "\n")
|
||||||
|
return keyCommands
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeFile(filename string, keyCommand []string) {
|
||||||
|
fmt.Println("Writing instructions to file...")
|
||||||
|
f, err := os.Create(filename)
|
||||||
|
defer f.Close()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
for _, keyCommand := range keyCommand {
|
||||||
|
f.WriteString(keyCommand)
|
||||||
|
f.WriteString("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func changeRunCount() int {
|
||||||
|
var runCount int
|
||||||
|
fmt.Print("Enter run count: ")
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
countStr, _ := reader.ReadString('\n')
|
||||||
|
countStr = strings.ReplaceAll(countStr, "\n", "")
|
||||||
|
countStr = strings.ReplaceAll(countStr, "\r", "")
|
||||||
|
runCount, err := strconv.Atoi(countStr)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
fmt.Println("Setting run count as 1...")
|
||||||
|
runCount = 1
|
||||||
|
}
|
||||||
|
return runCount
|
||||||
|
}
|
||||||
|
|
||||||
|
func printKeyCommands(keyCommands []string) {
|
||||||
|
fmt.Println("------------------------------")
|
||||||
|
for _, keyCommand := range keyCommands {
|
||||||
|
fmt.Println(keyCommand)
|
||||||
|
}
|
||||||
|
fmt.Println("------------------------------")
|
||||||
|
}
|
||||||
|
|
||||||
|
func runKeyCommands(keyCommands []string, runCount int) {
|
||||||
|
fmt.Printf("Running commands for %d times\n", runCount)
|
||||||
|
for i:=0; i<runCount; i++ {
|
||||||
|
for _, keyCommand := range(keyCommands) {
|
||||||
|
parseKeyCommand(keyCommand)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseKeyCommand(keyCommand string) {
|
||||||
|
// Mouse left click
|
||||||
|
if strings.Index(keyCommand, MOUSELEFTCLICK) == 0 {
|
||||||
|
args := strings.Split(keyCommand[len(MOUSELEFTCLICK)+1:len(keyCommand)], ",")
|
||||||
|
for n, _ := range(args) {
|
||||||
|
args[n] = strings.ReplaceAll(args[n], " ", "")
|
||||||
|
}
|
||||||
|
argX, err := strconv.Atoi(args[0])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
argY, err := strconv.Atoi(args[1])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
robotgo.MoveClick(argX, argY, "left", false)
|
||||||
|
// Mouse right click
|
||||||
|
} else if strings.Index(keyCommand,MOUSERIGHTCLICK) == 0 {
|
||||||
|
args := strings.Split(keyCommand[len(MOUSERIGHTCLICK)+1:len(keyCommand)], ",")
|
||||||
|
for n, _ := range(args) {
|
||||||
|
args[n] = strings.ReplaceAll(args[n], " ", "")
|
||||||
|
}
|
||||||
|
argX, err := strconv.Atoi(args[0])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
argY, err := strconv.Atoi(args[1])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
robotgo.MoveClick(argX, argY, "right", false)
|
||||||
|
// Mouse move
|
||||||
|
} else if strings.Index(keyCommand, MOUSEMOVE) == 0 {
|
||||||
|
args := strings.Split(keyCommand[len(MOUSEMOVE)+1:len(keyCommand)], ",")
|
||||||
|
for n, _ := range(args) {
|
||||||
|
args[n] = strings.ReplaceAll(args[n], " ", "")
|
||||||
|
}
|
||||||
|
argX, err := strconv.Atoi(args[0])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
argY, err := strconv.Atoi(args[1])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
robotgo.Move(argX, argY)
|
||||||
|
// Sleep
|
||||||
|
} else if strings.Index(keyCommand, SLEEP) == 0 {
|
||||||
|
args := keyCommand[len(SLEEP)+1:len(keyCommand)]
|
||||||
|
sleepTime, err := strconv.Atoi(args)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
time.Sleep(time.Duration(sleepTime) * time.Millisecond)
|
||||||
|
// Keyboard type
|
||||||
|
} else if strings.Index(keyCommand, KEYBOARD) == 0 {
|
||||||
|
args := keyCommand[len(KEYBOARD)+1:len(keyCommand)]
|
||||||
|
strokes, err := strconv.Unquote(args)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
robotgo.TypeString(strokes)
|
||||||
|
} else if strings.Index(keyCommand, TAPESCAPE) == 0 {
|
||||||
|
robotgo.KeyTap("escape")
|
||||||
|
} else if strings.Index(keyCommand, TAPTAB) == 0 {
|
||||||
|
robotgo.KeyTap("tab")
|
||||||
|
} else if strings.Index(keyCommand, TAPUP) == 0 {
|
||||||
|
robotgo.KeyTap("up")
|
||||||
|
} else if strings.Index(keyCommand, TAPDOWN) == 0 {
|
||||||
|
robotgo.KeyTap("down")
|
||||||
|
} else if strings.Index(keyCommand, TAPLEFT) == 0 {
|
||||||
|
robotgo.KeyTap("left")
|
||||||
|
} else if strings.Index(keyCommand, TAPRIGHT) == 0 {
|
||||||
|
robotgo.KeyTap("right")
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
mrRobotic.exe
Executable file
BIN
mrRobotic.exe
Executable file
Binary file not shown.
22
test/main.go
Normal file
22
test/main.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/go-vgo/robotgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
fmt.Println("--- Please press ctrl + shift + q ---")
|
||||||
|
// start hook
|
||||||
|
s := robotgo.Start()
|
||||||
|
// end hook
|
||||||
|
defer robotgo.End()
|
||||||
|
|
||||||
|
for ev := range s {
|
||||||
|
fmt.Println("hook: ", ev)
|
||||||
|
fmt.Println(ev.Kind)
|
||||||
|
fmt.Println(ev.Rawcode)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user