Here is an example auto hot key script:
^j::
WinActivate, MyWindow
WinWaitActive, MyWindow
Loop
{
If GetKeyState("Shift", "P")
Break
Click, 44, 55
Sleep, 1000
Click, 144, 155
Sleep, 1000
}
return
Everything works fine but I can't interrupt the loop by pressig "Shift". What is wrong ?
You have to hold the Shift key for more than 2 seconds pressed, because of the sleep times.
Or try something like this:
^j::
Loop
{
If !WinActive("MyWindow")
{
WinActivate, MyWindow
WinWaitActive, MyWindow
}
Click, 44, 55
Sleep_1000()
Click, 144, 155
Sleep_1000()
}
return
Sleep_1000(){
Loop 10
{
Sleep, 100
If GetKeyState("Shift", "P")
exit ; terminate the hotkey's thread
}
}
Using a loop inside a hotkey definition is bad practice.
AHK doesn't provide true multithreading, so long running loops are generally a really bad idea.
Using a timer fixes this, and usage of a timer is anyway always what you want for something like this.
And it'll be much more simple as well.
So, with Ctrl+j we activate the desired window and create the timer and tell it to run our function TimerCallback (which we will shortly create) every 2secs:
^j::
WinActivate, MyWindow
WinWaitActive, MyWindow ;shouldn't be needed, but if you find it helpful, fair enough
TimerCallback() ;run the function once, since the timer is going to
;run it for the first time only after 2secs
SetTimer, TimerCallback, 2000
return
And then we make shift be a hotkey for turning off the timer. And we for sure want to use the ~ modifier to not consume the key when the hotkey is fired:
~Shift::SetTimer, koira, Off
And now lets also define our function TimerCallback:
TimerCallback()
{
Click, 44, 55
Sleep, 1000
Click, 144, 155
}
So here's again the script in full if something was somehow left unclear:
^j::
WinActivate, MyWindow
WinWaitActive, MyWindow ;shouldn't be needed, but if you find it helpful, fair enough
TimerCallback() ;run the function once, since the timer is going to
;run it for the first time only after 2secs
SetTimer, TimerCallback, 2000
return
~Shift::SetTimer, TimerCallback, Off
TimerCallback()
{
Click, 44, 55
Sleep, 1000
Click, 144, 155
}
Related
I use AutoHotkey for windows. I want to write a script in order to paste (the text I copied earlier) with middle button click of the mouse to searchbar of the program Oxford dictionary on my computer. and also when the the window of the program is closed, after I clicked middle button of the mouse automatically open the window and do the same thing I wanted( paste the copied word into the searchbar of program). I write this code :
MButton::
IfWinExist, Oxford Advanced Learner's Dictionary
{
WinActivate
Click, 182, 133, 2
Send, ^a{Delete}
sleep, 100
Send, ^v{Enter}
}
else
{
Run, "E:\dictionary oxford\OALD9.exe"
WinActivate, Oxford Advanced Learner's Dictionary
sleep, 500
Click, 182, 133, 2
Send, ^a{Delete}
sleep, 100
Send, ^v{Enter}
}
return
When I run the code, it just do the first task I wanted. It paste into the search bar of the Oxford Dictionary when it is open. But when it is closed, after I click middle button of the mouse it just open the program and doesn't paste the word into the searchbar.
WinWait is your friend.
Documentation
MButton::
IfWinExist, Oxford Advanced Learner's Dictionary
{
WinActivate
Click, 182, 133, 2
Send, ^a{Delete}
Sleep, 100
Send, ^v{Enter}
}
else
{
Run, "E:\dictionary oxford\OALD9.exe"
WinWait, Oxford Advanced Learner's Dictionary,,4
WinActivate, Oxford Advanced Learner's Dictionary
Sleep, 500
Click, 182, 133, 2
Send, ^a{Delete}
Sleep, 100
Send, ^v{Enter}
}
return
Edit: You might want to consider RunWait, also. Documentation
I need to pause a spacebar spamming macro with a key like f10, here is my code
c::
Loop
{
if not GetKeyState("c", "P")
break
Sleep 25 ; ms
Send {space}
}
return
I tried to add a pause similar to the getkeystate in and out of the loop but to no avail.
I always do something to the extent of this:
c::
Toggle := !Toggle
While Toggle {
; do whatever you need to do here
}
Return
An additional advantage here is that there's only one hotkey to remember. Press once to begin the endless loop. Press again to stop.
q::
Loop
{
Click, right,
Mousemove, 0, 110, 5, Rel
click, left
Mousemove, 350, -473, 5, rel
click, left
Mousemove, -350, 363, 5, rel
}
return
#p::Pause,Toggle
https://autohotkey.com/board/topic/95308-endless-loop-with-hotkey-pause/
I would like my code to show 'paused' upon script being paused and show 'running' for only a short interval after the script is unpaused.
However, it did not work as expected.
My code below (commented the problematic issue):
NumpadEnter:: ; script is paused on said key and reactivated on said key
Suspend
ToolTip, PAUSED, 200, 250
Pause ,, 1
; ; ToolTip, RUNNING, 200, 250 ; Code segment when un-commented does not work as it should
; ; Sleep 500 ;
SetTimer, RemoveToolTip, 1
return
RemoveToolTip:
SetTimer, RemoveToolTip, Off
ToolTip
return
Thank you so much!!
Try this:
NumpadEnter::
Suspend
Pause ,,1
if A_IsPaused {
ToolTip, PAUSED, 200, 250
} else {
ToolTip, RUNNING, 200, 250
SetTimer RemoveToolTip, 1000
}
return
RemoveToolTip:
ToolTip
SetTimer, RemoveToolTip, Off
return
I wrote a script that sends autofire left clicks and can be triggered on and off. The script works. However, the problem is that holding the right mouse button does not work properly anymore because the left click keeps getting sent. So I want to change the script that it gets temporarily paused while I hold down the right mouse button.
How would I go about doing this? Here is my current code:
#MaxThreadsPerHotkey 3
#z::
#MaxThreadsPerHotkey 1
if keep_winz_running = y
{
keep_winz_running = n
return
}
; Otherwise:
keep_winz_running = y
Loop
{
GetKeyState, rbut, Rbutton
If rbut, = U
{
Loop,
{
MouseClick, left
Sleep, 50 ;This means the script will wait 1.5 secs
if keep_winz_running = n ; The user signaled the loop to stop.
break ; break out of the loop
}
Timers are the best!
sendToggle := false
#z::
if(!sendToggle) {
sendToggle := true
SetTimer, SendClick, 100
} else {
sendToggle := false
SetTimer, SendClick, Off
}
return
#If sendToggle
RButton::
SetTimer, SendClick, Off
KeyWait, RButton
SetTimer, SendClick, 100
return
SendClick:
Click
return
I find the send interval of 50 ms awfully fast, especially since you won't be able to actually reach 50 ms without reducing SetBatchLines and SetKeyDelay. If it really needs to be that fast, consider changing them.
My loop in my autohotkey script is only running through once. Can anyone tell me why? Thanks
Loop, 8
{
WinActivate, NDTr
ControlClick, Button3 ;Select Batch, enter info, start collecting data
WinWait, Batch Readings
ControlClick, Edit1
Send {BS}+{BS}+{BS}+{BS}+{BS}+{BS}
Send 1
ControlClick, Edit2
Send {BS}+{BS}+{BS}+{BS}+{BS}+{BS}
Send 15
if A_Index = 4
{
Sleep, 20000
}
else if A_Index = 7
{
Sleep, 20000
}
else if A_Index = 1
{
Sleep, 3000
}
else
{
Sleep, 15000
}
ControlClick, Button1
Sleep, 15000
}
WinWait looks like a likely culprit like anthv123 said. Double check your window's title and make sure it fits the TitleMatchMode that you're expecting.
Common debugging practices include adding different ToolTips in places along the problem code. For example tooltips above and below the WinWait line with texts "before" and "after" would tell you if it's pausing indefinitely at that part (if it never says "after").
Sleeping for 3-20 seconds isn't going to help your patience either.
Try using this to diagnose the issue. If "Batch Readings" takes longer than 5 seconds, you get an error letting you know and the loop continues
WinWait, Batch Readings,,5
if (errorLevel = 1)
Msgbox % "Batch Readings timed out"