我试图禁用stdin缓冲,以便读取ANSI代码\033[6n
的响应(应报告光标位置)。
我按照回答Setting smaller buffer size for sys.stdin?中的建议尝试了stdin_ub = os.fdopen(stdin.fileno(), 'rb', buffering=0)
,但程序仍然在第一次尝试阅读的第ch = stdin_ub.read(1)
行被阻止。当返回键入终端时,它会解锁,这表明stdin仍然是行缓冲的。
供参考,这里是完整的代码:
def getpos():
stdin_ub = os.fdopen(sys.stdin.fileno(), 'rb', buffering=0)
sys.stdout.write('\033[6n')
sys.stdout.flush()
ch, k, field = None, -1, [b'', b'']
while True:
#print('reading wait...')
ch = stdin_ub.read(1)
#print('reading OK')
if ch == b'[': k = 0
elif ch == b';': k = 1
elif ch == b'R': break
elif k >= 0: field[k] += ch
try:
return tuple(map(int, field))
except:
pass
我正在使用python 3.5.1
答案 0 :(得分:1)
诀窍是使用tty.setcbreak(sys.stdin.fileno(), termios.TCSANOW)
,然后在变量中通过termios.getattr
存储终端属性以恢复默认行为。设置cbreak
后,sys.stdin.read(1)
无缓冲。这也抑制了来自终端的ansi控制代码响应。
def getpos():
buf = ""
stdin = sys.stdin.fileno()
tattr = termios.tcgetattr(stdin)
try:
tty.setcbreak(stdin, termios.TCSANOW)
sys.stdout.write("\x1b[6n")
sys.stdout.flush()
while True:
buf += sys.stdin.read(1)
if buf[-1] == "R":
break
finally:
termios.tcsetattr(stdin, termios.TCSANOW, tattr)
# reading the actual values, but what if a keystroke appears while reading
# from stdin? As dirty work around, getpos() returns if this fails: None
try:
matches = re.match(r"^\x1b\[(\d*);(\d*)R", buf)
groups = matches.groups()
except AttributeError:
return None
return (int(groups[0]), int(groups[1]))
答案 1 :(得分:0)
不幸的是,没有便携的方法可以做到这一点。当从普通操作系统上的键盘读取时,底层IO系统是行缓冲的,例如Windows和Unix系列。
curses模块将提供一种几乎可移植的方式来控制线路规则,不幸的是它在Windows系统上不起作用。
如果可以使用它,则必须使用
curses.noecho()
curses.raw() # or curses.cbreak()
进入原始模式(通常应该设置回声)
和
curses.echo()
curses.noraw() # resp. curses.nocbreak()
恢复正常熟更多