那麼,我手寫了代碼。我會留下解釋以備將來參考。
要求
import sys, tty, termios, codecs, unicodedata
from contextlib import contextmanager
禁用行緩衝
是指當簡單地讀取標準輸入是行緩衝的第一個問題。我們希望單個字符在沒有必要的換行符的情況下到達我們的程序,這不是終端操作的默認方式。
對於這一點,我寫了一個處理tty
配置的上下文管理器:
@contextmanager
def cbreak():
old_attrs = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin)
try:
yield
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_attrs)
該管理器使下列成語:
with cbreak():
single_char_no_newline = sys.stdin.read(1)
它進行清理時,我們就大功告成了很重要,或者終端可能需要reset
。
解碼標準輸入
的第二個問題,只需讀取標準輸入編碼。非ASCII字符會逐字節地到達我們,這是完全不希望的。
要正確解碼標準輸入,我寫了一臺發電機,我們可以遍歷爲Unicode字符:
def uinput():
reader = codecs.getreader(sys.stdin.encoding)(sys.stdin)
with cbreak():
while True:
yield reader.read(1)
這可能會失敗過管道。我不確定。然而,對於我的用例,它會選擇正確的編碼並生成一串字符。
處理特殊字符
首先,我們應該能夠從控制那些分不清打印字符:
def is_printable(c):
return not unicodedata.category(c).startswith('C')
從printables
除此之外,現在,我只想處理←退格和Ctrl鍵d序列:
def is_backspace(c):
return c in ('\x08','\x7F')
def is_interrupt(c):
return c == '\x04'
把它放在一起:xinput()
一切都在現在。我想要的功能原始合同是讀取輸入,處理特殊字符,調用回調。實施只是反映了:
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
想出來
def test(text):
print 'Buffer now holds', text
xinput(test)
運行它,然後鍵入Hellx←退格啊,世界顯示:
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