Is there a prettier way to call SetTimer? Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
Awesome Quest
Posts: 7
Joined: 18 Jun 2020, 17:16

Is there a prettier way to call SetTimer?

Post by Awesome Quest » 18 Jan 2022, 09:04

I'm using this to do a comfortable alt tab with my mouse and need alt to be released after a given time.

Code: Select all

altUpFun(){
	Send("{Alt Up}")
}
~F13::{
	Send("{Alt down}{Tab}")
	SetTimer altUpFun, -1000
}
~F14::{
	Send("{Alt down}{Shift down}{Tab}{Shift up}")
	SetTimer altUpFun, -1000
}
This works perfectly but I'm wondering if there is a better way of using SetTimer than to declare what seems to me an unnecessary function.
Can't I call Send from within the SetTimer? I feel like that would make this less spaghetti.

[Mod edit: Topic moved to AHK v2 help.]

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

Re: Is there a prettier way to call SetTimer?

Post by mikeyww » 18 Jan 2022, 10:41

In v1, I don't think so. You could have a look at the v2 forum.

SetTimer:
Causes a function to be called automatically and repeatedly at a specified time interval.
Sleep may be an option depending on what you need.

User avatar
boiler
Posts: 16903
Joined: 21 Dec 2014, 02:44

Re: Is there a prettier way to call SetTimer?

Post by boiler » 18 Jan 2022, 10:46

Was just making a version with Sleep (v2 code):

Code: Select all

~F13::SendWait("{Alt down}{Tab}", "{Alt Up}")

~F14::SendWait("{Alt down}{Shift down}{Tab}", "{Shift up}{Alt up}")

SendWait(str1, str2, dur:=1000) {
	Send str1
	Sleep dur
	Send str2
}
(Note: Your version of the code didn't release Alt in the F14 routine.)


You may be able to use SetTimer with ObjBindMethod, but it doesn't seem necessary here.
Last edited by boiler on 18 Jan 2022, 10:52, edited 1 time in total.

swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Is there a prettier way to call SetTimer?  Topic is solved

Post by swagfag » 18 Jan 2022, 10:51

u can pass it an anonymous fat-arrow function () => Send('abc')

Rohwedder
Posts: 7616
Joined: 04 Jun 2014, 08:33
Location: Germany

Re: Is there a prettier way to call SetTimer?

Post by Rohwedder » 18 Jan 2022, 11:39

Hallo,
or a version with Timer (v1 code):

Code: Select all

~F1::SendWait("{Alt down}{Tab}", "{Alt Up}")
~F2::SendWait("{Alt down}{Shift down}{Tab}", "{Shift up}{Alt up}")

SendWait(str1:="", str2:="", dur:=1000) {
	Send,% str1, Timer := Func("WaitSend").Bind(str2)
	SetTimer,% Timer,% -Max(Abs(dur),1)
}
WaitSend(str2) {
	Send,% str2
}

Awesome Quest
Posts: 7
Joined: 18 Jun 2020, 17:16

Re: Is there a prettier way to call SetTimer?

Post by Awesome Quest » 19 Jan 2022, 06:41

swagfag wrote:
18 Jan 2022, 10:51
u can pass it an anonymous fat-arrow function () => Send('abc')
Thanks, I didn't know AHK had that syntax. But it does something weird, if I try to F13 then F14 to go back and forth, the "switching window" disappears mid switching, this does not happen when calling the regular function. I think this has to do with how setTimer handle's multiple timers, and since the two functions don't have the same memory the new timer doesn't cull the old timer.

This might be a stupid question, but can you get two anonymous functions to share memory without declaring the function?

lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: Is there a prettier way to call SetTimer?

Post by lexikos » 21 Jun 2022, 06:04

Awesome Quest wrote:
19 Jan 2022, 06:41
I think this has to do with how setTimer handle's multiple timers, and since the two functions don't have the same memory the new timer doesn't cull the old timer.
That is correct. To reset a previously set timer, you must pass SetTimer the same function. In your case, that means using one function for both timers.
This might be a stupid question, but can you get two anonymous functions to share memory without declaring the function?
You don't. If they occupied the same exact location in memory, it would literally be one function.

Your original definition creates a global constant "altUpFun" which contains a reference to a function. Since Send has no return value (and the return value doesn't matter), it is equivalent to write altUpFun() => Send("{Alt Up}"). If you wrote altUpFun := () => Send("{Alt Up}"), it would almost be the same, except that altUpFun is truly variable (you can assign to it) and the function is anonymous (altUpFun.Name is ""). altUpFun := Send.Bind("{Alt Up}") would give a similar result. While technically you get an anonymous function that you can pass to both SetTimer calls, there isn't any point in it being anonymous.

Of course, you can also pass Send.Bind("{Alt up}") directly to SetTimer, with the same problem as before because each call will create a new timer.

If you want to "make this less spaghetti", consider the overall pattern and the parts you are repeating:
  • Define a hotkey.
  • Send Alt down.
  • Send some keys that vary.
  • Set a timer to release Alt.
Then make a function that does that. The end result could look like:

Code: Select all

AltTabHotkey "~F13", "{Tab}"
AltTabHotkey "~F14", "{Shift down}{Tab}{Shift up}"
or

Code: Select all

~F13::SendAlt "{Tab}"
~F14::SendAlt "{Shift down}{Tab}{Shift up}"
With the rest done by the function (I'll leave that part for you to figure out).

Alternatively, instead of defining a function that just releases Alt, you can define a function that sets the timer:

Code: Select all

SendAltUpAfter1s() => SetTimer(() => Send("{Alt up}"), -1000)
There is only one anonymous function, so the timer is reset each time the function is called.


Depending on how you're producing F13/F14 events, you might want to add * so that the hotkeys can be used even while Alt is down due to Send. Unlike *~F13, ~F13:: won't activate if Alt is down (but if F13 is produced by software, that software could temporarily release Alt).

SandyClams
Posts: 63
Joined: 02 Jul 2020, 11:55

Re: Is there a prettier way to call SetTimer?

Post by SandyClams » 21 Jun 2022, 10:30

lexikos wrote:
21 Jun 2022, 06:04
There is only one anonymous function, so the timer is reset each time the function is called.
@lexikos, are you saying that, upon defining the function SendAltUpAfter1s in which a new anonymous function is created in the return expression, future calls to SendAltUpAfter1s will continue to call the original anonymous function rather than creating a new anonymous function on every call? As if the anonymous function was static?

lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: Is there a prettier way to call SetTimer?

Post by lexikos » 21 Jun 2022, 23:42

The anonymous function is static. Only closures are non-static. (In other words, it depends on whether the nested function refers to any non-static variables of the outer function.)

User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: Is there a prettier way to call SetTimer?

Post by kczx3 » 23 Jun 2022, 08:44

That is very interesting because I completely would have though a new callback would be created each time the SendAltUpAfter1s function was called.

SandyClams
Posts: 63
Joined: 02 Jul 2020, 11:55

Re: Is there a prettier way to call SetTimer?

Post by SandyClams » 23 Jun 2022, 09:06

kczx3 wrote:
23 Jun 2022, 08:44
That is very interesting because I completely would have though a new callback would be created each time the SendAltUpAfter1s function was called.
yeah that's also why I had to clarify. I know I personally have declared long lists of static fat arrows at the top of my functions before in the interest of minimizing redundant operations, it will be nice to not do that any more

Post Reply

Return to “Ask for Help (v2)”