如何在Linux终端上进行按键检测,python的低级风格

2024-05-08 05:20:56 发布

您现在位置:Python中文网/ 问答频道 /正文

我刚刚用python实现了一个Linux命令shell,只使用了os库的低级系统调用,比如fork()等等

我想知道如何实现一个键侦听器,它将侦听键(向上|向下)以滚动我的shell的历史记录

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

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

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

我只对让它在Linux上工作感兴趣,并且希望继续使用低级系统调用,最好不要使用为我处理一切的Python库。这是一个学习练习


Tags: 代码文本命令历史记录oslinux系统情况
2条回答

Python有一个keyboard模块,具有许多特性。安装它,可能需要使用以下命令:

pip install keyboard

然后在如下代码中使用它:

import keyboard

keyboard.add_hotkey('up', lambda: keyboard.write('write command retrieved from the history of your shell here'))
keyboard.wait('esc')

或者您可以使用按键上的功能 使用\上的功能按\键:

keyboard.on_press_key("p", lambda _:print("You pressed p"))

它需要一个回调函数。我使用了u,因为键盘函数将键盘事件返回给该函数

一旦执行,它将在按键时运行该功能。通过运行以下命令行,可以停止所有挂钩:

keyboard.unhook_all()

有关详细信息,您可以在stackoverflow上看到类似的帖子,希望这对您有所帮助 detect key press in python?

旁注: 您在python中提到了fork()方法,我们可以使用

子流程这里内置了模块,所以导入子流程,我们就可以开始了。这里特别使用run函数来执行子shell中的命令。对于那些来自C语言的人来说,这使我们不必进行分叉和创建子进程,然后等待子进程完成执行,让Python来处理这一次

用于执行用户输入的命令的示例代码

def execute_commands(command):
    try:
        subprocess.run(command.split())
    except Exception:
        print("psh: command not found: {}".format(command))

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

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

你可以在维基百科上阅读关于escape sequences的信息,这些信息用于up and down keys

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

您可能还希望尝试使用子流程(不引用模块-您可以使用fork()popen())。您将在主进程中解析未缓冲的输入,并将其发送到子进程的stdin(可以缓冲)。您可能需要进行一些进程间通信,以便与主进程共享历史

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

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

相关问题 更多 >