如何在 Linux 终端上进行按键检测,python 中的低级样式

mam*_*ama 7 python linux keypress low-level python-os

我刚刚在 python 中实现了一个 Linux 命令外壳,仅使用os库的低级系统调用,诸如此类fork()

我想知道如何实现一个键侦听器,该侦听器将侦听键 (UP|DOWN) 以滚动浏览我的 shell 的历史记录。

我想在不使用任何花哨的库的情况下做到这一点,但我也希望这不是超级复杂的事情。到目前为止,我的代码只有大约 100 行代码,我不想为了获得一个简单的功能而创建一个怪物:D

我对这个问题的想法是,应该可以创建一个带有某种循环的子进程,它将侦听 up^[[A和 down ^[[B,按键,然后以某种方式将文本放入我的输入字段,就像一个普通终端。

到目前为止,我最感兴趣的是 key-listener 的可能性。但接下来我可能必须弄清楚如何将该文本输入到输入字段中。关于这一点,我想我可能必须使用提供的一些stdin功能sys

我只对让它在 Linux 上运行感兴趣,并希望继续使用低级系统调用,最好不是为我处理所有事情的 Python 库。这是一个学习练习。

Git*_*ont 8

默认情况下,标准输入被缓冲并使用规范模式。这允许您编辑您的输入。当你按下回车键时,输入可以被 Python 读取。

如果您想对输入进行较低级别的访问,则可以tty.setraw()在标准输入文件描述符上使用。这允许您使用 一次读取一个字符sys.stdin.read(1)。请注意,在这种情况下,Python 脚本将负责处理特殊字符,您将失去一些功能,如字符回显和删除。有关更多信息,请查看termios(3)

您可以在 Wikipedia 上阅读有关用于向上和向下键的转义序列

如果您在一个进程中处理所有事情,您应该能够复制标准 shell 行为。

您可能还想尝试使用子流程(不是指模块 - 您可以使用fork()popen())。您将解析主进程中未缓冲的输入并将其发送到子进程的标准输入(可以缓冲)。您可能需要进行一些进程间通信以与主进程共享历史记录。

这是以这种方式捕获输入所需的代码示例。请注意,它仅进行一些基本处理,需要更多工作才能适合您的用例。

import sys
import tty
import termios


def getchar():
    fd = sys.stdin.fileno()
    attr = termios.tcgetattr(fd)
    try:
        tty.setraw(fd)
        return sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSANOW, attr)


EOT = '\x04'  # CTRL+D
ESC = '\x1b'
CSI = '['

line = ''

while True:
    c = getchar()
    if c == EOT:
        print('exit')
        break
    elif c == ESC:
        if getchar() == CSI:
            x = getchar()
            if x == 'A':
                print('UP')
            elif x == 'B':
                print('DOWN')
    elif c == '\r':
        print([line])
        line = ''
    else:
        line += c
Run Code Online (Sandbox Code Playgroud)