Questions regarding two settimer loops

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
kalitva
Posts: 4
Joined: 03 Jul 2022, 03:59

Questions regarding two settimer loops

Post by kalitva » 03 Jul 2022, 04:16

I want two loops to run parallel to each other. Read that settimer is the best way to do it but i encountered some problems.

First problem: When releasing the Lbutton, it takes around 3 seconds until its being registered as pressed. So only then i can run the two loops again. I suspect the second set timer loop to trigger a global cooldown of sorts. I only want the "cooldown" to apply to the second loop while the first loop is fired as soon as i press the lbutton again.

Second problem: The second loop doesnt remember where it has been left off and restarts as soon as I release the Lbutton. I want it to remember that it has, for example, pressed button 2 so it can than press button 3 etc. I tried cycle, but cycle seem to not be able to be held down, so i need physically press the lbutton for it to cycle through the keys.

Third problem: The loop randomly stops after some presses. Sometimes, but it still happens.

PS: I frankensteined this together and as such, have little to no understanding anythign concerning the scripting itself, so clear examples (of the code i posted preferably) would be appretiated.

Heres the code:

Code: Select all

#SingleInstance Force
Suspend, on

mbutton::
Suspend
ToolTip % A_IsSuspended ? "XXX" : "OOO", 1400, 100
return

; This puts a 30ms pause between each character when using SendEvent
SetKeyDelay, 30
; End of AES
Exit

; Pressing XB1 starts up everything
Lbutton::
state := 0
	; Run Shift+E one time
	GoSub, SendShift1
	; Then set a timer to run it again every 60 seconds
	SetTimer, SendShift1, 200
	; Then send the other stuff
	GoSub, SendStuff
Return



SendStuff:
	SendEvent, 2
	Sleep 3000
	if(state)
return
	SendEvent, 3
	Sleep 4000
	if(state)
return
	SendEvent, 4
	Sleep 5000
	if(state)
return
	; Check to see if XB1 is still being held
	If GetKeyState("Lbutton", "P")
		; If yes, run this sub again in 50ms
		SetTimer, % A_ThisLabel, -50
		GoSub, SendShift1
Return

; Shift+e gets its own subroutine so we can keep it on a 1 min loop
SendShift1:
	SendEvent, +1
Return

Lbutton Up:: 
SetTimer, SendStuff, off
SetTimer, SendShift1, Off
state := 1
return

WheelUp::
send q
WheelDown: 
send q

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

Re: Questions regarding two settimer loops

Post by mikeyww » 03 Jul 2022, 05:12

Welcome to this AutoHotkey forum!

I did not test this, but learning about blocks may help you here, as indentation (usually) looks good but has no effect on the way the script works. Example

You might want to shorten & simplify your script, so that you can get a small piece of it working first. Adding to it with incremental, iterative testing can then make for a smoother development process. I also recommend that you provide a clear, detailed goal statement indicating what the final script should do.

kalitva
Posts: 4
Joined: 03 Jul 2022, 03:59

Re: Questions regarding two settimer loops

Post by kalitva » 03 Jul 2022, 06:39

mikeyww wrote:
03 Jul 2022, 05:12
Welcome to this AutoHotkey forum!

I did not test this, but learning about blocks may help you here, as indentation (usually) looks good but has no effect on the way the script works. Example

You might want to shorten & simplify your script, so that you can get a small piece of it working first. Adding to it with incremental, iterative testing can then make for a smoother development process. I also recommend that you provide a clear, detailed goal statement indicating what the final script should do.
Thank you for your response. Sorry but i dont quite understand how it will help me with the issues. Can you maybe show me how the code should look at the end and explain what it fixes?

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

Re: Questions regarding two settimer loops

Post by mikeyww » 03 Jul 2022, 07:19

I'm not sure whether this was one intent.

Code: Select all

If GetKeyState("LButton", "P") {
 SetTimer, % A_ThisLabel, -50
 GoSub, SendShift1
}
Regarding whether it fixes anything: if you run the revised script, you will find the answer. I did not try it.

Since you provided no description of what your script should do, I do not have a way to help further. Follow your script line by line, to see what it does. Shorten, simplify, test iteratively. You can add lines that display values of your variables, conditional statements, & functions. Best wishes for success!

kalitva
Posts: 4
Joined: 03 Jul 2022, 03:59

Re: Questions regarding two settimer loops

Post by kalitva » 03 Jul 2022, 07:31

mikeyww wrote:
03 Jul 2022, 07:19
I'm not sure whether this was one intent.

Code: Select all

If GetKeyState("LButton", "P") {
 SetTimer, % A_ThisLabel, -50
 GoSub, SendShift1
}
Regarding whether it fixes anything: if you run the revised script, you will find the answer. I did not try it.

Since you provided no description of what your script should do, I do not have a way to help further. Follow your script line by line, to see what it does. Shorten, simplify, test iteratively. You can add lines that display values of your variables, conditional statements, & functions. Best wishes for success!
Thank you for your response. I removed that line you mentioned earlier (someone else told me the same) but it didnt really fix any of my issues unfortunately. To clarify what i want my script to do/what it does:
It holds shift and 1. And also cycles through the buttons 2-5 in a loop on set timers. For example shift and 1 is spammed every 200 miliseconds while the second loop cycles through the buttons 2-5 every 2-4 seconds. It has some problems and isnt finished so i hope someone can help me with the 3 problems i have with it. Thanks for your help

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

Re: Questions regarding two settimer loops

Post by mikeyww » 03 Jul 2022, 07:36

In your script, the auto-execute section actually ends before the first hotkey. Unlabeled code following Return is unreachable and will never execute. You can prove it simply and quickly.

Code: Select all

Suspend, On

MButton::
Suspend
ToolTip % A_IsSuspended ? "XXX" : "OOO", 1400, 100
Return

MsgBox, TEST
SetKeyDelay, 30
Exit
What do you believe will happen when you run this script?

Thus, perhaps you get this idea about starting with a shorter script that works, and building & retesting from there.

Explained: Auto-execute
After the script has been loaded, it begins executing at the top line, continuing until a Return, Exit, hotkey/hotstring label, or the physical end of the script is encountered (whichever comes first).
My point is that in a script with various different bugs, it could be time to take a step back, fix things, and have a second look at everything.

kalitva
Posts: 4
Joined: 03 Jul 2022, 03:59

Re: Questions regarding two settimer loops

Post by kalitva » 03 Jul 2022, 08:11

mikeyww wrote:
03 Jul 2022, 07:36
In your script, the auto-execute section actually ends before the first hotkey. Unlabeled code following Return is unreachable and will never execute. You can prove it simply and quickly.

Code: Select all

Suspend, On

MButton::
Suspend
ToolTip % A_IsSuspended ? "XXX" : "OOO", 1400, 100
Return

MsgBox, TEST
SetKeyDelay, 30
Exit
What do you believe will happen when you run this script?

Thus, perhaps you get this idea about starting with a shorter script that works, and building & retesting from there.

Explained: Auto-execute
After the script has been loaded, it begins executing at the top line, continuing until a Return, Exit, hotkey/hotstring label, or the physical end of the script is encountered (whichever comes first).
My point is that in a script with various different bugs, it could be time to take a step back, fix things, and have a second look at everything.
Mustve been a leftover. Anyway, removing it didnt do anything. Code behaves the same as before. Thanks

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

Re: Questions regarding two settimer loops

Post by mikeyww » 03 Jul 2022, 09:03

Code: Select all

SetKeyDelay, 30
time := [400, 500, 600, 700] ; Millisecond delays

LButton::
SoundBeep, 1500
SetTimer, SendShift1, 200
GoSub, SendShift1
While GetKeyState("LButton", "P") {
 Send % 1 + ++index := Mod(0 index, time.Count())
 Loop, % time[index] / 100
  Sleep, 100 * GetKeyState("LButton", "P")
}
Return

LButton Up::
SetTimer, SendShift1, Off
SoundBeep, 1000
Return

SendShift1:
Send +1
Return
It holds shift and 1. And also cycles through the buttons 2-5 in a loop on set timers.
The script does not hold; it presses. The cycle is not a timer, but a loop (Loop command is not a timer).

Explanation: although a hotkey can typically interrupt another hotkey, the original hotkey routine will resume afterwards. When that happens, if the same hotkey is pressed again before the routine finishes, it will not trigger its own routine again, by default.
For example, if a hotkey has a max of 1 [thread per hotkey] and it is pressed again while its subroutine is already running, the press will be ignored.
If the sleep in that routine is long, it increases the chance that this will happen. This is why the sleep is divided in the script that I posted.

Alternative:

Code: Select all

SetKeyDelay, 30

LButton::
SetTimer, SendShift1, 200
SoundBeep, 1500
GoSub, SendShift1
While GetKeyState("LButton", "P") {
 Send % 1 + ++index := Mod(0 index, 4)
 Loop, % [400, 500, 600, 700][index] / 100
  Sleep, 100 * GetKeyState("LButton", "P")
}
SetTimer, SendShift1, Off
SoundBeep, 1000
Return

SendShift1:
Send +1
Return

Post Reply

Return to “Ask for Help (v1)”