Search code examples
pythonlinuxbashkeyboard

How to prevent keypress execution in bash on python exit


I'm making use of the keyboard package to capture key events in a python program. Take this simple script with the following:

import keyboard

while True:
    try:
        if keyboard.is_pressed('ESC'):
            break
        else:
            pass
    except:
        break

When I run this script in terminal it behaves as expected until the program closes, at which point everything I typed is entered into the bash terminal as shell commands. This could be dangerous, as every line entered has the possibility of creating adverse system effects.

Any suggested workarounds for this? Pure python solutions preferred but script initialization parameters in bash are suitable.


Solution

  • You are using a global keyboard hook to read input for a single terminal. This is bad design because it spies on events the user may have meant for other programs, it stops your program from working like a normal terminal program (e.g. it won't run over ssh), and since you don't touch your own input queue you will see duplicated input (as you've discovered).

    The better solution is to set the tty to raw mode, and keep reading single keypresses until you want to exit

    #!/usr/bin/env python3
    import termios, tty, sys
    
    # Save terminal settings
    old = termios.tcgetattr(0)
    # Disable buffering
    tty.setcbreak(0)
    
    # Read until Esc
    while sys.stdin.read(1) != "\x1B":
      pass
    
    # Set the terminal settings back
    termios.tcsetattr(0, termios.TCSANOW, old)
    

    If you prefer your design, you can flush the input queue before you exit:

    import termios
    termios.tcflush(0, termios.TCIFLUSH)