AutoClicker

Some time ago I needed to scan a few books.
There was about 2000 pages in all. Not very much, because I had some months and nobody hurried me. The cover of books was soft, pages glued and that was impossible to open a book at 180 degree angle. So, to get a good scan I had to apply significant force to the book’s cover to flatten it on the scan glass. I had to push the “scan” button and immediately use all my weight on the book to flatten it (yes, my scanner is creaking and squeaking after that work…)

It is very inconvenient for one person to push the button and to hold a book.
There were two possible solutions that could give me the maximum speed – to create a pedal for starting a scanning process or to ask an another human being to help me.
Creation of pedal was too difficult for me because I had no any electronic and mechanical components at that time. Moreover, that pedal had to press a virtual button in the PC application, so it had to be some microcontroller’s stuff, maybe usb-to-com converter ad so on. It couldn’t be just a parallel switch over some hardware “scan” button. That was too long way for the copying of 5 books.
The next way was a help of neighbors… But there is a lack of neighbor human beings around me and those few that can be found – are not interested in a boring scanning process.
By the way I have a surplus of neighbor cat beings around… But… You know… There is a little chance to persuade a cat to help you.
They just sleep and eat and think that you are their servant.

After all I realized that the best I can do is an utility which will do clicks by timer. An autoclicker.
It is slower than starting the scanning process on demand, but the best I could.
There are plenty of similar utilities on the Internet but ALL of them has one significant disadvantage in my case.
They ALL have no visual indicator of remaining time before the next click.
To have this indicator was a very important thing for me, because I needed to know, how many time I wasted when struggled with a book and when I have to stop moving and hold it as it is.
Because I was unable to find suitable software on the internet I have written two little scripts by myself.

The first was a Perl script, because at that time I was in Linux Phase (now I’m in the phase of remission but I know that my relapse is not too far…).

Perl autoclicker
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#! /usr/bin/perl
 
use utf8;
use strict;
 
$| = 1;
 
my($x, $y, $timeout, $count) = @ARGV;
my $timer   	= 0;
my $counter     = 0;
 
die("incorrect X value: $x")        if( $x < 0 or $x > 1366);
die("incorrect Y value: $y")        if( $y < 0 or $y > 768);
die("incorrect timeout: $timeout")  if( $timeout !~ /^\d+$/);
die("incorrect count: $count")      if( $count !~ /^\d+$/);
 
$SIG{ALRM} = sub { 
	alarm 1; 
	$timer--, print "\riteration: $counter; timer: $timer;        " if $timer > 0;
};
 
if( $x == 0 and  $y == 0){
    ($x, $y) = split(' ', `xdotool getmouselocation`);
    $x =~ s/\D//g;
    $y =~ s/\D//g;
}
 
 
print "starting job. $count clicks ($x,$y) with ${timeout}sec timeout\n";
$timer      = $timeout;
$counter    = $count;
 
alarm 1;
foreach (1..$count){
    $timer  = $timeout;
    while($timer){ sleep 1; };
    `xdotool mousemove $x $y  click 1`;
    $counter --;
}
 
print "\n";
1;

This script is supposed to get 4 command line parameters: two coordinates of the click, timeout between clicks and the total number of clicks.
It can’t be considered as perfectly sane because of the variety of reasons. But it works and it helped me a lot.
It uses xdotool to control the mouse and ALRM interrupt to display the current state of the process in command line. Also it has hardcoded screen resolution for 1366×768 screen.

Then I switched to windows.
For some days I thought that I wouldn’t be able to create such simple and useful script on Windows. But then I found AutoIt.
It was an amazing thing for my case. It have helped me to easily create a GUI script, which looks very nice and more appropriate for a graphical environment than a console application.
autoclocker
I have posed this script on Sourceforge but I haven’t been seeing any interest 🙂
I wonder, how other people scan books? Maybe there is a some trick that I have missed? Maybe those people found a way to cozy to cats and get their help?

Anyway, here is my AutoIt script:

Autoit autoclicker
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
 
#include <GUIConstants.au3>
#include <AutoItConstants.au3>
#include <MsgBoxConstants.au3>
 
 
$Version = 1.02
 
$HelpMessage = "ProgressbarAutoclicker v" &$Version & @CRLF & _
"AutoIt script " & @CRLF & _
"kozyavk@gmail.com"  & @CRLF & _
"https://sourceforge.net/projects/progressbarautoclicker/" & @CRLF & _
""    & @CRLF & _
"shortcut for GetCoord button - CTRL+SHIFT+g"
 
 
$hGUI 			= GUICreate ("ProgressbarAutoClicker v"&$Version, 290, 230,-1,-1,Default,Default)
 
$CTRL_LblStatus 	= GUICtrlCreateLabel("Status: Waiting", 12, 10, 200, 26)
 
$progressbar1 		= GUICtrlCreateProgress (8,30,270,20,$PBS_SMOOTH)
$progressbar2 		= GUICtrlCreateProgress (8,60,270,20,$PBS_SMOOTH)
 
$CTRL_LblX 		= GUICtrlCreateLabel("X coord ", 8, 105, 50, 18)
$CTRL_EdtX 		= GUICtrlCreateEdit("0", 50, 100, 50, 18, $WS_EX_WINDOWEDGE)
$CTRL_LblXx 		= GUICtrlCreateLabel("px", 103, 105, 30, 18)
 
$CTRL_LblY 		= GUICtrlCreateLabel("Y coord ", 165, 105, 50, 18)
$CTRL_EdtY 		= GUICtrlCreateEdit("0", 205, 100, 50, 18, $WS_EX_WINDOWEDGE)
$CTRL_LblYy		= GUICtrlCreateLabel("px", 260, 105, 50, 18)
 
$CTRL_LblIter 		= GUICtrlCreateLabel("Clicks", 8, 125, 50, 20)
$CTRL_EdtIter		= GUICtrlCreateEdit("5", 50, 120, 50, 20, $WS_EX_WINDOWEDGE)
 
$CTRL_LblTimeout 	= GUICtrlCreateLabel("Timeout", 165, 125, 50, 20)
$CTRL_EdtTimeout	= GUICtrlCreateEdit("5", 205, 120, 50, 20, $WS_EX_WINDOWEDGE)
$CTRL_LblT		= GUICtrlCreateLabel("sec", 260, 125, 30, 18)
 
$CTRL_checkbox0		= GUICtrlCreateCheckbox("Stay on top", 8, 150, 150, 29 )
 
$CTRL_btn0 		= GUICtrlCreateButton("GetCoord", 8, 190, 70, 29)
$CTRL_btn1 		= GUICtrlCreateButton("START", 90, 190, 70, 29)
$CTRL_btn2 		= GUICtrlCreateButton("PAUSE", 170, 190, 70, 29)
$CTRL_btn3 		= GUICtrlCreateButton("?", 250, 190, 29, 29)
 
GUISetState()
 
 
 
$proc_run 		= 0 ; process is running flag
$is_paused		= 0 ; process is paused  flag
$timediff_when_paused	= 0 ; iteration time when pause button was pressed
$pause_time_adjust 	= 0 ; time left while pause button was pressed
$cur_iter 		= 0 ; number of current iteration
$time_beg		= 0 ; handler of timer for the beginning of current iteration
 
GUICtrlSetData ($progressbar1,100)
GUICtrlSetData ($progressbar2,100)
 
HotKeySet("^+g", "_GetMousePosition") ; Ctrl-Shift-g
 
_GetMousePosition()
 
Do
  $msg = GUIGetMsg()
 
   Select
   Case $msg = $CTRL_btn0 ; GET COORDINATES
	  _GetMousePosition()
   Case $msg = $CTRL_btn1 ; START/STOP
	  If( $proc_run = 0 )Then
		 $time_beg = TimerInit();
		 $proc_run = 1;
		 $cur_iter = 0;
		 GUICtrlSetData ( $CTRL_btn1, "STOP")
	  Else
		 $proc_run 		= 0
		 $cur_iter 		= 0
		 $time_beg		= 0
		 $is_paused 	        = 0
		 $pause_time_adjust 	= 0
		 $timediff_when_paused 	= 0
 
		 GUICtrlSetData ($progressbar1,100)
		 GUICtrlSetData ($progressbar2,100)
		 GUICtrlSetData ( $CTRL_LblStatus, "Status: Waiting")
		 GUICtrlSetData ( $CTRL_btn1, "START")
		 GUICtrlSetData ( $CTRL_btn2, "PAUSE")
	  EndIf
   Case $msg = $CTRL_btn2 And $proc_run = 1        ; PAUSE
 
	  If $is_paused = 0 Then
		 $is_paused = 1
		 GUICtrlSetData ( $CTRL_btn2, "CONTINUE")
		 $timediff_when_paused = TimerDiff($time_beg)
		 If $pause_time_adjust > 0 And $pause_time_adjust < $timediff_when_paused Then
			$timediff_when_paused = $timediff_when_paused - $pause_time_adjust
		 EndIf
	  Else
		 $is_paused = 0
		 $cur_timediff = TimerDiff($time_beg)
		 $pause_time_adjust = $cur_timediff - $timediff_when_paused
		 GUICtrlSetData ( $CTRL_btn2, "PAUSE")
	  EndIf
 
   Case $msg = $CTRL_checkbox0
	  If _IsChecked($CTRL_checkbox0) Then
		WinSetOnTop($hGUI, "", $WINDOWS_ONTOP)
	  Else
		WinSetOnTop($hGUI, "", $WINDOWS_NOONTOP)
	 EndIf
 
   Case $msg = $CTRL_btn3 ; Help
	  MsgBox ( $MB_OK, "Help", $HelpMessage, 0, $hGUI )
 
  EndSelect
 
   $ref_time	= GUICtrlRead($CTRL_EdtTimeout) * 1000;
   $iter_num	= GUICtrlRead($CTRL_EdtIter)
 
   If $proc_run = 1 And $is_paused = 0 Then
	  $diff = TimerDiff($time_beg)
 
	  If $pause_time_adjust > 0 And $pause_time_adjust < $diff Then
		 $diff = $diff - $pause_time_adjust
	  EndIf
 
	  If $diff >= $ref_time Then
		 ;do click
		 MouseClick("left", GUICtrlRead($CTRL_EdtX), GUICtrlRead($CTRL_EdtY), 1, 0)
		 $cur_iter+=1;
		 $pause_time_adjust = 0;
		 If $cur_iter < $iter_num Then
			$time_beg = TimerInit();
		 Else
			$proc_run 	= 0;
			$cur_iter 	= 0;
			$time_beg	= 0;
		 EndIf
	  EndIf
 
		 If $proc_run = 1 Then
			GUICtrlSetData ( $CTRL_LblStatus, "Countdown: clicks " & ($iter_num - $cur_iter) & ";   time: " & (GUICtrlRead($CTRL_EdtTimeout) - Floor($diff/1000)))
			GUICtrlSetData ($progressbar1,100-(Floor($diff/1000) * 100 / GUICtrlRead($CTRL_EdtTimeout)))
			GUICtrlSetData ($progressbar2,100-($cur_iter*100 / $iter_num))
		 Else
			GUICtrlSetData ( $CTRL_LblStatus, "Status: Waiting")
			GUICtrlSetData ($progressbar1,100)
			GUICtrlSetData ($progressbar2,100)
			GUICtrlSetData ( $CTRL_btn1, "START")
			GUICtrlSetData ( $CTRL_btn2, "PAUSE")
		 EndIf
 
	  Sleep(100)
   EndIf
Until $msg = $GUI_EVENT_CLOSE
 
 
 
Func _IsChecked($idControlID)
    Return BitAND(GUICtrlRead($idControlID), $GUI_CHECKED) = $GUI_CHECKED
EndFunc
 
 
Func _GetMousePosition()
   $pos = MouseGetPos()
   GUICtrlSetData ( $CTRL_EdtX, $pos[0] )
   GUICtrlSetData ( $CTRL_EdtY, $pos[1] )
EndFunc

To debug and compile AutoIt scripts you need the AutoIt framework installed, but after you had compiled the script into executable file – it can be run on any Windows and even on Wine.

You can also download precompiled executable file.

UPDATE 19.02.2019
As it turned out, in spite very low number of downloads my Progressbar AutoClicker has some users!
There is at least one user definitely! 😀
Last year one of them contacted me by email and asked to add the ability to set time in AutoClicker with millisecond precision.
So now GUI looks like this:

The latest compiled script and source code can be downloaded on SourceForge.