Nun, ich schrieb den Code von Hand. Ich werde eine Erklärung für zukünftige Referenz hinterlassen.
Dazu schrieb ich einen Kontext-Manager, der tty
Konfiguration Griffe:
@contextmanager
def cbreak():
old_attrs = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin)
try:
yield
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_attrs)
Dieser Manager ermöglicht das folgende Idiom:
with cbreak():
single_char_no_newline = sys.stdin.read(1)
Es ist wichtig, die Sanierung durchzuführen, wenn wir fertig sind oder das Terminal benötigt möglicherweise eine reset
.
Dekodierungs stdin
Das zweite Problem mit nur das Lesen stdin wird kodiert. Nicht-ASCII-Unicode-Zeichen erreichen uns Byte für Byte, was völlig unerwünscht ist.
richtig stdin zu dekodieren, schrieb ich einen Generator an, die wir für Unicode-Zeichen laufen kann:
def uinput():
reader = codecs.getreader(sys.stdin.encoding)(sys.stdin)
with cbreak():
while True:
yield reader.read(1)
Diese Überleitungen fehlschlagen. Ich bin mir nicht sicher. Für meinen Anwendungsfall nimmt es jedoch die richtige Kodierung auf und erzeugt einen Strom von Zeichen.
Umgang mit Sonderzeichen
Zunächst einmal sollten wir druckbare Zeichen außer Kontrolle diejenigen zu sagen in der Lage:
def is_printable(c):
return not unicodedata.category(c).startswith('C')
Abgesehen von printables, denn jetzt, ich will nur behandeln ← Backspace und die CtrlD Sequenz:
def is_backspace(c):
return c in ('\x08','\x7F')
def is_interrupt(c):
return c == '\x04'
Zusammensetzen: xinput()
Jetzt ist alles vorhanden. Der ursprüngliche Vertrag für die Funktion, die ich wollte, war Eingabe lesen, Sonderzeichen behandeln, Callback aufrufen. Die Umsetzung spiegelt genau das:
def xinput(callback):
text = ''
for c in uinput():
if is_printable(c): text += c
elif is_backspace(c): text = text[:-1]
elif is_interrupt(c): break
callback(text)
return text
Probieren Sie es aus
def test(text):
print 'Buffer now holds', text
xinput(test)
es Laufen und die Eingabe Hellx← Backspaceo Welt zeigt:
Buffer now holds H
Buffer now holds He
Buffer now holds Hel
Buffer now holds Hell
Buffer now holds Hellx
Buffer now holds Hell
Buffer now holds Hello
Buffer now holds Hello
Buffer now holds Hello w
Buffer now holds Hello wo
Buffer now holds Hello wor
Buffer now holds Hello worl
Buffer now holds Hello world