Toggle infinite loop by the same key - autohotkey

I want to be able to press key and run an infinite loop, and be able to press the same key to stop the loop. In a simple case I want the script to click indefinitely:
XButton2::
if (Doing = 0)
{
Doing := 1
While Doing = 1
{
Click
}
return
} else {
Doing := 0
}
Unfortunately this doesn't work - XButton2 does not respond any more because it is running a script. I can switch Doing := 0 by other key but I want for it to be the same XButton2. Any simple way of doing this? I would avoid complicated solutions.

Use a timed subroutine. That's how you'd start/stop a loop in ahk usually.
For example:
clicking := false
label_click:
click
return
XButton2::
clicking := !clicking
if(clicking)
setTimer, label_click, 1 ; click once every millisecond (approx.)
else
setTimer, label_click, off
return
That is how I usually do it, though I'd love to see a more compact version.

Related

How to press and hold 3 keys one after the other

New to Auto Hotkey. I’m looking to create a hotkey to press and hold Control, then press and hold Alt, then press “W”, then let go of all 3 and do the same after 30 seconds.
I tried this but unsure if it’s right. Thanks!
#SingleInstance, force
#MaxThreadsPerHotkey 2
F10::
Toggle := !Toggle
while Toggle
{
Send, {Ctrl}
Send, {Alt}
Send, {W}
Sleep, 30000 ;
}
Return
This should work:
#SingleInstance, force
F10::
Toggle := !Toggle
if (Toggle)
{
gosub, sub
SetTimer sub, 30000
}
else{
SetTimer sub, Off
}
Return
sub:
Send ^!w
return
Notes:
When a sleep command is used, the program is unable to detect hotkeys being pressed. Instead of using multiple threads, it would be better to implement a SetTimer/ Subroutine system.
In order to send Ctrl+Alt+W, just use Send ^!w. (^ means Control, ! means Alt, and and w means w; for more info, see modifiers.

Repeatedly calling a hotkey

I've tried to implement a t flip flop(I think this is what it's called) into my program but am having some issues with it. The idea is to have the program start and stop while using the same hotkey. This is what I have so far.
looping := false
pass = 0
max = 2
^r::
pass++
looping := true
while(looping = true AND pass < max)
{
Send, stack overflow, save me!
}
looping := false
pass = 0
return
When I run the program and hit the hotkey the while loop starts. However, when I attempt to break the loop by pressing ^r I get no response and the program keeps looping.
I think you are referring to a "toggle" script. I am not what sure you are trying to achieve exactly, but the key is using a logical not: looping := !true. More about it here.
looping := false
pass = 0
max = 2
^r::
pass++
looping := !true
while (looping & pass < max)
{
Send, stack overflow, save me!
}
pass = 0
return
There's a lot of resources for this, here are a few:
https://autohotkey.com/boards/viewtopic.php?t=11952
http://maul-esel.github.io/ahkbook/en/toggle-autofire.html
https://www.reddit.com/r/AutoHotkey/comments/6wqgbu/how_do_i_toggle_hold_down_a_key/dmad0xx

autohotkeys using ifwinactive with expression not working

I am using AutoHotKeys to test if a window is active along with an expression. I don't seem to be able to get it to work. I am assigning the expression to a variable and then testing for ifWinActive and the variable. AutoHotKeys doesn't seem to be able to evaluate the expression correctly. This is my script:
^W::
;hotkey always fires
done = false
SetTimer, CheckPopups, 10000 ; check every 10 seconds for window
CheckPopups:
this := (done != true)
#IfWinActive "Volume Spike - Down" and this
{
;specific lines only when active window is true and done is false
msgbox hello
done := true
}
IfWinNotActive Volume Spike - Down
{
done = false
}
When I launch the script and the window is not active, it shows the message box Hello. Then 10 seconds later it shows it again. It should only show the message box if the window is active and done = false. Any idea what I am doing wrong?
You're using #IfWinActive, which is a directive used to create conditional hotkeys. You should use IfWinActive instead.
You can also use the function version, WinActive() inside your if-clause. It makes it look a little cleaner in my opinion.
Here's a short example:
#Persistent
done := false
SetTimer, CheckPopups, 1000 ; Check every second for window
return
CheckPopups:
if ( WinActive("Volume Spike - Down") ) and (!done) {
msgBox, Hello
done := true
} else {
done := false
}
return

Use of application name with space(s) with WinExist

So I wanted to check if certain application exists or not.
If it does and there was no input within 4.5 min, switch to that app and perform some task.
Basically an AFK cheater.
This is what I have so far:
#SingleInstance force
#Persistent
settimer, idleCheck, 1000; check every second
return
idleCheck:
if WinExist(App Name with Spaces); if app is running
{
if(A_TimeIdle >= 270000); and there was no input in 4.5 min
{
WinActivate; switch to that app
sendInput z; and perform an action
}
}
return
Now obviously that doesn't work since I'd not be posting here otherwise.
The question is very simple yet I couldn't find an answer.
Thanks in Advance.
WinExist is a function and function parameters are expressions...
In expressions you need to use double quotes " around strings and you don't need % around variables
you also need to have a space before the semicolon to use comments
#SingleInstance force
#Persistent
settimer, idleCheck, 1000 ; check every second
return
idleCheck:
if WinExist("App Name with or without Spaces") ; if app is running
{
if(A_TimeIdle >= 270000) ; and there was no input in 4.5 min
{
WinActivate ; switch to that app
sendInput z ; and perform an action
}
}
return
Hope it helps

Using GetKeyState() and loops

I'm trying to write a script that has a loop in which the upper arrow key is pressed every two seconds. The loop must be activated when I press the spacebar and deactivated when I press it again. I'm now using this.
$Space::
if GetKeyState("Space", "P")
{
Loop
{
Sleep 2000
Send {Up}
if GetKeyState("Space", "P")
{
return
}
}
}
For some reason, the if condition inside the loop doesn't work, i.e. I can't get out of the loop. I hope anyone can help me out...
You wouldn't need the first if GetKeyState("Space", "P")
and you would need to be holding space when the loop got to the second one
for it to break; and you would need to replace the return with break.
However I agree with Gary, although I would write it like this:
; (on:=!on) reverses the value of variable 'on'
; the first press of space reverses on's value (nothing) to something (1)
; the second press reverses on's value from (1) to (0)
; when (on = 1) delay will be set to 2000, and Off when (on = 0)
space::SetTimer, Action, % (on:=!on) ? ("2000") : ("Off")
Action:
Send, {up}
Return
% starts an expression.
From http://l.autohotkey.net/docs/Variables.htm
?:
Ternary operator
This operator is a shorthand replacement for the if-else statement.
It evaluates the condition on its left side to determine
which of its two branches will become the final result.
For example, var := x>y ? 2 : 3 stores 2 in Var if x is greater than y; otherwise it stores 3.
How about using SetTimer?
; Create timer.
SetTimer, SendUp, 2000
; Set timer to 'Off' at start of script.
SetTimer, SendUp, Off
TimerEnabled := False
; When Space is pressed toggle the state of the timer.
$Space::
If TimerEnabled
{
SetTimer, SendUp, Off
TimerEnabled := False
}
Else
{
SetTimer, SendUp, On
TimerEnabled := True
}
; Label called by timer to send {Up} key.
SendUp:
Send, {Up}
return