Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 84 lines (70 sloc) 2.88 KB
#!/usr/bin/env python
import sys, os
import termios, fcntl # For non-blocking key reads
import time
class KeyReader :
'''
Read keypresses one at a time, without waiting for a newline.
Uses the technique from
http://docs.python.org/2/faq/library.html#how-do-i-get-a-single-keypress-at-a-time
'''
def __init__(self, echo=False) :
'''Put the terminal into cbreak and noecho mode.'''
self.fd = sys.stdin.fileno()
self.oldterm = termios.tcgetattr(self.fd)
newattr = termios.tcgetattr(self.fd)
newattr[3] = newattr[3] & ~termios.ICANON
if not echo :
newattr[3] = newattr[3] & ~termios.ECHO
termios.tcsetattr(self.fd, termios.TCSANOW, newattr)
self.oldflags = fcntl.fcntl(self.fd, fcntl.F_GETFL)
fcntl.fcntl(self.fd, fcntl.F_SETFL, self.oldflags | os.O_NONBLOCK)
# Sad hack: when the destructor __del__ is called,
# the fcntl module may already be unloaded, so we can no longer
# call fcntl.fcntl() to set the terminal back to normal.
# So just in case, store a reference to the fcntl module,
# and also to termios (though I haven't yet seen a case
# where termios was gone -- for some reason it's just fnctl).
# The idea of keeping references to the modules comes from
# http://bugs.python.org/issue5099
# though I don't know if it'll solve the problem completely.
self.fcntl = fcntl
self.termios = termios
def __del__(self) :
'''Reset the terminal before exiting the program.'''
self.termios.tcsetattr(self.fd, self.termios.TCSAFLUSH, self.oldterm)
self.fcntl.fcntl(self.fd, self.fcntl.F_SETFL, self.oldflags)
def getch(self) :
'''Read keyboard input, returning a string.
Note that one key may result in a string of more than one character,
e.g. arrow keys that send escape sequences.
There may also be multiple keystrokes queued up since the last read.
This function, sadly, cannot read special characters like VolumeUp.
They don't show up in ordinary CLI reads -- you have to be in
a window system like X to get those special keycodes.
'''
try:
return sys.stdin.read()
except IOError:
return None
if __name__ == "__main__" :
readkey = KeyReader()
while True :
time.sleep(1)
c = readkey.getch()
if not c :
continue
# Examples of how to compare strings.
if c == 'q' :
print "Bye!"
#readkey.reset()
readkey = None
sys.exit(0)
if c == '\x1b[A' : # Up arrow
print "Up!"
continue
for cc in c :
o = ord(cc)
if o < 32 : cc = ' ' # Don't try to print nonprintables
print '%c (%d)' % (cc, o),
print