So I am making a program that requires arrow keys but cannot use curses or chr funtion. Is there any simple and easy way to do this?
BTW I have already tried inp.key_UP
but this does not seem to work. Also I am on mac so gtsrc wont work.
So I am making a program that requires arrow keys but cannot use curses or chr funtion. Is there any simple and easy way to do this?
BTW I have already tried inp.key_UP
but this does not seem to work. Also I am on mac so gtsrc wont work.
When the user presses a key (unless you're reading at a very low level, like a Cocoa system event hook), the terminal program (usually Terminal.app) processes that and sends your program a sequence of bytes, which you can read off sys.stdin
or /dev/tty
.
Assuming default settings:
ord
of the character.\x1b[A
), or maybe Cursor Up 1 (\x1b[1A
). (You really shouldn't assume an ANSI-compatible terminal—and you can even configure Terminal.app to send different things—but rather reading $TERM
and looking up the termcaps entry, but if you only care about Mac, you'll almost certainly get away with this.)So, now you just have to open stdin
or /dev/tty
as an unbuffered raw binary file, put it into raw mode (and make sure to restore it at the end of your program), read bytes off it, and recognize ANSI control sequences. Oh, and if the user's keyboard has any keys that aren't ASCII, they'll also show up as multiple bytes that you'll have to decode as UTF-8.
Here's something that should demonstrate it:
import termios
import tty
with open('/dev/tty', 'rb', buffering=0) as f:
stashed = termios.tcgetattr(f.fileno())
try:
tty.setraw(f.fileno())
while True:
key = f.read(1)
if key == b'\x03': # Control-C
break
if key == b'\x1b': # Escape
buf = key
while True:
key = f.read(1)
buf += key
# Cheating a bit; most sequences go until the first letter
if key.isalpha():
break
if buf == b'\x1b[A':
print('Up arrow!')
else:
print('Some other control sequence:', buf)
# punting on UTF-8 decoding, treating non-ASCII as control chars
elif b' ' <= key < b'\x80':
print(key.decode())
else:
print('Some control or non-ASCII key', key)
finally:
termios.tcsetattr(f.fileno(), termios.TCSADRAIN, stashed)
If this doesn't demonstrate why people usually use higher-level libraries like curses
, then look for some code that actually does the termcap and locale stuff right instead of assuming. :)
I tried to... However you need to press enter for it to return the value. Good Luck!
import sys
def get():
x = sys.stdin.read(1)
return x
while True:
key = get()
print key