Created
January 7, 2015 09:35
-
-
Save geraintwhite/100537f524052ee69394 to your computer and use it in GitHub Desktop.
NonBlockingInput module for Python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Most of this code came from this page: | |
http://code.activestate.com/recipes/134892/#c5 | |
""" | |
import sys | |
import select | |
UP, DOWN, RIGHT, LEFT = 'A', 'B', 'C', 'D' | |
class NonBlockingInput: | |
""" | |
Gets a single character from standard input. Does not echo to the | |
screen. | |
""" | |
def __init__(self): | |
try: | |
self.impl = _nbiGetchWindows() | |
except ImportError: | |
try: | |
self.impl = _nbiGetchMacCarbon() | |
except (AttributeError, ImportError): | |
self.impl = _nbiGetchUnix() | |
def char(self): | |
try: | |
return self.impl.char().replace('\r', '\n').replace('\r\n', '\n') | |
except: | |
return None | |
def __enter__(self): | |
self.impl.enter() | |
return self | |
def __exit__(self, type_, value, traceback): | |
self.impl.exit(type_, value, traceback) | |
class _nbiGetchUnix: | |
def __init__(self): | |
# Import termios now or else you'll get the Unix version on the Mac. | |
import tty | |
import termios | |
self.tty = tty | |
self.termios = termios | |
def enter(self): | |
self.old_settings = self.termios.tcgetattr(sys.stdin) | |
self.tty.setcbreak(sys.stdin.fileno()) | |
def exit(self, type_, value, traceback): | |
self.termios.tcsetattr(sys.stdin, | |
self.termios.TCSADRAIN, self.old_settings) | |
def char(self): | |
if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []): | |
return sys.stdin.read(1) | |
return None | |
class _nbiGetchWindows: | |
def __init__(self): | |
import msvcrt | |
self.msvcrt = msvcrt | |
def enter(self): | |
pass | |
def exit(self, type_, value, traceback): | |
pass | |
def char(self): | |
if self.msvcrt.kbhit(): | |
try: | |
return str(self.msvcrt.getch(), encoding='UTF-8') | |
except: | |
pass | |
return None | |
class _nbiGetchMacCarbon: | |
""" | |
A function which returns the current ASCII key that is down; | |
if no ASCII key is down, the null string is returned. The | |
page http://www.mactech.com/macintosh-c/chap02-1.html was | |
very helpful in figuring out how to do this. | |
""" | |
def __init__(self): | |
# See if teminal has this (in Unix, it doesn't) | |
import Carbon | |
self.Carbon = Carbon | |
self.Carbon.Evt | |
def enter(self): | |
pass | |
def exit(self, type_, value, traceback): | |
pass | |
def char(self): | |
if self.Carbon.Evt.EventAvail(0x0008)[0] == 0: # 0x0008 is the keyDownMask | |
return '' | |
else: | |
# The event contains the following info: | |
# (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1] | |
# | |
# The message (msg) contains the ASCII char which is | |
# extracted with the 0x000000FF charCodeMask; this | |
# number is converted to an ASCII character with chr() and | |
# returned. | |
_, msg, _, _, _ = self.Carbon.Evt.GetNextEvent(0x0008)[1] | |
return chr(msg & 0x000000FF) | |
class BlockingInput(NonBlockingInput): | |
""" | |
Gets a single character from standard input. Does not echo to the | |
screen. | |
""" | |
def __init__(self): | |
try: | |
self.impl = _biGetchWindows() | |
except ImportError: | |
try: | |
self.impl = _biGetchMacCarbon() | |
except (AttributeError, ImportError): | |
self.impl = _biGetchUnix() | |
class _biGetchUnix(_nbiGetchUnix): | |
def char(self): | |
return sys.stdin.read(1) | |
class _biGetchWindows(_nbiGetchWindows): | |
def char(self): | |
try: | |
return str(self.msvcrt.getch(), encoding='UTF-8') | |
except: | |
return None | |
class _biGetchMacCarbon(_nbiGetchMacCarbon): | |
pass | |
def escape_code(bi): | |
# Blocking only | |
first = bi.char() | |
if first == chr(27) and bi.char() == '[': | |
return bi.char() | |
return first | |
def main(): | |
import time | |
with BlockingInput() as bi: | |
while True: | |
print(ord(escape_code(bi))) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment