moses-palmer / pynput

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

Inexplicable thread end on windows while suppressing keyboard event #605

Open Ananym opened 1 week ago

Ananym commented 1 week ago

I've been trying to call suppress_event inside the on_press hook for the keyboard. As far as I can tell from the source, this pattern should work - suppressing events in the regular hooks is definitely more convenient than having to do all your event logic with the windows event data provided by win32_event_filter. However, while it works just fine for mouse events, trying to suppress a keyboard event like this causes the thread to instantly end for me. No exception is shown, even if the thread has been joined, so I've been struggling to work out exactly what's going on.

from pynput import keyboard, mouse

# Works: suppresses all scroll/rightclick events without issue
mouse_listener = mouse.Listener()
def on_scroll(x,y,dx,dy):
    mouse_listener.suppress_event()
mouse_listener.on_scroll = on_scroll

def on_click(x,y,button,pressed):
    if button == mouse.Button.right:
        mouse_listener.suppress_event()
mouse_listener.on_click = on_click

# Thread ends immediately on pressing q with no displayed error (event is not suppressed)
keyboard_listener = keyboard.Listener()
def on_press(key):
    if key == keyboard.KeyCode.from_char('q'):
        keyboard_listener.suppress_event()
keyboard_listener.on_press = on_press

if __name__ == "__main__":
    mouse_listener.start()
    mouse_listener.join()
    # or
    keyboard_listener.start()
    keyboard_listener.join()

Would appreciate any comments on the cause, or a better pattern that's similarly convenient, or just tips on how to get started debugging this. Win 10, python 3.11.

Ananym commented 1 week ago

Spent more time on this... Looks like a basically a coincidence that the mouse side of this works: the exception is handled generically, allowing the thread to continue, but the keyboard side doesn't have the abstract exception handler decoration. However, I still have no idea why the event actually gets suppressed in the mouse side - given it goes through an event queue, that doesn't look possible? Yet.. it's what's happening