ethanhs / pyhooked

Pure Python hotkey hook, with thanks to pyHook and pyhk
155 stars 28 forks source link

Multikey-press behaves strangely depending on key up/down sequence #22

Open AlexEshoo opened 8 years ago

AlexEshoo commented 8 years ago

Consider the following code which prints the event type, key, and list of currently pressed keys for a keyboard event.

from pyhooked import Hook, KeyboardEvent

def handle_events(args):
    if isinstance(args, KeyboardEvent):
        print args.event_type, args.current_key, args.pressed_key

hk = Hook()  # make a new instance of PyHooked
hk.handler = handle_events  # add a new shortcut ctrl+a, or triggered on mouseover of (300,400)
hk.hook()  # hook into the events, and listen to the presses

When a key, 'a' for example, is held down, the output is: key down A ['A'] and it is repeated until the key is released, which then yields a single output of: key up A [] .

Now consider pressing the 'A' and 'S' Keys simultaneously. For the first example, consider holding 'A' first, then 'S', then letting go of 'A', then 'S'. The output is (in order, repeated if dots follow):

key down A ['A']
...
key down S ['A', 'S']
...
key up A['S']
key down S ['S']
...
key up S []

Now consider the case of releasing 'S' first instead. The output is (in order, repeated if dots follow):

key down A ['A']
...
key down S['A', 'S']
...
key up S ['A']
key up A []

Notice that the difference is that the key down event does not repeat for 'A' after 'S' has been released as was the case for 'S' in the first example. This can be generalized for the case when more than two buttons are pressed as well. In every case, if the last button that was pressed is released, the output stops repeating.

This behavior is inconsistent, however I'm not sure what the intended behavior is. Do we define a keyboard event as a triggered event? Then holding a key down should not repeat output. Or do we define it as the state of the key? In that case the output should repeat for the key(s) being held and when one is released the other(s) should continue to repeat.

Do you have thoughts on what should be the proper output?

ethanhs commented 8 years ago

If I understand your explanation correctly, then I believe the first example is correct. Because if you lift up 'S' first, A is still down so, it should be received as such.

AlexEshoo commented 8 years ago

I'm not very familiar with the windows API unfortunately, so I can't seem to find where the code is going wrong with this. Do you have any ideas?

ethanhs commented 8 years ago

No ideas off the top of my head. I can't promise I'll have time to look at this soon, but I will try to get to it when I can.

KeineLimonade commented 8 years ago

Don´t worry, I found myself a workaround.

AlexEshoo commented 8 years ago

What is the workaround that you found?

AlexEshoo commented 8 years ago

I did a little digging and I found this example also exhibits the same behavior. (Not surprisingly since this repository is a spitting image of the example). http://stackoverflow.com/questions/9817531/applying-low-level-keyboard-hooks-with-python-and-setwindowshookexa

Something else that perhaps I do not fully understand, and therefore found confusing is that TranslateMessage(byref(message)) and DispatchMessageW(byref(message)) never seemed to be called. It seems that msg = GetMessageW(byref(message), 0, 0, 0) gets called once in the while loop, but never again. Is this to be expected? The WinAPI documentation seems to indicate otherwise. https://msdn.microsoft.com/en-us/library/windows/desktop/ms644928(v=vs.85).aspx

KeineLimonade commented 8 years ago

I created a daemon thread and an function which would wait till this thread outputs something

KeineLimonade commented 8 years ago

https://github.com/DungeonDevs/DungeonGame/blob/master/src/engine/input.py