Just found and fixed a bug. I have other scripts that activate Caps Lock for certain events. For whatever reason, when Caps Lock is activated by another script, this script breaks a bit. Simply pressing Caps Lock once doesn't change the Caps Lock state. I have to double-tap Caps Lock once to "enable" it via this script, then press it again to disable it. I honestly don't know why this happens, but I've found a solution, by changing the KeyPressed() method like so:
Code: Select all
KeyPressed(){
if (A_TimeSincePriorHotkey == -1 || A_TimeSincePriorHotkey > this.Timeout){
this.SetLockState(this.Preference)
return
}
this.SetLockState(!this.Preference)
}
It just explicitly sets the preferred state if it timed-out, and sets the non-preferred state otherwise. That type of logic just seems more robust to me, it's also slightly less complicated to read IMO. Something about blindly toggling the state if the condition wasn't met was allowing it to break in this one particular edge-case, although I still don't fully understand why.
So the full script is:
Code: Select all
#SingleInstance force
cm := new LockManager("CapsLock", 200, 0) ; Manage CapsLock - Timeout of 200, default to Off
nm := new LockManager("NumLock", 200, 1) ; Manage NumLock - Timeout of 200, default to On
sm := new LockManager("ScrollLock", 200, 0) ; Manage ScrollLock - Timeout of 200, default to Off
class LockManager {
static TypeMappings := {CapsLock: 1, NumLock: 2, ScrollLock: 3}
static StateWords := {0: "Off", 1: "On"}
__New(keyname, timeout, preference := 0){
if (!ObjHasKey(this.TypeMappings, keyname)){
return 0
}
this.KeyName := keyname
this.Timeout := timeout
this.Preference := preference
this.Type := this.TypeMappings[this.KeyName]
this.LockState := this.GetLockState()
if (this.LockState != this.Preference){
this.SetLockState(this.Preference)
}
fn := this.KeyPressed.Bind(this)
hotkey, % "*" this.KeyName, % fn
}
GetLockState(){
return GetKeyState(this.KeyName, "T")
}
SetLockState(state){
if (this.Type == 1){
SetCapsLockState, % this.StateWords[state]
} else if (this.Type == 2){
SetNumLockState, % this.StateWords[state]
} else if (this.Type == 3){
SetScrollLockState, % this.StateWords[state]
} else {
return 0
}
this.LockState := state
}
KeyPressed(){
if (A_TimeSincePriorHotkey == -1 || A_TimeSincePriorHotkey > this.Timeout){
this.SetLockState(this.Preference)
return
}
this.SetLockState(!this.Preference)
}
}
Another thing about this code that I've just noticed: with my first script, if I mashed a lock button it would keep toggling, but with this script button-mashing makes the lock stay in the non-preferred position. That way if the computer isn't behaving itself and I get angry I can just mash the button to MAKE IT DO THE THING NOW. Something about that appeals to the caveman in me.