v2.0 InputHook() fails to capture Numeric keypad numbers

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
snovotill
Posts: 8
Joined: 23 Nov 2023, 10:40

v2.0 InputHook() fails to capture Numeric keypad numbers

Post by snovotill » 23 Nov 2023, 11:01

[Moderator's note: Topic moved from Bug Reports.]

The following script works great with the main keyboard number keys but InputHook() fails on the numeric keypad.
It allows you to enter hex Unicode ( eg 221e and so on ) values in order to insert special characters.
Instructions are in the comment header and it will display all keystrokes entered as a tooltip.
I did try adding {Numeric7} etc to KeyOpt but to no avail.

A second problem is that InputHook() fails to recognize key-up codes as input termination characters.
I tried InputHook("L5 T9 M","{LAlt up}") and even though it dispatches OnKeyUp, it fails to actually stop and so I had to implement the rather silly work-around in my code below.

Despite these problems, the program works great, much better than the crap which microsoft has spewed upon the masses (This program works exactly the same way but it ACTUALLY works reliably and doesn't require a registry key). It's a mind-numbing thought that MS has not provided any reasonable way to enter unicode characters into Windows. I often do this many times per day, so AutoHotKey and the program below and is a true godsend.

Code: Select all

#Requires AutoHotkey v2.0

; https://www.autohotkey.com/
; Instructions: 
;    Hold down ALT key
;    Punch + key
;    Type a 1~5 digit hex code, eg: f7
;    Release ALT key
; Hit Esc key at any point to cancel out
; Times out after 9s to prevent confusion
; Put this script into: shell:startup
; Or better into: shell:common startup

!NumpadAdd::
!+::
{
ih := InputHook("L5 T9 M","{Space}{Enter}{Escape}")
ih.VisibleNonText := False
ih.KeyOpt("{All}", "+I -N")
ih.KeyOpt("1234567890abcdef", "-I")
ih.KeyOpt("{LAlt}{RAlt}", "+N")
ih.OnKeyUp := KeyUp
ih.Start()
ih.Wait()
if (ih.EndReason = "Timeout" or ih.EndKey = "Escape")
   return
Send "{U+" ih.Input "}"
ToolTip "{U+" ih.Input "}"
SetTimer () => ToolTip(), -3000
}

KeyUp(ih, vk, sc)
{
ih.Stop()
;MsgBox GetKeyName(Format("vk{:x}sc{:x}", vk, sc)) " vk" vk " sc" sc
}

User avatar
Datapoint
Posts: 303
Joined: 18 Mar 2018, 17:06

Re: v2.0 InputHook() fails to capture Numeric keypad numbers

Post by Datapoint » 23 Nov 2023, 13:08

snovotill wrote:
23 Nov 2023, 11:01
I did try adding {Numeric7} etc to KeyOpt but to no avail.
Try it with {Numpad7} instead.

snovotill
Posts: 8
Joined: 23 Nov 2023, 10:40

Re: v2.0 InputHook() fails to capture Numeric keypad numbers

Post by snovotill » 23 Nov 2023, 18:39

Oops, I actually did try {Numpad7} last night but it did not help. Sorry about the typo in my original post (was a very late night trying to get it to work).

lexikos
Posts: 9652
Joined: 30 Sep 2013, 04:07
Contact:

Re: v2.0 InputHook() fails to capture Numeric keypad numbers

Post by lexikos » 23 Nov 2023, 19:19

How is this a bug?

Numpad keys do not produce text while you are holding Alt, so none can be collected by InputHook. If you want to collect key-combinations that would not normally produce text, you must use OnKeyDown.

InputHook isn't intended to support {key up} in the EndKeys parameter, and there is nothing in the documentation indicating such a thing would be valid.
A list of zero or more keys, any one of which terminates the Input when pressed

snovotill
Posts: 8
Joined: 23 Nov 2023, 10:40

Re: v2.0 InputHook() fails to capture Numeric keypad numbers

Post by snovotill » 23 Nov 2023, 19:50

I did try capturing the NumPad numbers via OnKeyDown and then feeding the keypresses back into InputHook() via Send, but that fed the keypresses downstream to my application instead of ingesting them into InputHook().

I also tried using the vk code of Alt (up) to terminate, but that didn't work either so now I have the circumspect work-around

Is it intentional that InputHook does not have options to allow any solution for these issues? If so then I should open a feature request instead of a bug. I have not found any other way to do these things, and fixing the numpad issue via OnKeyDown is extremely circumspect, considering that InputHook does see these keys. The most useful solution I can see would be to have an option which simply unblocks the ingestion of vk codes, since these are already being seen but silently blocked.

snovotill
Posts: 8
Joined: 23 Nov 2023, 10:40

Re: v2.0 InputHook() fails to capture Numeric keypad numbers

Post by snovotill » 23 Nov 2023, 20:10

Farther to above (since I cannot edit my post), is there a way to have Send to insert vk and sc codes at the "keyboard" level, so that InputHook can see and intercept them? I realize this could create loops, but it allows simple work-arounds for specific problems.

ntepa
Posts: 434
Joined: 19 Oct 2022, 20:52

Re: v2.0 InputHook() fails to capture Numeric keypad numbers

Post by ntepa » 25 Nov 2023, 06:02

This works with Numpad numbers:

Code: Select all

!NumpadAdd::
!+::
{
    ih := InputHook("L0 T9","{Space}{Enter}{Escape}")
    ih.VisibleNonText := False
    Numbers := ""
    loop 10
        Numbers .= (A_Index - 1) . "{Numpad" (A_Index - 1) "}"
    ih.KeyOpt(Numbers "{LAlt}{RAlt}abcdef", "+N")

    ih.OnKeyDown := KeyDown
    ih.OnKeyUp := KeyUp

    ih._Input := ""
    ToolTip "{U+" ih._Input "}"

    ih.Start()
    ih.Wait()

    SetTimer ToolTip, -3000

    if ih.EndReason = "Timeout" || ih.EndKey = "Escape" || ih._Input = ""
        return

    Send "{U+" ih._Input "}"

    KeyDown(ih, vk, sc) {
        keyName :=  GetKeyName(Format("vk{:x}sc{:x}", vk, sc))
        ; If Numpad0 to Numpad9
        if (vk >= 96 && vk <= 105)
            ih._Input .= SubStr(keyName, -1)
        else
            ih._Input .= keyName

        ToolTip "{U+" ih._Input "}"
        if StrLen(ih._Input) >= 5
            ih.Stop()
    }

    KeyUp(ih, vk, sc) {
        ; LAlt or RAlt
        if (vk = 164 || vk = 165)
            ih.Stop()
    }
}

snovotill
Posts: 8
Joined: 23 Nov 2023, 10:40

Re: v2.0 InputHook() fails to capture Numeric keypad numbers

Post by snovotill » 25 Nov 2023, 23:07

Congratulations maestro! You have just re-written much of the InputHook() source-code LOL, except that you didn't implement the backspace key for snubbing the occasionally mis-typed digit.

Let me rephrase that: Thank you for doing this, it would have taken me no less than 16 hours of continuous work to do the same. I am absolutely thrilled that I can now bang U+hex values into my NUMERIC KEYPAD like machine-gun fire! Thank you.

The 20 lines of extra code needed to do this (after future implementation of backspace) are only necessary because InputHook() currently has no option to enable ingestion of "keys actually typed". I would like to submit a feature request to add an option "InputHook(K)" which will enable such powerful processing. Any advice on how best to submit this so that it will be seen? I am not capable of implementing it myself (yet) but I'm fully willing to contribute by writing the documentation for it.

I would also like to request that "InputHook(,{LAlt up})" and similar be made to work. Again, there seems to be some options in the source code which currently actively prevent this?

snovotill
Posts: 8
Joined: 23 Nov 2023, 10:40

Re: v2.0 InputHook() fails to capture Numeric keypad numbers

Post by snovotill » 25 Nov 2023, 23:48

...farther to above, another useful thing would be to provide a way to place keystrokes into InputHook()'s buffer. Then you could read strokes via OnKeyDown(), process them, and punt them back in without re-triggering OnKeyDown(). Perhaps much more powerful than my post above, but also very easy to use for people like me who struggle to write a line of code.

lexikos
Posts: 9652
Joined: 30 Sep 2013, 04:07
Contact:

Re: v2.0 InputHook() fails to capture Numeric keypad numbers

Post by lexikos » 30 Nov 2023, 19:49

InputHook does not have a buffer of keystrokes; it has a buffer of characters, which the Input property returns. If you want a buffer containing text and other data, you can create your own and collect whatever you want into it, in whatever form you want.

Having the Numpad keys produce digits regardless of Alt would be a simple solution for your use case, but it would not help in any situation where the script needs to differentiate between Numpad and non-Numpad keys, or collect other non-text key combinations, key-up events or other data, such as timing. If InputHook was to collect non-text keys and up events, it would need some way to convey that to the script. For instance, with a string like "{Numpad7}{Numpad8}" or "{LAlt up}{Numpad7 down}{Numpad7 up}", your script would need to parse out the individual components. I doubt that this would be much simpler than ntepa's script, which is just the result of applying logic to combine some simple features of InputHook.

snovotill wrote:feeding the keypresses back into InputHook() via Send, but that fed the keypresses downstream to my application
By design, SendInput (the default mode of Send) uninstalls the keyboard hook temporarily, which has the side-effect of disabling InputHook collection and hook-based hotkeys. If you want the sent keys to be collected, you should use SendEvent.

I also tried using the vk code of Alt (up) to terminate
As I said, InputHook's EndKeys option terminates when the key is pressed, and the "up" suffix is not valid in this context. It has nothing to do with whether you specify a name, VK or SC.

fixing the numpad issue via OnKeyDown is extremely circumspect, considering that InputHook does see these keys
I don't think you're using the word "circumspect" correctly. In any case, OnKeyDown is a part of InputHook, and obviously wouldn't work if InputHook didn't see the keys, so your reasoning seems questionable.

Is it intentional that InputHook does not have options to allow any solution for these issues?
InputHook gives you all of the basic features needed to solve many different problems. As with any problem that doesn't have a ready-made solution, it is just a case of choosing the appropriate elements and tying them together using logic, translated to code. This is what I call programming.

snovotill
Posts: 8
Joined: 23 Nov 2023, 10:40

Re: v2.0 InputHook() fails to capture Numeric keypad numbers

Post by snovotill » 15 Dec 2023, 02:52

lexikos wrote:If you want the sent keys to be collected, you should use SendEvent.
I tried that too but SendEvent() causes InputHook() to crash per the example code below, so there is no way that you can capture a keystroke with InputHook(), modify it into a different keystroke, and then send it onto the InputHook() character buffer. SendEvent is literally causing InputHook() to crash, whereas InputHook should be ingesting the character.

Code: Select all

!NumpadAdd::
!+::
{
ih := InputHook("L5 T9 M","{Space}{Enter}{Escape}")
ih.VisibleNonText := False
ih.KeyOpt("{All}", "+I -N")
ih.KeyOpt("1234567890abcdef", "-I")
ih.KeyOpt("{Numpad0}{Numpad1}{Numpad2}{Numpad3}{Numpad4}{Numpad5}{Numpad6}{Numpad7}{Numpad8}{Numpad9}", "+N")
ih.KeyOpt("{LAlt}{RAlt}", "+N")
ih.OnKeyDown := KeyDown
ih.OnKeyUp := KeyUp
ih.Start()
ih.Wait()
if (ih.EndReason = "Timeout" or ih.EndKey = "Escape")
   return
Send "{U+" ih.Input "}"
ToolTip "{U+" ih.Input "}"
SetTimer () => ToolTip(), -3000
}

KeyDown(ih, vk, sc)
{
mumber := vk-66
; Numpad0 to Numpad9
if (vk > 95 && vk < 106) {
SendEvent "{U+" vk-66 "}"
}
}

KeyUp(ih, vk, sc)
{
; LAlt or RAlt
if (vk = 164 || vk = 165) {
ih.Stop()
}
}

[Mod edit: Added [code][/code] tags. Please use them yourself when posting code.]

snovotill
Posts: 8
Joined: 23 Nov 2023, 10:40

Re: v2.0 InputHook() fails to capture Numeric keypad numbers

Post by snovotill » 15 Dec 2023, 18:24

Okay folks, I've given up on trying to make InputHook() do all of the work internally, but I'm using InputHook() to intercept keystrokes and Send() to punt out the unicode.

Thanks to ntepa for suggesting the skeleton code and thanks to AutoHotKey for saving me the trouble of having to write C++ code.

My latest Unicode Keyboard Input U+‹Hex› script now handles the numpad as well as keystroke editing and input validation.
It works SO MUCH BETTER than the official Microsoft utility while being a drop-in replacement for it.

I've literally used it hundreds of times over the past week and I'm so happy with it that it has earned its own web page at:
https://www.congrenation.com/UnicodeKeyboardInput/index.html where anyone can download it.

lexikos
Posts: 9652
Joined: 30 Sep 2013, 04:07
Contact:

Re: v2.0 InputHook() fails to capture Numeric keypad numbers

Post by lexikos » 16 Dec 2023, 23:36

snovotill wrote:
15 Dec 2023, 02:52
I tried that too but SendEvent() causes InputHook() to crash per the example code below
It does not "crash". Some basic debugging reveals that your code detects Alt has been released, and specifically calls ih.Stop(). Of course InputHook will stop collecting when you tell it to.

Unless you tell it to do otherwise, Send/SendEvent assumes you want the keys or text sent unmodified. As you are holding Alt down, sending "{U+...}" unmodified requires releasing Alt, so SendEvent does that. One way to avoid that is to use {Blind}:

Code: Select all

SendEvent "{Blind}{U+" vk-66 "}"

A second problem with your code is that you told InputHook to ignore all text produced by anything except the keys "1234567890abcdef". "{U+...}" produces a Unicode packet not corresponding to any key, so any text it produces is ignored. Unicode packets have the VK value 0xE7 (VK_PACKET). InputHook treats each Unicode event as both {vkE7} and {sc000}, so you must remove the flag from both.

Code: Select all

ih.KeyOpt("{sc000}{vkE7}", "-I")

With these two changes, if I type a sequence using the Numpad, the system inserts its own character before the script does. I think this is because the system's own handling of Alt+Numpad is done at a lower level than the keyboard hook, or in other words, before the hook is called. Instead of the two changes above, you can send one of the digit keys:

Code: Select all

SendEvent "{Blind}" Chr(vk-0x30)

This works as expected, which I presume is because sending a non-Numpad key interrupts the system's processing of Alt+Numpad, even though the script ultimately intercepts and suppresses the sent key.

Post Reply

Return to “Ask for Help (v2)”