CapsLock to Control and Escape while retaining modifiers

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
samvv
Posts: 3
Joined: 17 Jul 2021, 07:30
Contact:

CapsLock to Control and Escape while retaining modifiers

17 Jul 2021, 07:45

Hi everyone,

I'm upgrading my development setup and thought about using Windows with WSL 2 as an alternative to a crashing Ubuntu installation. One piece of software I can't live without is xcape, a tiny X11 service that maps CapsLock to Escape when pressed for a brief time and otherwise maps it to Ctrl.

I'd like to achieve the same mapping from CapsLock to Ctrl/Escape on my Windows installation, but I'm having some issues. The script at the end of this post does almost exactly what I want, except that it does not work when typing e.g. Shift+Ctrl+V in the terminal. This is probably because the script only starts working as soon as it detects the Ctrl modifier. Ctrl+Shift+V works perfectly fine, but unfortunately I tend to type the first combination a lot when I'm in a hurry.

My question is: how do I adjust the script below to take into account additional modifiers like Shift?

Code: Select all

SetCapsLockState Off

CapsLock::
	key=
	Input, key, B C L1 T1, {Esc}
	if (ErrorLevel = "Max")
		Send {Ctrl Down}%key%
	KeyWait, CapsLock
	Return
CapsLock up::
	If key
		Send {Ctrl Up}
	else
		if (A_TimeSincePriorHotkey < 1000)
			Send, {Esc 2}
	Return
Thanks for taking the time to read this!
User avatar
submeg
Posts: 326
Joined: 14 Apr 2017, 20:39
Contact:

Re: CapsLock to Control and Escape while retaining modifiers

18 Jul 2021, 07:24

Hey @samvv, welcome to AHK!

The way I change the behaviour of keys is to check for a short press, long press and a double press. In your case, it would look something like this (untested):

Code: Select all

CapsLock::

KeyWait, CapsLock, T0.2

if (ErrorLevel) {	;received a long press - Sends CTRL (do you need to specify Left or Right control?)

	Send, {Ctrl}

}

else {

	KeyWait, CapsLock, D T0.1
	If (ErrorLEvel) {		;received a short press - Send Esc (twice)

		Send, {Esc 2}

	}

	else {			;received a double press - toggle caps lock

		Hotkey, CapsLock, off

		Send, {CapsLock}

		Hotkey, CapsLock, on

	}

}

KeyWait, CapsLock

Return

____________________________________
Check out my site, submeg.com
Connect with me on LinkedIn
Courses on AutoHotkey :ugeek:
samvv
Posts: 3
Joined: 17 Jul 2021, 07:30
Contact:

Re: CapsLock to Control and Escape while retaining modifiers

18 Jul 2021, 08:01

Hi submeg,

Thanks, that's a valid alternative. However I've been working on it just now and found the solution. It was embarrassingly simple: just add a * to accept modifiers and it works! With some further tweaking to avoid race conditions, the following script is what I came up with. It might not look pretty, but it works really well. So far no issues, even when using the key very regularly in Vim.

Code: Select all

SetCapsLockState Off

WaitingForCtrlInput := false
SentCtrlDownWithKey := false

*CapsLock::
	key := 
	WaitingForCtrlInput := true
	Input, key, B C L1 T1, {Esc}
	WaitingForCtrlInput := false
	if (ErrorLevel = "Max") {
		SentCtrlDownWithKey := true
		Send {Ctrl Down}%key%
	}
	KeyWait, CapsLock
	Return

*CapsLock up::
	If (SentCtrlDownWithKey) {
		Send {Ctrl Up}
		SentCtrlDownWithKey := false
	} else {
		if (A_TimeSincePriorHotkey < 1000) {
			if (WaitingForCtrlInput) {
				Send, {Esc 2}
			} else {
				Send, {Esc}
			}
		}
	}
	Return

samvv
Posts: 3
Joined: 17 Jul 2021, 07:30
Contact:

Re: CapsLock to Control and Escape while retaining modifiers

18 Jun 2022, 14:16

Hi all,

Just wanted to share this snippet for AutoHotKey 2.0 beta. It does the same thing as the previous snippet but makes use of InputHook, which results in some edge cases being better handled and a more elegant implementation. Note that I applied this hack to map Ctrl to CapsLock on my machine. AutoHotKey recognises my CapsLock key as Ctrl; I guess because the registry hack has a pretty high precedence.

Code: Select all

#Requires AutoHotkey v2.0-beta
#SingleInstance

ih := InputHook("B L1 T1", "{Esc}")

*Ctrl::
{
	ih.Start()
	reason := ih.Wait()
	if (reason = "Stopped") {
		Send "{Esc}"
	} else if (reason = "Max") {
		Send "{Blind}{Ctrl down}" ih.Input
	}
}

*Ctrl up::
{
	if (ih.InProgress) {
		ih.Stop()
	} else {
		Send "{Ctrl up}"
	}
}
A big thank you to everyone who made AutoHotKey possible! This saves me a tremendous amount of time and makes me a bit more comfortable working with Windows.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: hedehede81, OrangeCat and 290 guests