How To Read Keyboard Input One Char At A Time With A Timer With Python
I am trying to figure out how to create a little Python script that can take the following parameters: prompt - string time to wait as an integer number of characters before stop
Solution 1:
Ok, I have achieved it :D.
#!/usr/bin/env python
import sys
from select import select
def main(argv):
timeout = 3
prompt = '> '
max_chars = 3
# set raw input mode if relevant
# it is necessary to make stdin not wait for enter
try:
import tty, termios
prev_flags = termios.tcgetattr(sys.stdin.fileno())
tty.setraw(sys.stdin.fileno())
except ImportError:
prev_flags = None
buf = ''
sys.stderr.write(prompt)
while True: # main loop
rl, wl, xl = select([sys.stdin], [], [], timeout)
if rl: # some input
c = sys.stdin.read(1)
# you will probably want to add some special key support
# for example stop on enter:
if c == '\n':
break
buf += c
# auto-output is disabled as well, so you need to print it
sys.stderr.write(c)
# stop if N characters
if len(buf) >= max_chars:
break
else:
# timeout
break
# restore non-raw input
if prev_flags is not None:
termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, prev_flags)
# and print newline
sys.stderr.write('\n')
# now buf contains your input
# ...
if __name__ == "__main__":
main(sys.argv[1:])
It's fairly incomplete; I just put a few values to test it. A few words of explanation:
- You need to switch the tty to 'raw' mode — otherwise you wouldn't be able to get input without it being confirmed by enter key,
- in raw mode the typed in characters are no longer output by default — you need to output them yourself if you want user to see what he is typing,
- you probably want to handle special keys like enter and backspace — I've added enter handling here. Maybe you could reuse parts of
curses
for that, - I've assumed the timeout is '3 seconds after last key'. If you want timeout for whole process, I think the easiest way would be to get current time, increase it by timeout (i.e. get
end_time
), and then passend_time - current_time
in seconds as timeout toselect()
, - I've made unix-specific imports optional. I don't know whether it will work on Windows correctly, though.
Solution 2:
Okay. This thread is a few years idle, but I spent a good hour exploring this (and related) threads for a clean solution. In the end, I decided to use the tool that already works well: bash's read
. Here is an example asking for a power level. The first line in the try
block addresses the question at hand (of course, this only works if you are starting your python script from a bash shell.) Here you have 3 seconds to enter up to 3 characters. (The rest of the try
block converts to int and makes sure it is in an expected range.)
import os
try:
pwr=os.popen('read -t 3 -n 3 -p "enter power level: " power; echo ${power:-0}').read().strip()
print ''
pwr=int(pwr)
if pwr < 0 or pwr > 100: raise ValueError("valid power levels [0..100]")
print "power=%d"%pwr
except ValueError as e:
print "Illegal Power:", e.message
Post a Comment for "How To Read Keyboard Input One Char At A Time With A Timer With Python"