Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capturing user input at arbitrary times in python

Is there a way to send an interrupt to a python module when the user inputs something in the console? For example, if I'm running an infinite while loop, i can surround it with a try/except for KeyboardInterrupt and then do what I need to do in the except block.

Is there a way to duplicate this functionality with any arbitrary input? Either a control sequence or a standard character?

Edit: Sorry, this is on linux

like image 250
Falmarri Avatar asked Aug 10 '26 06:08

Falmarri


2 Answers

Dependent on the operating system and the libraries available, there are different ways of achieving that. This answer provides a few of them.

Here is the Linux/OS X part copied from there, with in infinite loop terminated using the escape character. For the Windows solution you can check the answer itself.

import sys
import select
import tty
import termios

from curses import ascii

def isData():
    return select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], [])

old_settings = termios.tcgetattr(sys.stdin)
try:
    tty.setcbreak(sys.stdin.fileno())

    i = 0
    while 1:
        print i
        i += 1

        if isData():
            c = sys.stdin.read(1)
            if c == chr(ascii.ESC):
                break

finally:
    termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)

Edit: Changed the character detection to use characters as defined by curses.ascii, thanks to Daenyth's unhappiness with magic values which I share.

like image 184
Muhammad Alkarouri Avatar answered Aug 11 '26 21:08

Muhammad Alkarouri


You need a separate process (or possibly a thread) to read the terminal and send it to the process of interest via some form of inter-process communication (IPC) (inter-thread communication may be harder -- basically the only thing you do is send a KeyboardInterrupt from a secondary thread to the main thread). Since you say "I was hoping there would be a simple way to inject user input into the loop other than just ^C", I'm sad to disappoint you, but that's the truth: there are ways to do what you request, but simple they aren't.

like image 21
Alex Martelli Avatar answered Aug 11 '26 20:08

Alex Martelli