I post this in the gaming section because I guess gamers might be more interested in it, and the main example is a classic gaming example, a spam script, however, usage is not limited to gaming.
See github for latest version.
When to use?
When the timer callback needs to fire frequently and completes very fast, if you use any sleeps, keydelays or other wait functions in the callback, you do not need this timer.
Test result
This is the result from the speed test example, Basic usage
Usage is very simple, create a timer, call start() and stop(),
Code: Select all
#include timer.ahk
sendMode "event"
setkeydelay -1, -1
callback := func("send").bind("z")
qt := new quickTimer(callback)
f1::qt.start()
f1 up::qt.stop()
esc::exitapp
- start, start the timer.
- stop, stop the timer.
- delete, delete the timer, do not use again when deleted.
- startAll, starts all timers.
- stopAll, stops all timers.
- deleteAll, deletes all timers.
Only send keys with sendmode "sendevent" and setkeydelay -1, -1. Always include a hotkey to close the script, eg esc::exitapp.
How does it work?
While any timer is active, the class keeps a thread running which basically only does loop { sleep(-1) }, this prevents the running AutoHotkey.exe from doing its internal sleep and instead it will check its message queue, and there is no sleeping between timer messages.
Notes
This is experimental. CPU usage will be much higher. Your regular timers will also be fast while a quickTimer is active.
Self-contained example
This is a classic spam script. Hotkeys a and b sends a and b using quickTimer. Hotkey c and d sends c and d using regular timers. esc exits the script.
Code: Select all
; Classic "spam" example.
SendMode "Event" ; Do not change this.
SetKeyDelay -1, -1
aTimer := new quickTimer( () => send("a") )
bTimer := new quickTimer( () => send("b") )
a::aTimer.start()
b::bTimer.start()
a up::aTimer.stop()
b up::bTimer.stop()
c::
if cIsOn
return
cIsOn := true
setTimer c() => send("c"), 0
return
d::
if dIsOn
return
dIsOn := true
setTimer d() => send("d"), 0
return
c up::
settimer "c", "off"
cIsOn := false
return
d up::
settimer "d", "off"
dIsOn := false
return
esc::exitapp
class quickTimer {
; User methods
__new(callback, priority:=0){
this.callback := callback
this.priority := priority
quickTimer.timers[this] := "" ; store the instance for xxxAll() methods
}
; Timer states:
; 1 - running
; 0 - stopped
; -1 - deleted (or never started)
state := -1
start(){
if this.state == 1
return
setTimer(this.callback, 0, this.priority)
this.state := 1
local pte := quickTimer.enabled++
if !pte
quickTimer.toggleQT()
return this
}
stop(){
if this.state != 1
return
this.state := 0
quickTimer.enabled--
setTimer(this.callback, "off")
}
delete(){
if this.state == 1
this.stop()
this.state := -1
setTimer(this.callback, "delete")
quickTimer.timers.delete this
this.base := "" ; will throw error on further use.
}
startAll(){
this.loopTimers(quickTimer.start)
}
stopAll(){
this.loopTimers(quickTimer.stop)
}
deleteAll(){
this.loopTimers(quickTimer.delete)
}
; Interal methods
static timers := []
loopTimers(fn){
local
global quickTimer
for timer in quickTimer.timers
fn.call(timer)
}
static enabled := 0
toggleQT(){
static tfn := quickTimer.quickFn.bind(quickTimer)
setTimer(tfn, "-0")
}
static speed := -1 ; fastest. Set to -1 for fastest, 0 for fast or 1+ for 'quite' slow
quickFn(){
static dllsleep := func("dllcall").bind("Sleep", "uint")
critical false
while this.enabled
(this.speed == -1) ? "" : dllsleep.call(this.speed), sleep(-1)
}
}