Remapping Alt key is unreliable

Report problems with documented functionality
Federhalter
Posts: 13
Joined: 07 Sep 2022, 04:04

Remapping Alt key is unreliable

Post by Federhalter » 07 Sep 2023, 11:43

I use the following script with RAlt as a dead key to type accented letters on a US keyboard. This works, but often, especially when typing fast, in Windows Notepad, the menu is opened. So it seems the Alt key event masking fails sometimes.

Code: Select all

#Requires AutoHotkey v2.0.7+
#Warn All
KeyHistory 500
#SingleInstance Force
Persistent
A_MaxHotkeysPerInterval := 200
;SendMode "Event"
A_MenuMaskKey := "vkE8"
Umlaut := 0
return

#UseHook

#HotIf (Umlaut == 1)
o::
{
	global Umlaut
	SendText "ö"
	Umlaut := 0
}	
u::
{
	global Umlaut
	SendText "ü"
	Umlaut := 0
}	

#HotIf
RAlt::
{
	global Umlaut
	Umlaut := 1
}
~*Esc:: ExitApp
If this occurs, the log of the script shows some ignored (i) events of the A_MenuMaskKey and RAlt, which seems unusual.

Code: Select all

VK  SC	Type	Up/Dn	Elapsed	Key		Window
-------------------------------------------------------------------------------------------------------------
...
A5  138	h	d	0.09	RAlt           	
4F  018	h	d	0.02	o              	
4F  018	s	u	0.09	o              	
55  016	 	u	0.00	u              	
A5  138	s	u	0.01	RAlt           	
A5  138	h	d	0.06	RAlt           	
55  016	h	d	0.01	u              	
4F  018	h	d	0.00	o              	
55  016	s	u	0.52	u              	
E7 00FC	U	d	0.00	ü              	
E8  000	i	d	0.00	not found      	
E8  000	i	u	0.00	not found      	
A5  138	i	u	0.00	RAlt           	
E8  000	i	d	0.00	not found      	
A5  138	i	d	0.00	RAlt           	
E8  000	i	u	0.00	not found      	
55  016	 	u	0.06	u              	
4F  018	s	u	0.00	o              	
A5  138	s	u	0.02	RAlt           	
A5  138	h	d	0.08	RAlt           	
4F  018	 	d	0.00	o              	
55  016	 	d	0.02	u              	
4F  018	 	u	0.08	o              	
55  016	 	u	0.02	u              	
A5  138	s	u	0.01	RAlt           	
...
What is also strange, the script works much more reliable if a second script has a keyboard hook installed, e.g. if the following script is run concurrently, the problem almost never happens:

Code: Select all

#Requires AutoHotkey v2.0.7+
KeyHistory 500
#SingleInstance force   
#Warn All
InstallKeybdHook
#UseHook
Persistent
~*Esc:: ExitApp
I would rather accept a certain delay in typing than the current, unreliable, behaviour.

Also, SendMode "Event" did not solve the problem.
lexikos
Posts: 9780
Joined: 30 Sep 2013, 04:07
Contact:

Re: Remapping Alt key is unreliable

Post by lexikos » 10 Sep 2023, 06:58

RAlt::Ctrl is "remapping" RAlt. RAlt:: is just a hotkey which blocks RAlt when not modified by any other modifier key.

What happens if you use *RAlt::?
lexikos
Posts: 9780
Joined: 30 Sep 2013, 04:07
Contact:

Re: Remapping Alt key is unreliable

Post by lexikos » 11 Sep 2023, 05:47

The timing in the KeyHistory indicates that the "i" events are being sent by SendText "ü". If you insert a short sleep (perhaps >= 20) after SendText "ü" and the subsequent "i" event still shows 0.00, that would more or less confirm it.

I can't see the reason that these events are sent, though, and can't reproduce it.
Federhalter
Posts: 13
Joined: 07 Sep 2022, 04:04

Re: Remapping Alt key is unreliable

Post by Federhalter » 11 Sep 2023, 15:32

It seems I was somewhat wrong about the problem. It is not related to the Alt key at all, but to two keys being pressed in very quick succession.

The following fails very often (on an old & slow i5 machine). I can provoke it by pressing 3 and 4 at the same time very quickly.

Code: Select all

#Requires AutoHotkey v2.0.7+
#Warn All
KeyHistory 500
#SingleInstance Force
Persistent
A_MaxHotkeysPerInterval := 200
;SendMode "Event"
return

#UseHook

3::
{
	Send "1"
	Sleep 20
}	
4::
{
	Send "2"
	Sleep 20
}	

~*Esc:: ExitApp
In a Notepad window by pressing 3 and 4, I got:
2112232321141212
The 3 3 4 characters shouldn't be there!

The log is:

Code: Select all

VK  SC	Type	Up/Dn	Elapsed	Key		Window
-------------------------------------------------------------------------------------------------------------
34  005	h	d	6.64	4              	Unbenannt - Editor
32  003	i	d	0.00	2              	
32  003	i	u	0.00	2              	
33  004	h	d	0.05	3              	
31  002	i	d	0.00	1              	
31  002	i	u	0.00	1              	
34  005	s	u	0.06	4              	
33  004	s	u	0.01	3              	
33  004	h	d	0.09	3              	
31  002	i	d	0.00	1              	
31  002	i	u	0.00	1              	
34  005	h	d	0.03	4              	
32  003	i	d	0.00	2              	
32  003	i	u	0.00	2              	
33  004	s	u	0.05	3              	
34  005	s	u	0.00	4              	
34  005	h	d	0.11	4              	
32  003	i	d	0.00	2              	
32  003	i	u	0.00	2              	
34  005	s	u	0.05	4              	
33  004	 	u	0.00	3              	
34  005	h	d	0.11	4              	
32  003	i	d	0.00	2              	
32  003	i	u	0.00	2              	
33  004	 	u	0.05	3              	
34  005	s	u	0.00	4              	
34  005	h	d	0.11	4              	
32  003	i	d	0.00	2              	
32  003	i	u	0.00	2              	
33  004	h	d	0.02	3              	
31  002	i	d	0.00	1              	
31  002	i	u	0.00	1              	
34  005	s	u	0.03	4              	
33  004	s	u	0.00	3              	
33  004	h	d	0.09	3              	
31  002	i	d	0.00	1              	
31  002	i	u	0.00	1              	
34  005	 	u	0.05	4              	
33  004	s	u	0.00	3              	
33  004	h	d	0.12	3              	
34  005	h	d	0.00	4              	
31  002	i	d	0.00	1              	
31  002	i	u	0.00	1              	
32  003	i	d	0.02	2              	
32  003	i	u	0.00	2              	
34  005	s	u	0.03	4              	
33  004	s	u	0.00	3              	
33  004	h	d	0.11	3              	
34  005	h	d	0.00	4              	
31  002	i	d	0.00	1              	
31  002	i	u	0.00	1              	
32  003	i	d	0.01	2              	
32  003	i	u	0.00	2              	
34  005	s	u	0.02	4              	
33  004	s	u	0.00	3              	
Press [F5] to refresh.
There are three entries with no type (3 3 4) which seem to correlate to the failures.

And, if I add SendMode "Event", the problem disappears!
lexikos
Posts: 9780
Joined: 30 Sep 2013, 04:07
Contact:

Re: Remapping Alt key is unreliable

Post by lexikos » 11 Sep 2023, 21:42

This is by design. SendInput is reliable only if there are no keyboard hooks installed. If there are no other scripts with keyboard hooks running, it will automatically deactivate the script's keyboard hook while the keys are sent. Any user input that is buffered by the system during this are fully handled before the system returns control to AutoHotkey. Only registered ("reg" method) hotkeys work while the hook is inactive.

If you have another script with a keyboard hook, SendInput will fall back to SendEvent.
If a script other than the one executing SendInput has a low-level keyboard hook installed, SendInput automatically reverts to SendEvent (or SendPlay if SendMode "InputThenPlay" is in effect). This is done because the presence of an external hook disables all of SendInput's advantages, making it inferior to both SendPlay and SendEvent. However, since SendInput is unable to detect a low-level hook in programs other than AutoHotkey v1.0.43+, it will not revert in these cases, making it less reliable than SendPlay/Event.
Federhalter
Posts: 13
Joined: 07 Sep 2022, 04:04

Re: Remapping Alt key is unreliable

Post by Federhalter » 12 Sep 2023, 03:50

lexikos wrote:
11 Sep 2023, 05:47
The timing in the KeyHistory indicates that the "i" events are being sent by SendText "ü". If you insert a short sleep (perhaps >= 20) after SendText "ü" and the subsequent "i" event still shows 0.00, that would more or less confirm it.

I can't see the reason that these events are sent, though, and can't reproduce it.
I reduced the script to reproduce the issue (pressing both RAlt and 1 very quickly and repeatedly) with US layout:

Code: Select all

#Requires AutoHotkey v2.0.8+
#Warn All
KeyHistory 500
#SingleInstance Force
Persistent
A_MaxHotkeysPerInterval := 200
SendMode "Event"
A_MenuMaskKey := "vkE8"
return

1::
{
	SendText "ö"
	Sleep 20
}	

*RAlt::
{
}

~*Esc:: ExitApp
Log:

Code: Select all

Type	Off?	Level	Running	Name
-------------------------------------------------------------------
reg				1
k-hook				*RAlt
k-hook				~*Esc

Window: ...\test.ahk - AutoHotkey v2.0.8
Keybd hook: yes
Mouse hook: no
Enabled Timers: 0 of 0 ()
Interrupted threads: 0
Paused threads: 0 of 0 (0 layers)
Modifiers (GetKeyState() now) = RAlt 
Modifiers (Hook's Logical) = RAlt 
Modifiers (Hook's Physical) = 
Prefix key is down: no

NOTE: To disable the key history shown below, call KeyHistory(0).  The same method can be used to change the size of the history buffer.  For example: KeyHistory 100  (Default is 40, Max is 500)

The oldest are listed first.  VK=Virtual Key, SC=Scan Code, Elapsed=Seconds since the previous event.  Types: h=Hook Hotkey, s=Suppressed (blocked), i=Ignored because it was generated by an AHK script, a=Artificial, #=Disabled via #HotIf, U=Unicode character (SendInput).

VK  SC	Type	Up/Dn	Elapsed	Key		Window
-------------------------------------------------------------------------------------------------------------
...
A5  138	h	d	6.88	RAlt           	
31  002	 	d	0.03	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.02	ö              	
A5  138	s	u	0.05	RAlt           	
31  002	 	u	0.05	1              	
A5  138	h	d	0.05	RAlt           	
31  002	 	d	0.05	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.09	RAlt           	
31  002	 	u	0.00	1              	
A5  138	h	d	0.06	RAlt           	
31  002	 	d	0.02	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.09	RAlt           	
31  002	 	u	0.00	1              	
A5  138	h	d	0.05	RAlt           	
31  002	 	d	0.03	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
31  002	 	u	0.09	1              	
A5  138	s	u	0.03	RAlt           	
A5  138	h	d	0.01	RAlt           	
31  002	 	d	0.02	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
31  002	 	u	0.11	1              	
A5  138	s	u	0.00	RAlt           	
A5  138	h	d	0.05	RAlt           	
31  002	 	d	0.02	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.09	RAlt           	
31  002	 	u	0.01	1              	
A5  138	h	d	0.05	RAlt           	
31  002	 	d	0.03	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.08	RAlt           	
31  002	 	u	0.00	1              	
A5  138	h	d	0.05	RAlt           	
31  002	 	d	0.03	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.06	RAlt           	
31  002	 	u	0.03	1              	
A5  138	h	d	0.05	RAlt           	
31  002	 	d	0.03	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.05	RAlt           	
31  002	 	u	0.06	1              	
A5  138	h	d	0.00	RAlt           	
31  002	 	d	0.06	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.05	RAlt           	
31  002	 	u	0.03	1              	
A5  138	h	d	0.03	RAlt           	
31  002	 	d	0.05	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.05	RAlt           	
31  002	 	u	0.06	1              	
A5  138	h	d	0.00	RAlt           	
31  002	 	d	0.06	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.03	RAlt           	
31  002	 	u	0.06	1              	
A5  138	h	d	0.09	RAlt           	
31  002	 	d	0.02	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
31  002	 	u	0.06	1              	
31  002	 	d	0.11	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.11	RAlt           	
31  002	 	u	0.00	1              	
A5  138	h	d	0.02	RAlt           	
31  002	 	d	0.06	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
31  002	 	u	0.09	1              	
31  002	 	d	0.06	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.06	RAlt           	
31  002	 	u	0.03	1              	
A5  138	h	d	0.02	RAlt           	
31  002	 	d	0.06	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.08	RAlt           	
A5  138	h	d	0.02	RAlt           	
31  002	 	u	0.02	1              	
31  002	 	d	0.06	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.06	RAlt           	
31  002	 	u	0.03	1              	
A5  138	h	d	0.03	RAlt           	
31  002	 	d	0.05	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.03	RAlt           	
31  002	 	u	0.05	1              	
A5  138	h	d	0.03	RAlt           	
31  002	 	d	0.05	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.05	RAlt           	
31  002	 	u	0.05	1              	
A5  138	h	d	0.03	RAlt           	
31  002	 	d	0.06	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.00	RAlt           	
31  002	 	u	0.09	1              	
A5  138	h	d	0.00	RAlt           	
31  002	 	d	0.06	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	s	u	0.02	RAlt           	
A5  138	h	d	0.06	RAlt           	
A5  138	s	u	0.08	RAlt           	
A5  138	h	d	0.06	RAlt           	
31  002	 	u	0.08	1              	
A5  138	s	u	0.01	RAlt           	
31  002	 	d	0.03	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	h	d	0.05	RAlt           	
31  002	 	u	0.06	1              	
A5  138	s	u	0.00	RAlt           	
31  002	 	d	0.06	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	h	d	0.03	RAlt           	
A5  138	s	u	0.08	RAlt           	
31  002	 	u	0.00	1              	
31  002	 	d	0.09	1              	
E7 00F6	U	d	0.00	ö              	
E7 00F6	U	u	0.00	ö              	
A5  138	h	d	0.00	RAlt           	
E8  000	i	d	0.01	not found      	
A5  138	i	d	0.00	RAlt           	
E8  000	i	u	0.00	not found      	
A5  138	s	u	0.06	RAlt           	
A5  138	h	d	0.09	RAlt           	
31  002	 	u	0.03	1              	
A5  138	s	u	0.03	RAlt           	
31  002	 	d	0.03	1              	
31  002	 	u	0.06	1              	
Press [F5] to refresh.
The "i" events is where the problem occurs ("stuck" RAlt key)
Federhalter
Posts: 13
Joined: 07 Sep 2022, 04:04

Re: Remapping Alt key is unreliable

Post by Federhalter » 13 Sep 2023, 03:49

My suspicion is that the keyboard hook becomes disabled for some reason here. When reading the following:

https://www.autohotkey.com/docs/v2/lib/Send.htm#Remarks

Characters vs. keys: By default, characters are sent by first translating them to keystrokes. If this translation is not possible (that is, if the current keyboard layout does not contain a key or key combination which produces that character), the character is sent by one of following fallback methods:
  • SendEvent and SendInput use SendInput() with the KEYEVENTF_UNICODE flag.
  • SendPlay uses the Alt+nnnnn method, which produces Unicode only if supported by the target application.
  • ControlSend posts a WM_CHAR message.
The first case seems to suggest that "SendInput()" would be used. Is the keyboard hook disabled in this case?

The following is just as unreliable (even though it sends a keystroke for which a key exists with that character, so it should not revert to SendInput:

Code: Select all

2::
{
	SendEvent "4"
	Sleep 20
}	
Using ControlSendText works reliably, but is not supported in all applications:

Code: Select all

3::
{
	aWin := WinActive("A")
	aCtrl := ControlGetFocus(aWin)
	ControlSendText "ö", aCtrl, aWin
	Sleep 20
}	
lexikos
Posts: 9780
Joined: 30 Sep 2013, 04:07
Contact:

Re: Remapping Alt key is unreliable

Post by lexikos » 13 Sep 2023, 21:56

No, the keyboard hook is temporarily deactivated only by SendInput or Send in SendInput mode, and only if it is not reverting to another mode.

When SendEvent uses SendInput() for individual characters, it does so one call at a time (and applies key delays), so there is no advantage to deactivating the hook (i.e. user input and sent input may be interspersed either way).
Federhalter
Posts: 13
Joined: 07 Sep 2022, 04:04

Re: Remapping Alt key is unreliable

Post by Federhalter » 15 Sep 2023, 11:16

Should I invest time in investigating this problem further, or is my expectation flawed?

My expectation is that it is possible to remap the Right Alt key reliably - and it seems to work fine when using ControlSendText. But a general solution to send characters which are not on the keyboard that works universally in all programs would be better.
lexikos
Posts: 9780
Joined: 30 Sep 2013, 04:07
Contact:

Re: Remapping Alt key is unreliable

Post by lexikos » 15 Sep 2023, 18:00

I don't get it. It is not typical to have these issues.
lexikos
Posts: 9780
Joined: 30 Sep 2013, 04:07
Contact:

Re: Remapping Alt key is unreliable

Post by lexikos » 23 Mar 2024, 01:09

This might have been fixed by v2.0.12.
Fixed Send erroneously releasing a modifier due to a race condition. For example, ~LAlt::Send "{Blind}x" intermittently released LAlt if some other keyboard hook was installed more recently than the script's own hook.
Post Reply

Return to “Bug Reports”