How to interrupt a loop with a hotkey - loops

This should be easy! I've checked out this thread, but it doesn't help.
I can't seem to break out of the loop using the hotkey. The idea is that you can start and stop the looping process with a single hotkey.
It seems like the value of timeron never gets into the the loop once it's begun.
Here is a sample script:
#singleinstance force
timeron = 0
return
!f7::
if(timeron){
timeron = 0
msgbox Okay, the loop is off.
}else{
timeron = 1 ;if this is not set to one, the loop will not begin
msgbox Turning on the loop.
gosub, STARTLOOPING
}
RETURN
STARTLOOPING:
;do this over and over
loop{
if(!timeron)
break
;now wait for the right length of time before continuing the loop
msgbox, The loop yet continues....
Sleep, 5000
if(!timeron)
break
}
RETURN
What am I missing here?

Since your !F7 never ends, a second press of !F7 is ignored.
Per default there is only one thread for each hotkey allowed at one time.
Add
#MaxThreadsPerHotkey 2
as a second line to your script then the second !F7 press can deactivate the loop.

Why don't you use timers instead? They allow your script to do other stuff in between timer runs, thus allowing hotkeys to interrupt them:
timeron := false
Exit
!F7::
if(timeron) {
timeron := false
SetTimer, MyTimer, Off
} else {
timeron := true
; Call GoSub once if you want the subroutine
; to fire immediately at the beginning
GoSub, MyTimer
; Then let the timer repeat it
SetTimer, MyTimer, 5000
}
return
MyTimer:
Msgbox, Looping like crazy!
return
You can always replace a loop's functionality with a timer. If you have some kind of for loop/counter, you can use global variables instead.

Related

i need this continue to skip the entire while loop but it skips just the if loop (i think)

while continue_bool:
try:
name = input("Name (str): ")
if (name in used_names):
print("This name is already in use")
continue
quantity = int(input("quantity (int): "))
here is the code. i tested the continue statement and it does what i want it to do in a simple for loop. it seems here the if (x in y) creates a loop of its own that the continue just restarts. how do i make the continue restart the while loop?
Try taking the continue keyword outside the if block

_.each wait till boolean condition has been met to loop around

How can I achieve a loop like this:
foobar.each(function (model, j) {
// asynchrounous call etc. {in here bool get set to true}
// outside all asynchronous calls
// wait till bool is true, without stopping anything else except the loop to the top of
the _.each
})
I asked a similar question yesterday. But it got marked as a duplicate when it wasn't the same case. Their solution did not achieve the same thing. Also generator functions were suggested which looked like it would work. But I can't use them with ecmascript 5
I've tried busy loops and set time out but they don't seem to work either
I've also tried this:
goto();
function goto() {
if (foo === true) {
//return true; /*I've tried with and without the return because the loops
doesn't need a return*/
} else {
goto();
}
}
What happens with the goto() method is it breaks. Giving me the right results for the first iterations then execution seems to stop altogether. 'foo' always gets set to true in normal execution though.
What you could do is implement a foreach yourself, where you execute your condition, and then on success callback go to the next item (but meanwhile the rest of the code will keep running.
var iteration = 0 //count the iteration of your asynchronous process
//start looping
loop(iteration)
function loop(iteration){
var model = foobar[iteration];
//exit your loop when all iterations have finished (assuming all foobar items are not undefined)
if (foobar[iteration] === undefined){
return;
}
//do what you want
//on success callback
iteration++;
loop(iteration);
//end success callback
}

Using Loop multiple times

1. Briefly
I don't understand, how I can use cycles from Loop multiple times without ending script.
2. Settings
I have a file SashaAutoScrolling.ahk, it content:
; First loop, Speed 1
#+1::
Loop
{
Send {WheelDown}
Sleep 3000
}
; Second loop, Speed 2
#+2::
Loop
{
Send {WheelDown}
Sleep 600
}
; Third loop, Speed 3
#+3::
Loop
{
Send {WheelDown}
Sleep 100
}
; Fourth loop, Speed Up
#+0::
Loop
{
Send {WheelUp}
Sleep 600
}
; Loop pause
; http://autohotkey.com/board/topic/95308-endless-loop-with-hotkey-pause/?p=600526
#p::Pause
; Exit script
#esc::ExitApp
3. Steps to reproduce
I open any pdf file in any PDF-viewer. I switch between «speeds»:
Shift+Super+3,
Shift+Super+0,
Shift+Super+2,
Shift+Super+3,
Shift+Super+0.
4. Actual behavior
If I run Shift+Super+3 and Shift+Super+0 first time
    I can successful switch between «speeds».
If I run Shift+Super+3 and Shift+Super+0 second and next times,
    I can't switch between «speeds».
5. Expected behavior
Successful switch between «speeds» unlimited number of times.
6. Not helped
Googling, searching in Stack Overflow and AutoHotkey forum.
7. Do not offer
Please, do not offer use third-party programs. Adobe Reader free version works as expected, but I can't read, use this program , for example, djvu or doc books.
Please, do not offer use built-in mouse auto scrolling. It uncomfortable, because is problematic quick choose exact comfortable «speed» for reading.
This code scrolls current window with simulated mouse wheel scrolls
Shift+Win+1, Shift+Win+2, etc... starts scrolling. If already scrolling, just updates sleep interval. esc exits
; globals:
; g_running : true while loop is active
; g_sleep : milliseconds to sleep between sending input event
; g_key : key to simulate
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; HOTKEY DEFINITIONS
#MaxThreadsPerHotkey 2
#+1:: scrollit(3000)
#+2:: scrollit(600)
#+3:: scrollit(300)
#+0:: scrollit(600,"WheelUp")
#MaxThreadsPerHotkey 1
Esc:: abort()
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; HELPER FUNCTIONS
; send wheeldown every _delay_ microseconds
; if called while loop is already active, just update delay and exit
;
scrollit(sleep, key="WheelDown")
{
global g_running
global g_sleep := sleep
global g_key := key
if g_running
return
g_running := true
while (g_running)
{
Send {%g_key%}
Sleep g_sleep
}
}
abort()
{
global g_running := false
}
Scrolls current window by simulating mouse wheel scroll when Shift+Win+1, Shift+Win+2, etc. pressed. esc exits loop
#+1:: scrollit(3000)
#+2:: scrollit(600)
#+3:: scrollit(300)
Esc:: abort()
scrollit(delay)
{
global abort := false
while (!abort)
{
Send {WheelDown}
Sleep delay
}
}
abort()
{
global abort := true
}
Your code doesn't work because by default there is only one thread per hotkey. When you do:
Loop
{
Send {WheelDown}
Sleep 100
}
You never return from this one thread so when you call it second time the hotkey will not fire and your program will continue looping in the current thread.
Jim U solved it by calling #MaxThreadsPerHotkey 2, this wouldn't have made your code work though because you don't return from your hotkey threads at all, Jim U doesn't return from the first thread only so 2 threads is enough for his solutoin to work.
An alternative solution is to use timers, the following will change the scrolling speed immediately, doesn't need any special directives and doesn't rely on Autohotkeys unique threading model.
#+1::callSetTimer(3000)
#+2::callSetTimer(600)
#+3::callSetTimer(100)
#+0::callSetTimer(600, "WheelUp")
Esc::SetTimer, scrollTimer, Off
callSetTimer(interval, key := "WheelDown") {
global currKey := key
SetTimer, scrollTimer, %interval%
scrollTimer:
send, {%currKey%}
return
}

How to stop an infinite loop in autohotkey using the key you start it with

So i just started using autohotkey and i made this script to spam the trade chat in a game called path of exile, it works pretty well, but i cant get it to stop when i press f1 again, i've tried countles times, but the loop just won't stop
#MaxThreads 2
wintitle=Path of Exile
SetTitleMatchMode,2
DetectHiddenWindows,On
setkeydelay,2500,0
f1::
toggle:=!toggle
Loop
{
if toggle
controlsend,,{enter}{up}{enter}, %wintitle%
else
break
}
return
I think you're better off using SetTimer for this. Loops aren't very easy to work with when it comes to toggles.
i := 0
toggle := 0
F1::
toggle := !toggle
if (toggle) {
SetTimer, Timer_Spam, 10
} else {
SetTImer, Timer_Spam, Off
}
return
Timer_Spam:
TrayTip, Counter, %i%
i++
return
The reason why your loop isn't working is because once you enter the loop the program is stuck there, so to get out you need to work from inside the loop.
You can do this with GetKeyState(), but then you can't use the same key to toggle it on and off, as it'll toggle off as soon as you start it, unless you add Sleep commands in there, in which case it becomes unreliable instead.
You can however use a separate key to stop the loop, shown here.
toggle := 0
i := 0
F1::
toggle := !toggle
if (toggle) {
Loop {
if (GetKeyState("F2", "P")) {
toggle := !toggle
break
}
TrayTip, Counter, %i%
i++
}
}
return
But like I said above, SetTimer achieves the same result in a much more stable way. So I'd go with that.
use MaxThreadsPerHotkey
#MaxThreadsPerHotkey 2
wintitle=Path of Exile
SetTitleMatchMode,2
DetectHiddenWindows,On
setkeydelay,2500,0
return
f1::
toggle:=!toggle
Loop
{
if toggle
controlsend,,{enter}{up}{enter}, %wintitle%
else
break
}
return
This is the easiest approach I was able to do.
Start/stop toggle with key "2", sending "a" with 0.1 second delay.
#MaxThreadsPerHotkey 2
running := false
stop := false
~2::
if(!running) {
running := true
}
else {
stop := true
return
}
loop {
Send {a} ; example sending key "a"
if(stop) {
running := false
stop := false
break
}
Sleep, 100
}
return
My strategy is this,
Use this command:
v::
loop
{
click
if (GetKeyState("b")) {
break
}
}
return
(Its simple AutoClicker)
Working example with Loop command. Yet so simple.
#Persistent
#MaxThreadsPerHotkey 2
toggle := False
f1 UP::
toggle := !toggle
Loop {
If (!toggle) {
break
}
; Spam commands here
}
Return
This code does what you want:
#MaxThreads 2
wintitle=Path of Exile
SetTitleMatchMode,2
DetectHiddenWindows,On
setkeydelay,2500,0
return
F1::
Loop
{
CheckLButton1:
if (GetKeyState("F1"))
{
Goto, CheckLButton1
}
Docode:
controlsend,,{enter}{up}{enter}, %wintitle%
;ToolTip, 1
if (!(GetKeyState("F1")))
{
Goto, Docode
}
CheckLButton2:
if (!(GetKeyState("F1")))
{
return
}
else
{
Goto, CheckLButton2
}
}
return
If you need explanation, look here at my post: http://ahkscript.org/boards/viewtopic.php?f=5&t=4613#p26298

Swift: test for expiration / invalidation of NSTimer seems to fail

Using Swift, I'm having difficulty testing for the expiration / invalidation of an NSTimer.
In particular, why does it appear that a test like while timer1 != nil { } or while timer1?.valid { } does not escape the null loop after it has been seemingly clearly invalidated and set to nil directly.
I have reviewed several of the questions relating to NSTimer already, and unless there is a version in Obj-C that I simply am not recognizing as the same issue due to my poor comprehension of ObjC properly, I don't believe this is covered (directly).
Please note, I'm not looking to directly "fix" the code, I'm looking for comprehension.
// ViewController.swift
// NSTimerTest
import UIKit
class ViewController: UIViewController {
var z:Int = 0
var timer1:NSTimer? = nil
#IBOutlet var lblMessage: UILabel
#IBOutlet var lbl2: UILabel
#IBAction func btnPress(sender: AnyObject) {
doBtnPress()
}
override func viewDidLoad() {
super.viewDidLoad()
z = 0
lblMessage.text = "Timer was called \(z) times."
lbl2.text = "waiting for countdown"
}
func doBtnPress(){
lblMessage.text = "doBtnPress!!"
timer1 = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "doTimedAction", userInfo: nil, repeats: true)
// All of the below infinitely loop
// while timer1?.valid { } // <=== never escapes, also depreciated in IOS 8.0 ???
// while timer1 { } // <==== never escapes
// while timer1 != nil { } // <==== never escapes
// while z >= 0 { } // <==== test counter instead, but no use
lbl2.text = "timer has been invalidated"
}
func doTimedAction(){
lblMessage.text = "Timer was called \(++z) times."
if z >= 10 {
timer1?.invalidate()
timer1 = nil
z = -1
}
}
}
As you can see, I have two labels -- one that is simply updated with the number of times the NSTimer has been invoked, and the other that hold be updated after I invalidate the timer.
With the testing lines commented out as noted above, things work as I expect. The label indicating the number of timer invocations updates each second (or so) and the immediate but factually incorrect display of the statement that "Timer has been invalidated" )
However, it my expectation that de-commenting any of the three lines that follow should allow the timer to run through 10 iterations, and then be invalidated, allowing the "Timer invalidated" message to display. Instead, however, I end up stuck infinitely in the empty loop, as if the condition(s) never come true. The UI does not update at all.
Instead of testing the timer, I also tried testing the counter z, but this does not work either, leading me to believe there is something more elemental at play that I am not understanding. For example, using while z >= 0 { println("z is \(z)")} in the location results in z is 0 -- the reason the loop is infinite. But again, if I comment out the line, z does in fact clearly increment, as the label DOES change, reflecting the cane in the counter z.
Again, I'm looking more to understand WHY things are failing (i.e., what I am failing to comprehend here). I understand, for example, I could make this "work" by having the doTimedAction() func directly update the label --- but that would not help me understand why my tests fail.
Whilst you are in the loop, you are blocking the timer from firing, as both the timer and loop are on the same thread.
Check out the documentation on Run Loops, and also this post on creating an NSTimer on a background thread.

Resources