If one googles backspace python stdin or so, there are a lot of SO results and none that solve my problem. They are all about what the backspace char is not how to get it.
Here's a function that reads a single keypress from stdin
, courtesy https://stackoverflow.com/a/6599441/4532996:
def read_single_keypress():
import termios, fcntl, sys, os
fd = sys.stdin.fileno()
# save old state
flags_save = fcntl.fcntl(fd, fcntl.F_GETFL)
attrs_save = termios.tcgetattr(fd)
# make raw - the way to do this comes from the termios(3) man page.
attrs = list(attrs_save) # copy the stored version to update
# iflag
attrs[0] &= ~(termios.IGNBRK | termios.BRKINT | termios.PARMRK
| termios.ISTRIP | termios.INLCR | termios. IGNCR
| termios.ICRNL | termios.IXON )
# oflag
attrs[1] &= ~termios.OPOST
# cflag
attrs[2] &= ~(termios.CSIZE | termios. PARENB)
attrs[2] |= termios.CS8
# lflag
attrs[3] &= ~(termios.ECHONL | termios.ECHO | termios.ICANON
| termios.ISIG | termios.IEXTEN)
termios.tcsetattr(fd, termios.TCSANOW, attrs)
# turn off non-blocking
fcntl.fcntl(fd, fcntl.F_SETFL, flags_save & ~os.O_NONBLOCK)
# read a single keystroke
try:
ret = sys.stdin.read(1) # returns a single character
except KeyboardInterrupt:
ret = 0
finally:
# restore old state
termios.tcsetattr(fd, termios.TCSAFLUSH, attrs_save)
fcntl.fcntl(fd, fcntl.F_SETFL, flags_save)
return ret
Hacky as it is, it would appear to be cross-platform.
Implementing that is a utility function from my module:
def until(char) -> str:
"""get chars of stdin until char is read"""
import sys
y = ""
sys.stdout.flush()
while True:
i = read_single_keypress()
_ = sys.stdout.write(i)
sys.stdout.flush()
if i == char or i == 0:
break
y += i
return y
Which works really well, except pressing backspace does nothing, and you can't move the cursor (which import readline; input()
allows you to (at least on a Python built with GNU Readline)).
I understand the fact that the best way to implement both of these is probably curses
. I also understand that curses
defeats the standard-libraryness and cross-platformness of this module.
What I'm looking for is a way to read stdin
in a way that will capture backspace, and, for a special bonus, DEL and preferably the arrow keys too.
The module targets Pythons both 2 and 3, but I'm okay with a solution that targets just Python 3, because people really need to stop using 2.
If you think I'm flaming mad for wanting to do this without curses
, well, that's the point.