纯 Python 从 stdin 读取退格键、DEL 和朋友?
Read backspace, DEL and friends from stdin in pure Python?
如果用 google backspace python stdin 左右,有很多 SO 结果和 none 解决了我的问题.它们都是关于退格字符是什么而不是如何获得它。
这是一个从 stdin
中读取单个按键的函数,由 提供:
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,但它似乎是跨平台的。
实施 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
效果很好,除了按退格键什么都不做,而且你不能移动光标(import readline; input()
允许你(至少在使用 GNU Readline 构建的 Python 上)) .
我明白实现这两个的最好方法可能是 curses
。我也明白 curses
破坏了这个模块的标准库性和跨平台性。
我正在寻找一种阅读方式 stdin
该模块针对 Pythons 2 和 3,但我可以接受仅针对 Python 3 的解决方案,因为人们确实需要停止使用 2。
如果你认为我因为想在没有 curses
的情况下这样做而发疯,那么,这就是重点。
原始模式下的终端驱动程序允许读取 BS ^H 和 DEL 字符。箭头键往往是 ESC 序列,而不是一个字节,除非你有类似 80 年代真正的 Wyse 终端的东西。预计 GNU readline 功能(如箭头键)不会在原始模式下工作,这意味着不要进行任何字符处理。
开发功能键映射器对于支持 ANSI/DEC 编写的应用程序的 VT100 样式终端是必要的,该应用程序假设 1 个键 = 1 个输入字节,有效地使用 Wyse 终端控制字符作为内部命令。
类似地通过写入输出,除非读取的输入字节被转换,也许通过管道转换为 od(1),您将如何看到非打印字符?
curses 库更多的是关于屏幕绘制和高效更新,它使用原始模式和 getch() 例程来允许菜单选项等,而无需点击 return。如果您只是简单地阅读键盘输入,则没有必要。
考虑使用 this recipe from ActiveState that is also this SO 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()
# then call getch() to get the input...
如果用 google backspace python stdin 左右,有很多 SO 结果和 none 解决了我的问题.它们都是关于退格字符是什么而不是如何获得它。
这是一个从 stdin
中读取单个按键的函数,由 提供:
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,但它似乎是跨平台的。
实施 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
效果很好,除了按退格键什么都不做,而且你不能移动光标(import readline; input()
允许你(至少在使用 GNU Readline 构建的 Python 上)) .
我明白实现这两个的最好方法可能是 curses
。我也明白 curses
破坏了这个模块的标准库性和跨平台性。
我正在寻找一种阅读方式 stdin
该模块针对 Pythons 2 和 3,但我可以接受仅针对 Python 3 的解决方案,因为人们确实需要停止使用 2。
如果你认为我因为想在没有 curses
的情况下这样做而发疯,那么,这就是重点。
原始模式下的终端驱动程序允许读取 BS ^H 和 DEL 字符。箭头键往往是 ESC 序列,而不是一个字节,除非你有类似 80 年代真正的 Wyse 终端的东西。预计 GNU readline 功能(如箭头键)不会在原始模式下工作,这意味着不要进行任何字符处理。
开发功能键映射器对于支持 ANSI/DEC 编写的应用程序的 VT100 样式终端是必要的,该应用程序假设 1 个键 = 1 个输入字节,有效地使用 Wyse 终端控制字符作为内部命令。
类似地通过写入输出,除非读取的输入字节被转换,也许通过管道转换为 od(1),您将如何看到非打印字符?
curses 库更多的是关于屏幕绘制和高效更新,它使用原始模式和 getch() 例程来允许菜单选项等,而无需点击 return。如果您只是简单地阅读键盘输入,则没有必要。
考虑使用 this recipe from ActiveState that is also this SO 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()
# then call getch() to get the input...