hotkeys does not work when send is in loop - autohotkey

Assume this code:
Loop
{
if enabled
Send, /
}
m::
enabled := !enabled
Return
I want to toggle sending / to a Notepad for example. But if I run this code by pressing M on keyboard, then pressing the M key again does not disable sending.
Looks like the send command in the Loop cause this issue since Ive tried using msgbox which does not disable the m key.
How can I make this code to work? (SendInput and Play does not work too)

It's because your loop is blocking any other execution. Unless that loop is the only thing in your script, you generally want to avoid using loops and use timers instead.
Timers don't block further execution but act more like their own thread. Here's an example using a timer:
slashTimerActive := 0
m::
if (!slashTimerActive)
SetTimer, SendSlash, 100 ; Call the sub every 100ms
else
SetTimer, SendSlash, Off
slashTimerActive := !slashTimerActive ; Flip the variable
return
; Subroutine
SendSlash:
SendInput, /
return

Related

How to get ExitApp to take effect immediately in AHK?

If I run the following code, if I hit the ^+q it does not stop entering the numbers 1-100. Only after it completes does the script exit. Is there a way to get the script to stop even if it is in the middle of sending keystrokes?
^j::
ArrayCount := 100
Loop % ArrayCount
{
Send, %A_index%
}
return
^+q::ExitApp ; Exit script with Escape key
There are 2 issues with your code.
Sendreleases modifier keys when it simulates input, using it in a loop this way is going to interfere with autohotkey's hotkey detection. You can still activate ^+q if you press the 3 buttons simultaneously but it's much easier to use a hotkey without modifiers for example the Escape key. This is also what your comment says you're doing
^+q::ExitApp ; Exit script with Escape key
so as a bonus it will fix the discrepancy between your comment and your code ;).
The second problem is that the loop in which you execute the Send command is going to finish very quickly if you use SendInput and by the time ExitApp is executed all the numbers were already sent(even if you don't yet see the effect). In case of SendEvent there is some other problem which prevents other threads from being executed when you do it in a loop(don't know what causes it, might be a bug).
To solve it you need to add Sleep. At my system doing Sleep 1 works well. You can experiment with different numbers and send modes until you get the desired effect(you can also try 0 and -1.
Full code:
^j::
ArrayCount := 100
Loop % ArrayCount
{
Send %A_index%
Sleep 1 ; experiment with how long to sleep
}
return
Escape::ExitApp ; Exit script with Escape key

How to repeat an ongoing script if the same input is given in autohotkey

i use this code to send more mouse wheel scrolls using one notch, the problem is when an input is sent again before the loop is finished, it is not taken in account and the loop needs to end before relaunching
I tried looking for a way to break up the code if there is an input and relaunch it with no success
WheelUp::
loop 100
{
sendInput {WheelUp}
sleep 2
}
return
Expected behavior: on the 50th loop, if input is given again, reset the loop count (stop and relaunch the script) so the total repetitions would be 150
Try this approach.
You have to change the #MaxThreadsPerHotkey setting.
This setting is used to control how many "instances" of a given hotkey
or hotstring subroutine are allowed to exist simultaneously. For
example, if a hotkey has a max of 1 and it is pressed again while its
subroutine is already running, the press will be ignored.
That will allow the hotkey to "interupt" itself.
Each time you scroll up while the hotkey is already active it will add another 100 scrolls to the loop.
#MaxThreadsPerHotkey 2
WheelUp::
if (counter > 0) ; this means the hotkey is already active
{
counter := counter + 100 ; in that case we just add another 100 scrolls to the loop
return
}
else ; this means the hotkey is not active, we start fresh with 100 scrolls
{
counter := 100
}
while, counter > 0
{
sendinput, {WheelUp}
sleep 40 ; change this to your requirement
counter--
; tooltip, % counter ; un-comment this line for testing
}
return
~WheelDown::counter := 0 ; extra hotkey to stop the loop immediately if needed
I cannot respond to the other comment but WheelUp::Send, {WheelUp 100} won't break the current 100 Wheelups and will add another 100 WheelUps. So if the input was given again on the 50th WheelUp, it would still send 200 WheelUps.
In the loop you will need a conditional statement to detect if a physical scroll up was detected recently, and then restart the loop if it does. For most keys you would use GetKeyState as the check in the if statement, however the mouse wheel has no state to detect.
In my example code, the Enter button will restart the loop. I'm not sure how to restart the loop if trying to use WheelUp again since there is no state to detect, and A_TimeSincePriorHotkey is not reliable because the loop is sending WheelUps.
WheelUp::
loop 100
{
sendInput {WheelUp}
sleep 2
if (GetKeyState("Enter", "P"))
Goto WheelUp
}
return

Using AutoHotKey to temporarily disable stuck modifier keys

I want to temporarily disable all modifier keys if it seems like one or more of them has become 'stuck' - basically, I need the opposite of Windows' StickyKeys.
I'm working with a Windows tablet (ie. no physical keyboard) with a faulty input device, and it sometimes just jams a bunch of modifier keys, with no predictable trigger. Until I have time to actually troubleshoot the (potentially hardware-level) bug, this script will be a stopgap.
I just need a few seconds to sleep and unsleep the system, since that usually smacks input back into order - unfortunately, the stuck modifier keys interfere with the machine's normal sleep button behavior.
I'm trying to work with the ctrl key first, just to get the concept working, then test for the other modifiers later.
TimerVar := 0
CtrlIsStuck := False
Loop {
CtrlKeyPhysicallyDown := GetKeyState("Ctrl", "P")
If CtrlKeyPhysicallyDown
TimerVar++
Else
TimerVar := 0
If TimerVar > 1 ; TODO: make sane before deploy
{
CtrlIsStuck := True
Break
}
Sleep, 500 ; TODO: make sane before deploy
}
#If CtrlIsStuck
ToolTip, Stuck keys detected; jamming for 15 seconds. Use Sleep button now.
SetTimer, DoReload, 15100
Hotkey, Ctrl, DoNothing
Send, {Ctrl Up}
Sleep 15000
DoReload:
Reload
DoNothing:
Return
I expect this to check in a loop to see if the ctrl key has been held for a span of time, and if it has, bind ctrl to something that does nothing, claim ctrl has been physically released, then wait for a bit.
The 'check if it's held' logic is working, but once it gets past that #If line, things start behaving in a way that, after reading the manual for a while, I still don't understand. While it definitely runs, the Hotkey statement doesn't seem to do anything useful, and the SetTimer line effectively behaves redundantly; I suspect I'm missing something obvious about AutoHotKey's script flow, but I'm unsure what.

Simple keypress script with loop in Autohotkey

Whenever you press w you get into a loop that press e around every 10 seconds. Another button has to be pressed to get out of it again at any moment (and making it possible to start over again). This is what I have so far:
w::
Loop
{
Send, e
Random, SleepAmount, 9000, 10000
Sleep, %SleepAmount%
x::Break
}
Return
I don't understand why it is not working yet. It presses e once and doesn't do anything anymore after that.
x::Break
is the short form for
x::
break
return
and therefore terminates the current subroutine. Never define a hotkey within any other execution bodies. Instead, define the x-hotkey outside the w hotkey and make it stop the loop.
Example using goTo (note that goSub is different for the latter will not terminate the subroutine):
w::
Loop {
send e
Random, SleepAmount, 9000, 10000
Sleep, %SleepAmount%
}
after_loop:
return
x::
goTo after_loop
return
; or, more compact:
; x::goto after_loop
Since gotos are pretty bad programming style, you might consider using a timer (instead of the loop). But to be honest, it's not worth it because your sleep amount is not fix.

Need help trying to create a simple script

So I have no idea what I'm really doing, but I need help with a very simple script.
The basic idea is to press a key, such as k, four times each second, repeating until the script is turned off with a command (Alt-x).
I'm using Autohotkey script editor.
You can use Timers.
Example code:
F1:: ;key that launches this code
SetTimer, SendKeyK,250 ;set timer to repeat every 250 miliseconds
return ;end
F2::
SetTimer, SendKeyK,Off ;turn of the timer
return
SendKeyK:
Send, {k} ;timer sends (presses) the key k
return
As you can see there is no need to exit the script.