Terminating a Loop Immediately

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Alexander2
Posts: 348
Joined: 27 Apr 2019, 17:38

Terminating a Loop Immediately

Post by Alexander2 » 04 Aug 2021, 10:11

I would like to know whether it is possible to break a loop with a hotkey immediately. For example, is it possible to terminate the execution of the following loop with a hotkey immediately, not waiting until all the Sleep commands have finished running?

Code: Select all

loop 10
{
soundbeep 1000
Sleep 1000
sounbeep 1000
Sleep 1000
}

User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: Terminating a Loop Immediately

Post by mikeyww » 04 Aug 2021, 10:21

You could add conditional statements that check a variable that the hotkey sets. Another option is Reload.

Ideas:

https://www.autohotkey.com/boards/viewtopic.php?f=76&t=82813

https://www.autohotkey.com/boards/viewtopic.php?p=250076#p250076

Alexander2
Posts: 348
Joined: 27 Apr 2019, 17:38

Re: Terminating a Loop Immediately

Post by Alexander2 » 06 Aug 2021, 13:11

mikeyww wrote:
04 Aug 2021, 10:21
You could add conditional statements that check a variable that the hotkey sets. Another option is Reload.

Ideas:

https://www.autohotkey.com/boards/viewtopic.php?f=76&t=82813

https://www.autohotkey.com/boards/viewtopic.php?p=250076#p250076
Thank you. From what is stated in the threads, it seems that there is no standard method to terminate the execution of a loop in a simple way with a hotkey. An If command has to be used inside the loop to check a certain condition all the time.

User avatar
mikeyww
Posts: 26601
Joined: 09 Sep 2014, 18:38

Re: Terminating a Loop Immediately

Post by mikeyww » 06 Aug 2021, 13:23

Aside from Reload, that is generally true in AHK version 1.x. Version 2 might give you additional options.

WatsonEnterprises
Posts: 19
Joined: 25 May 2020, 23:04

Re: Terminating a Loop Immediately

Post by WatsonEnterprises » 07 Aug 2021, 03:12

Here's something funny.

Code: Select all

F1::LoopUntilHotkeyIsPressed("LoopBody_Test", "F2", maxLoops:=4)

LoopBody_Test(){
	SoundBeep, 500
	sleep 100
	SoundBeep, 800
	sleep 500
}




LoopUntilHotkeyIsPressed(loopBody, terminationKey, maxLoopCount:=""){
	loop := new HotkeyTerminatedLoop(loopBody, terminationKey, maxLoopCount)
	loop.Start()
}
class HotkeyTerminatedLoop{
	__New(loopBody, terminationKey, maxLoopCount:=""){
		this.loopBody := IsObject(loopBody) ? loopBody : Func(loopBody)
		this.terminationKey := terminationKey
		this.maxLoopCount := maxLoopCount
		
		if (!IsObject(this.loopBody))
			msgbox % "Error: Invalid func was passed for loop body"
	}
	
	Start(){
		this.isBroken := false
		this.ToggleBreakHotkey("on")
		
		Loop {
			if (this.isBroken   ||   (this.maxLoopCount  &&  A_Index > this.maxLoopCount))
				break
			this.loopBody.Call()
		}
		
		this.ToggleBreakHotkey("off")
	}
	Break(){
		this.isBroken := true
	}
	
	ToggleBreakHotkey(mode:="on"){
		fnLoopBreaker := ObjBindMethod(this, "Break")
		Hotkey, % this.terminationKey, % fnLoopBreaker, % mode
	}
}
Pass your loop body as a function, and it'll check the termination condition before each iteration of it.

If you want to terminate halfway into an iteration (like you mention in the OP), then mikey's suggestion of Reload/ExitApp seems like your best option aside from putting an if statement after every line. If you don't want to reload your whole script, you could run your loop separately as a second smaller script.

Alexander2
Posts: 348
Joined: 27 Apr 2019, 17:38

Re: Terminating a Loop Immediately

Post by Alexander2 » 08 Aug 2021, 14:14

WatsonEnterprises wrote:
07 Aug 2021, 03:12
Here's something funny.

Code: Select all

F1::LoopUntilHotkeyIsPressed("LoopBody_Test", "F2", maxLoops:=4)

LoopBody_Test(){
	SoundBeep, 500
	sleep 100
	SoundBeep, 800
	sleep 500
}




LoopUntilHotkeyIsPressed(loopBody, terminationKey, maxLoopCount:=""){
	loop := new HotkeyTerminatedLoop(loopBody, terminationKey, maxLoopCount)
	loop.Start()
}
class HotkeyTerminatedLoop{
	__New(loopBody, terminationKey, maxLoopCount:=""){
		this.loopBody := IsObject(loopBody) ? loopBody : Func(loopBody)
		this.terminationKey := terminationKey
		this.maxLoopCount := maxLoopCount
		
		if (!IsObject(this.loopBody))
			msgbox % "Error: Invalid func was passed for loop body"
	}
	
	Start(){
		this.isBroken := false
		this.ToggleBreakHotkey("on")
		
		Loop {
			if (this.isBroken   ||   (this.maxLoopCount  &&  A_Index > this.maxLoopCount))
				break
			this.loopBody.Call()
		}
		
		this.ToggleBreakHotkey("off")
	}
	Break(){
		this.isBroken := true
	}
	
	ToggleBreakHotkey(mode:="on"){
		fnLoopBreaker := ObjBindMethod(this, "Break")
		Hotkey, % this.terminationKey, % fnLoopBreaker, % mode
	}
}
Pass your loop body as a function, and it'll check the termination condition before each iteration of it.

If you want to terminate halfway into an iteration (like you mention in the OP), then mikey's suggestion of Reload/ExitApp seems like your best option aside from putting an if statement after every line. If you don't want to reload your whole script, you could run your loop separately as a second smaller script.
Yes, I can see that there seems to be no easy way to terminate a loop without having to write much code or to reload the entire script. The variables in the script will be reset if the script is reloaded. So adding IF statements within the loop may be the only option which involves few lines of code.

Post Reply

Return to “Ask for Help (v1)”