How to read a single character from the user?
Solution 1:
Here's a link to the ActiveState Recipes site that says how you can read a single character in Windows, Linux and OSX:
getch()-like unbuffered character reading from stdin on both Windows and Unix
class _Getch:
"""Gets a single character from standard input. Does not echo to the
screen."""
def __init__(self):
try:
self.impl = _GetchWindows()
except ImportError:
self.impl = _GetchUnix()
def __call__(self): return self.impl()
class _GetchUnix:
def __init__(self):
import tty, sys
def __call__(self):
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
class _GetchWindows:
def __init__(self):
import msvcrt
def __call__(self):
import msvcrt
return msvcrt.getch()
getch = _Getch()
Solution 2:
sys.stdin.read(1)
will basically read 1 byte from STDIN.
If you must use the method which does not wait for the \n
you can use this code as suggested in previous answer:
class _Getch:
"""Gets a single character from standard input. Does not echo to the screen."""
def __init__(self):
try:
self.impl = _GetchWindows()
except ImportError:
self.impl = _GetchUnix()
def __call__(self): return self.impl()
class _GetchUnix:
def __init__(self):
import tty, sys
def __call__(self):
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
class _GetchWindows:
def __init__(self):
import msvcrt
def __call__(self):
import msvcrt
return msvcrt.getch()
getch = _Getch()
(taken from http://code.activestate.com/recipes/134892/)
Solution 3:
The ActiveState recipe quoted verbatim in two answers is over-engineered. It can be boiled down to this:
def _find_getch():
try:
import termios
except ImportError:
# Non-POSIX. Return msvcrt's (Windows') getch.
import msvcrt
return msvcrt.getch
# POSIX system. Create and return a getch that manipulates the tty.
import sys, tty
def _getch():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
return _getch
getch = _find_getch()
Solution 4:
Also worth trying is the readchar library, which is in part based on the ActiveState recipe mentioned in other answers.
Installation:
pip install readchar
Usage:
import readchar
print("Reading a char:")
print(repr(readchar.readchar()))
print("Reading a key:")
print(repr(readchar.readkey()))
Tested on Windows and Linux with Python 2.7.
On Windows, only keys which map to letters or ASCII control codes are supported (Backspace, Enter, Esc, Tab, Ctrl+letter). On GNU/Linux (depending on exact terminal, perhaps?) you also get Insert, Delete, Pg Up, Pg Dn, Home, End and F n keys... but then, there's issues separating these special keys from an Esc.
Caveat: Like with most (all?) answers in here, signal keys like Ctrl+C, Ctrl+D and Ctrl+Z are caught and returned (as '\x03'
, '\x04'
and '\x1a'
respectively); your program can be come difficult to abort.