Python, "filtered"行编辑,通过字符读取标准输入,无回显

标签 python readline curses

我需要一个像 raw_input() 那样将输入读入缓冲区的函数,但不是回显输入并阻塞直到返回整行,它应该抑制回显并调用回调每次缓冲区发生变化时

我说“缓冲区更改”而不是“字符被读取”是因为,作为 raw_input(),我希望它能够识别特殊键。例如,退格键应该起作用。

例如,如果我想使用回调来模拟输入的大写回显,代码将如下所示:

def callback(text):
    print '\r' + text.upper()

read_input(callback)

我怎样才能做到这一点?

注意: 我一直在尝试使用 readlinecurses 来达到我的目的,但是这两个 Python 绑定(bind)都不完整。 curses 无法在不清除整个屏幕的情况下启动,并且 readline 在任何输入开始之前提供了一个钩子(Hook)。

最佳答案

好吧,我手写了代码。我会留下解释以供将来引用。

要求

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)

完成后执行清理很重要,否则终端可能需要重置

解码标准输入

仅读取标准输入的第二个问题是编码。非 ascii unicode 字符将逐字节到达我们,这是完全不可取的。

为了正确解码标准输入,我写了一个生成器,我们可以为 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')

除了可打印文件,目前我只想处理 ← 退格键CtrlD 序列:

def is_backspace(c):
    return c in ('\x08','\x7F')

def is_interrupt(c):
    return c == '\x04'

放在一起:xinput()

一切就绪。我想要的功能的原始契约(Contract)是读取输入、处理特殊字符、调用回调。实现反射(reflect)了这一点:

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← backspaceo World 显示:

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

关于Python, "filtered"行编辑,通过字符读取标准输入,无回显,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15992651/

相关文章:

c - 如何使光标像 curses/C 中的文本编辑器/终端一样工作?

python - _curses.error : add_wch() returned an error

python - get_absolute_url 问题。错误捕获 ViewDoesNotExist

python - 运行时错误 : Optimal parameters not found: Number of calls to function has reached maxfev = 800

c - 尝试使用已安装的开发人员工具进行编译时,找不到 editline/history.h 和 editline/readline.h/在 macOS 上工作

python - Shift + Return 在 python 中插入换行符

javascript - vt100 应用程序的 Node.js/Angular 包装器

python - 有什么办法可以让这个函数看起来更好看吗?

python - 如何等待 iframe 使用 phantomjs 在 selenium python 中加载

c# - 读取文件中的特定行