moses-palmer / pynput

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

Windows all process input lag when listener + python input #438

Closed RugnirViking closed 3 months ago

RugnirViking commented 2 years ago

Description I was making a terminal app with this library which was working fine. I have a listener running in non-blocking mode, but when I ask the terminal for input, like to have the user enter a number, some kind of process fighting behind the scenes starts happening, as ALL keyboard input, even when the console is minimised starts to have very long delay,

I could of course handle the number entry myself with keys but I don't want to go through the hassle

Platform and pynput version pynput 1.7.6 windows 10 build 19042.1466

To Reproduce Run following file, press b, and observe all keyboard input in all processes are hanging. On a second note, I was not able to stop the listener for the input either, running the "pynput.keyboard.Listener.stop" command that the docs claim works from anywhere in fact results in an error ( TypeError: stop() missing 1 required positional argument: 'self' )

import time
from pynput import keyboard

def flush_input():
    try:
        import msvcrt
        while msvcrt.kbhit():
            msvcrt.getch()
    except ImportError:
        import sys, termios    #for linux/unix
        termios.tcflush(sys.stdin, termios.TCIOFLUSH)

class Engine():
    def __init__(self):
        self.stop = False

    def on_press(self,key):
        if hasattr(key, 'char'):
            if key.char=='b' or key.char=='B':

                flush_input() 
                # clears the input buffer so the b we 
                # just pressed doesn't go into the input

                # keyboard.Listener.stop() causes error

                num = int(input("Please enter a number:\n"))
                print(f"The number: {num}")

        if key==keyboard.Key.esc:
            self.stop = True

    def on_release(self,key):
        pass

def main():
    # ...or, in a non-blocking fashion:
    engine = Engine()
    listener = keyboard.Listener(
        on_press=engine.on_press,
        on_release=engine.on_release)
    listener.start()

    while True:
        if engine.stop:
            return
        time.sleep(0.1)

if __name__ == '__main__':
    main()
cashlycash commented 3 months ago

valid. found any solutions?

moses-palmer commented 3 months ago

Thank you for your report.

Please see the documentation regarding blocking listener callbacks.

Notably, on Windows, this will incur delays throughout the operating system. flush_input in your example does block. I would suggest to dispatch flushing to another thread.

I will close this issue, as the is an issue of the platform and a known limitation.