Queer European MD passionate about IT

helper.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. package helper
  2. import (
  3. "fmt"
  4. "log"
  5. "math"
  6. "os"
  7. "os/signal"
  8. "strings"
  9. "time"
  10. "github.com/go-vgo/robotgo"
  11. "gopkg.in/yaml.v3"
  12. )
  13. type Point struct {
  14. X int
  15. Y int
  16. }
  17. func (p Point) String() string {
  18. return fmt.Sprintf("(%v, %v)", p.X, p.Y)
  19. }
  20. func (p Point) Click(button ...string) {
  21. buttonToClick := "left"
  22. if len(button) > 0 && (button[0] == "left" || button[0] == "right") {
  23. buttonToClick = button[0]
  24. }
  25. robotgo.Move(p.X, p.Y)
  26. robotgo.Click(buttonToClick, false)
  27. }
  28. func (p Point) RightClick() {
  29. p.Click("right")
  30. }
  31. func (p1 *Point) GetDistance(p2 *Point) float64 {
  32. return math.Sqrt(math.Pow(float64(p1.X-p2.X), float64(2)) + math.Pow(float64(p1.Y-p2.Y), float64(2)))
  33. }
  34. func (p0 *Point) GetDistanceFromClosest(pp ...*Point) float64 {
  35. var minDistance float64
  36. for index, p := range pp {
  37. if distance := p.GetDistance(p0); index == 0 || distance < minDistance {
  38. minDistance = distance
  39. }
  40. }
  41. return minDistance
  42. }
  43. type PointGroup struct {
  44. Name string
  45. Points []*Point
  46. }
  47. type SavedGroups struct {
  48. Groups []PointGroup
  49. }
  50. func getSavedGroups(yamlFile string) *SavedGroups {
  51. s := SavedGroups{}
  52. inputFile, err := os.ReadFile(yamlFile)
  53. if err == nil { // No yaml file found
  54. err = yaml.Unmarshal(inputFile, &s)
  55. if err != nil {
  56. log.Fatalf("%v - Exiting", err)
  57. }
  58. }
  59. for index, g := range s.Groups {
  60. if index == 0 {
  61. fmt.Println("Available groups:")
  62. }
  63. fmt.Printf("%v. %v\n", index+1, g.Name)
  64. }
  65. return &s
  66. }
  67. func addSavedGroup(s *SavedGroups) {
  68. g := PointGroup{}
  69. var name string
  70. var points int
  71. for {
  72. name = ""
  73. fmt.Print("If you want to add a new group of locations, enter a name. Press enter to skip. ")
  74. fmt.Scanln(&name)
  75. if name == "" {
  76. break
  77. }
  78. fmt.Printf("How many positions are there in group %v? ", name)
  79. _, err := fmt.Scanln(&points)
  80. if err != nil {
  81. fmt.Println("I haven't understood, try again...")
  82. var discard string
  83. fmt.Scanln(&discard)
  84. continue
  85. }
  86. for i := 0; i < points; i++ {
  87. fmt.Printf("Please move your mouse into position %v of %v (group %v)\n", i+1, points, name)
  88. time.Sleep(2 * time.Second)
  89. x, y := robotgo.GetMousePos()
  90. fmt.Printf("Added point (x=%v, y=%v) to %v\n", x, y, name)
  91. p := Point{X: x, Y: y}
  92. g.Points = append(g.Points, &p)
  93. }
  94. g.Name = name
  95. s.Groups = append(s.Groups, g)
  96. }
  97. }
  98. func storeSavedGroups(s *SavedGroups, yamlFile string) {
  99. d, err := yaml.Marshal(s)
  100. if err != nil {
  101. log.Fatalf("error: %v", err)
  102. }
  103. err = os.WriteFile(yamlFile, d, 0644)
  104. if err != nil {
  105. log.Fatalf("error: %v", err)
  106. }
  107. }
  108. func AbsInt(i int) int {
  109. if i > 0 {
  110. return i
  111. }
  112. return -i
  113. }
  114. func Oscillator(amplitude int) chan int {
  115. amplitude--
  116. c := make(chan int, 1)
  117. i := amplitude
  118. go func() {
  119. for {
  120. c <- AbsInt((i%(amplitude*2))-amplitude) + 1
  121. i++
  122. if i == amplitude*2 {
  123. i = 0
  124. }
  125. }
  126. }()
  127. return c
  128. }
  129. func StringOscillator(s string, amplitude int) chan string {
  130. c := make(chan string)
  131. o := Oscillator(amplitude)
  132. go func() {
  133. for {
  134. c <- strings.Repeat(s, <-o)
  135. }
  136. }()
  137. return c
  138. }
  139. func press(key string) {
  140. robotgo.KeyTap(key)
  141. }
  142. func keyboardWrite(s string) {
  143. robotgo.TypeStr(s)
  144. robotgo.MilliSleep(100)
  145. }
  146. func ClickRepeatedly(s *SavedGroups, c chan os.Signal) {
  147. for index, g := range s.Groups {
  148. fmt.Printf("- Press %v to select %v\n", index+1, g.Name)
  149. }
  150. var choice int
  151. for choice < 1 {
  152. fmt.Print("Your selection: ")
  153. _, err := fmt.Scanln(&choice)
  154. if err != nil {
  155. fmt.Println("I haven't understood, try again...")
  156. var discard string
  157. fmt.Scanln(&discard)
  158. continue
  159. }
  160. if choice > len(s.Groups) {
  161. choice = 0
  162. }
  163. }
  164. selection := s.Groups[choice-1]
  165. fmt.Printf("You selected %v. I'll be clicking in the following positions:\n", selection.Name)
  166. for index, p := range selection.Points {
  167. fmt.Printf("%v - %v\n", index+1, p)
  168. }
  169. o := StringOscillator(".", 15)
  170. var t int
  171. var minDistance float64
  172. for {
  173. for _, p := range selection.Points {
  174. p.Click()
  175. time.Sleep(100 * time.Millisecond)
  176. }
  177. fmt.Println(<-o)
  178. time.Sleep(500 * time.Millisecond)
  179. t = 0
  180. for t = 0; t < 10; t++ {
  181. x, y := robotgo.GetMousePos()
  182. currentPosition := Point{X: x, Y: y}
  183. minDistance = currentPosition.GetDistanceFromClosest(selection.Points...)
  184. if minDistance <= 50 {
  185. break
  186. }
  187. fmt.Printf("%v You moved the mouse (distance %.2f), waiting 2 seconds (%v of 10)\n", strings.Repeat("_", 10-t), minDistance, t+1)
  188. time.Sleep(2 * time.Second)
  189. }
  190. if t >= 10 {
  191. fmt.Println("You stayed away too long, exiting...")
  192. c <- os.Interrupt
  193. return
  194. }
  195. }
  196. }
  197. func cleanUp(c chan os.Signal) chan int {
  198. r := make(chan int)
  199. go func() {
  200. signal := <-c
  201. fmt.Printf("Got signal %v, cleaning up...\n", signal)
  202. r <- 1
  203. }()
  204. return r
  205. }
  206. func interactWithUser(s *SavedGroups, yamlFile string, c chan os.Signal) {
  207. addSavedGroup(s)
  208. storeSavedGroups(s, yamlFile)
  209. ClickRepeatedly(s, c)
  210. }
  211. func RunAutoClicker() {
  212. c := make(chan os.Signal, 1)
  213. quit := cleanUp(c)
  214. signal.Notify(c, os.Interrupt)
  215. yamlFile := "SavedGroups.yaml"
  216. s := getSavedGroups(yamlFile)
  217. go interactWithUser(s, yamlFile, c)
  218. if <-quit == 1 {
  219. fmt.Println("Exiting...")
  220. } else {
  221. fmt.Println("Unknown error...")
  222. }
  223. }