moses-palmer / pynput

Sends virtual input commands
GNU Lesser General Public License v3.0
1.79k stars 248 forks source link

Still unable to pass vk values to parse #345

Closed tehruttiger closed 3 years ago

tehruttiger commented 3 years ago

In issue #342, the response was:

Yes, this is possible. Please see here.

It appears this piece of documentation in not included on readthedocs; I'll see to it that it gets included, and also the fact that you can pass VK's as <123>.

I am still unable to get the Hotkey to fire.

I used the following code to get VK values for 'shift' and 'a'

from pynput.keyboard import Key, KeyCode, Controller, Listener
from time import sleep

def on_press(key):
    print('press',key.__dict__)
    sleep(3)

def on_release(key):
    print('release',key.__dict__)

with Listener(on_press=on_press,on_release=on_release) as listener:
    listener.join()

That gave me 65 for 'a' and 160 for 'shift'. I then tried this and attempted to trigger the event with the shift key with no luck.

from pynput import keyboard
from time import sleep

SkipHotkey = "<160>"
go = True

def dosomething():
    print("hi")

def on_activate():
    dosomething()

def for_canonical(f):
    return lambda k: f(listener.canonical(k))

hotkey = keyboard.HotKey(keyboard.HotKey.parse(SkipHotkey),on_activate)

listener = keyboard.Listener(
    on_press=for_canonical(hotkey.press),
    on_release=for_canonical(hotkey.release))
listener.start()

while go:
    sleep(1)

Just for grins I also tried setting SkipHotkey to "160" which threw a ValueError. Using <65> also similarly did not trigger on_activate when 'a' was pressed. My original plan was to use <160>+<65> which also does not trigger on_activate.

moses-palmer commented 3 years ago

I think you have actually found a bug in the implementation.

I have pushed a fix to fixup-global-hotkeys-canonical. Using that branch, the following code works as expected:

from pynput import keyboard

def on_activate():
    print('<shift>+<numpad:4> pressed')

with keyboard.GlobalHotKeys({
        '<shift>+<65361>': on_activate}) as h:
    h.join()

Please note that using virtual key codes is inherently coupled with a specific platform; since you say that you found shift to be 160, I can assume that you are probably running your application on Windows, and the code above, which uses virtual key codes for Linux, will not work.

Also note that your example above will not work with the fix, since characters and modifiers will never be compared using virtual key codes; you will be able to specify keys not defined by pynput however, such as the numeric keys from #342.

tehruttiger commented 3 years ago

If I understand you correctly, you are saying that modifiers cannot be passed to keyboard.GlobalHotKeys as virtual key codes, though they can be paired in their normal form like with virtual key codes of characters (or numeric keys as you mention). Is that correct?

Will keyboard.HotKey.parse be receiving a similar fix/update?

It would appear that the virtual key code for numpad:4 is 100, but I was still unable to get your code above (with <65361> replaced with <100>) to work. I'm pretty new to Python though, so its entirely possible I screwed something up.

Replacing <100> with <37>, which is left, did work, but only with NumLock off, obviously. It worked interchangeably with shift + left arrow key.

moses-palmer commented 3 years ago

I performed some testing in a Windows virtual machine, and I can confirm your findings.

When logging the actual keys received, I noticed that when shift is pressed, the virtual key code for numpad:4 changes to 37. On my system, a shift-release is injected just before the <37> is sent, and a shift-press just after, so the hot key state never matches what is expected and it cannot be triggered.

I think this is as far as I am willing to go to make virtual key codes work. The test branch does fix an error, so I will merge it, but I think the long term solution would be to add support for the numeric keys. On windows, they will not be usable with the shift modifier however.

With that, I will close this issue.