A really simple solution to accidental CapsLock/NumLock presses

Post your working scripts, libraries and tools for AHK v1.1 and older
Excrubulent
Posts: 28
Joined: 24 Jun 2014, 20:47

A really simple solution to accidental CapsLock/NumLock presses

08 Jul 2016, 02:36

EDIT: A better implementation of this idea is here in this post by evilC.

Accidentally pressing CapsLock and NumLock drives me nuts. I have to undo work, it slows me down, and half the time when I'm going fast I'll rush it and press the button again without thinking about it.

So I thought it would be great if I could double-tap the CapsLock key to enable it, and single tap to disable. That way it's really hard to accidentally turn it on, and I can know without looking whether I've just turned it on or off. I've also extended the idea to NumLock and ScrollLock, using the single press for my preferred state and double-tap for the alternative state.

Code: Select all

#SingleInstance Force

; how fast should the double tap be in milliseconds
TimeOut := 200

; CapsLock is off by default
CapsLock::

	If (A_PriorHotkey = A_ThisHotkey
			&& A_TimeSincePriorHotkey < TimeOut)
		
		SetCapsLockState on
	Else
		SetCapsLockState off

Return

; NumLock is on by default
NumLock::

	If (A_PriorHotkey = A_ThisHotkey
			&& A_TimeSincePriorHotkey < TimeOut)

		SetNumLockState off
	Else
		SetNumLockState on

Return

; ScrollLock is off by default
ScrollLock::

	If (A_PriorHotkey = A_ThisHotkey
			&& A_TimeSincePriorHotkey < TimeOut)

		SetScrollLockState on
	Else
		SetScrollLockState off

Return

My only gripe with this code is it would feel nicer to have option variables like

Code: Select all

CapsPreference := on
and then

Code: Select all

SetCapsLockState %CapsPreference%
and

Code: Select all

SetCapsLockState !%CapsPreference%
but that didn't seem to work. If it was part of a larger script that would create some maintainability issues, but for these simple purposes it's not a big deal.
Last edited by Excrubulent on 07 Feb 2017, 19:37, edited 1 time in total.
Shadowpheonix
Posts: 1259
Joined: 16 Apr 2015, 09:41

Re: A really simple solution to accidental CapsLock/NumLock presses

08 Jul 2016, 15:57

Technically, SetCapsLockState !%CapsPreference% should have been SetCapsLockState % !CapsPreference by traditional AutoHotkey standards. Unfortunately, that also does not work. However, here is a tweak to your code that accomplishes the desired result in a less elegant fashion...

Code: Select all

CapsPreference = Off  	; Sets CapsLock to be off by default
CapsLock::
	If CapsPreference = On
		NonCapsPreference = Off
	Else
		NonCapsPreference = On
	If (A_PriorHotkey = A_ThisHotkey
			&& A_TimeSincePriorHotkey < TimeOut)
 
		SetCapsLockState %NonCapsPreference%
	Else
		SetCapsLockState %CapsPreference%
Return
Excrubulent
Posts: 28
Joined: 24 Jun 2014, 20:47

Re: A really simple solution to accidental CapsLock/NumLock presses

31 Jan 2017, 20:29

Well, it's been over six months, I only just saw this reply. Thanks, although it's not such a big deal since I never really have a need to touch this script, so easy configuration isn't such an issue for me in the end. I have however created a little tweak. The new script is:

Code: Select all

#SingleInstance Force

; how fast should the double tap be in milliseconds
TimeOut := 200

; CapsLock is off by default  * modifier runs this script whether 
*CapsLock::

	If (A_PriorHotkey = A_ThisHotkey
			&& A_TimeSincePriorHotkey < TimeOut)
		
		SetCapsLockState on
	Else
		SetCapsLockState off

Return

; NumLock is on by default
*NumLock::

	If (A_PriorHotkey = A_ThisHotkey
			&& A_TimeSincePriorHotkey < TimeOut)

		SetNumLockState off
	Else
		SetNumLockState on

Return

; ScrollLock is off by default
*ScrollLock::

	If (A_PriorHotkey = A_ThisHotkey
			&& A_TimeSincePriorHotkey < TimeOut)

		SetScrollLockState on
	Else
		SetScrollLockState off

Return
The * option means the hotkeys get triggered even if modifier keys are being held. This was important because I discovered how easy it was to press Shift+CapsLock by accident, which would bypass this script and turn on CapsLock.
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: A really simple solution to accidental CapsLock/NumLock presses

01 Feb 2017, 16:35

Fun little idea.

Here is an implementation where you can easily configure it for any of the 3 locks.
You can specify timeout and "preferred" state. (Defaults to off).

When the script starts, it will set the toggle to the preferred state

Transitioning from the preferred to the non-preferred state requires a double tap
Transitioning from the non-preferred to the preferred state requires a single tap

Code: Select all

#SingleInstance force
cm := new LockManager("CapsLock", 200, 0)	; Manage CapsLock - Timeout of 200, default to Off
nm := new LockManager("NumLock", 500, 1)	; Manage NumLock - Timeout of 500, 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 (this.LockState == this.Preference && (A_TimeSincePriorHotkey == -1 || A_TimeSincePriorHotkey > this.Timeout)){
			return
		}
		this.SetLockState(!this.LockState)
	}
}
Excrubulent
Posts: 28
Joined: 24 Jun 2014, 20:47

Re: A really simple solution to accidental CapsLock/NumLock presses

05 Feb 2017, 18:47

Wow, somehow I never realised that classes were in AHK. It makes sense, of course, but I had no idea.

I do like the way it works, but ultimately I would only create a class like that if I envisioned using it over a large number of applications. As it is, I know I'm only ever going to need it for three lock keys, so I know I'm not going to run into maintainability problems just copy-pasting the same code for each instance.

All that said, now that you've gone to the trouble of implementing this, I may as well use it and see what I can learn from it. :)
4GForce
Posts: 553
Joined: 25 Jan 2017, 03:18
Contact:

Re: A really simple solution to accidental CapsLock/NumLock presses

06 Feb 2017, 00:03

evilC is 'loco', nice useful object, thank you !
DeepMind
Posts: 271
Joined: 19 Jul 2016, 14:47

Re: A really simple solution to accidental CapsLock/NumLock presses

06 Feb 2017, 07:30

evilC wrote:Fun little idea.
...
Hi, I was searching the forum to find out if it's possible to do this:

1. use SetCapsLockState, AlwaysOff at the auto-execute section alwaysoff the capslock; because I use it instead of enter in one case, and instead of tab and +tab in an combonation with alt in another case.. like this:

Code: Select all

!CapsLock::SendInput, +{Tab}
!Tab::SendInput, {Tab}
and if I don't set the state to alwaysoff, it turns the capslock light on every time I press it, and it was I guess annoying before :D
so in all other cases I use capslock and tab instead of enter and backspace

but the tweak I'm looking for right now is, I want to toggle capslock with for example ^Capslock; but I don't know if it's possible, and if so I don't know the syntax, I will show as much as I can:

Code: Select all

^Capslock::setcapslockstate, on ; then (the next time I press the hotkey I want it to toggle) always off, then on, then always off, ...
appreciate any insight :)

Edit: tried using both SetCapsLockState, AlwaysOff +CapsLock::send {capslock} ;chs35 @potential (for messing) in auto-exe section but +CapsLock::send {capslock} clearly turns the capslock on but doesn't turn it off.
Last edited by DeepMind on 06 Feb 2017, 07:40, edited 1 time in total.
DeepMind
Posts: 271
Joined: 19 Jul 2016, 14:47

Re: A really simple solution to accidental CapsLock/NumLock presses

06 Feb 2017, 07:48

evilC wrote:

Code: Select all

^Capslock::
	setcapslockstate, % (GetKeyState("CapsLock", "T") ? "Off" : "On")
	return
thanks man, sorry to bother you with this little thing. so, it does toggles it on and off, but is there a way to change this that the other toggle be the always off, cause my only gripe with this is that it turns the capslock light on every time I use capslock if its state set to off and not alwaysoff.
DeepMind
Posts: 271
Joined: 19 Jul 2016, 14:47

Re: A really simple solution to accidental CapsLock/NumLock presses

06 Feb 2017, 07:55

evilC wrote:

Code: Select all

^Capslock::
	setcapslockstate, % (GetKeyState("CapsLock", "T") ? "AlwaysOff" : "On")
	return
?
oh man, it seemed really easy that I didn't even tried it :lol: , thanks again :bravo:
Excrubulent
Posts: 28
Joined: 24 Jun 2014, 20:47

Re: A really simple solution to accidental CapsLock/NumLock presses

07 Feb 2017, 23:20

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.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 167 guests