python - 如何在 Linux 终端上进行按键检测,python 中的低级样式
问题描述
我刚刚在 python 中实现了一个 Linux 命令 shell,只使用os
库的低级系统调用,诸如此类fork()
。
我想知道如何实现一个键侦听器,它将侦听键 (UP|DOWN) 以滚动浏览我的 shell 的历史记录。
我想在不使用任何花哨的库的情况下做到这一点,但我也希望这不是超级复杂的事情。到目前为止,我的代码只有大约 100 行代码,我不想为了获得一个简单的功能而创建一个怪物:D
我对这个问题的想法是,应该可以创建一个带有某种循环的子进程,它将监听 up^[[A
和 down ^[[B
,按键,然后以某种方式将文本放入我的输入字段,就像普通终端一样。
到目前为止,我最感兴趣的是关键听众的可能性。但接下来我可能不得不弄清楚如何将文本输入输入字段。关于这一点,我在想我可能必须使用提供的一些stdin
功能sys
。
我只对让它在 Linux 上运行感兴趣,并希望继续使用低级系统调用,最好不要使用为我处理所有事情的 Python 库。这是一个学习练习。
解决方案
默认情况下,标准输入被缓冲并使用规范模式。这允许您编辑您的输入。当您按下回车键时,Python 可以读取输入。
如果您想要对输入进行较低级别的访问,您可以tty.setraw()
在标准输入文件描述符上使用。这允许您使用 . 一次读取一个字符sys.stdin.read(1)
。请注意,在这种情况下,Python 脚本将负责处理特殊字符,您将失去一些功能,例如字符回显和删除。有关更多信息,请查看termios(3)。
您可以在 Wikipedia 上阅读有关用于向上和向下键的转义序列。
如果您在一个进程中处理所有事情,您应该能够复制标准的 shell 行为。
您可能还想尝试使用子进程(不是指模块 - 您可以使用fork()
or 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
推荐阅读
- sql - 无法删除系统生成的序列
- android - 如何从 Activity 更新导航标题中的 TextView?
- ruby-on-rails - 如果日期等于今天或将来,则从 postgres 渲染事件
- spring-boot - 在属性文件中禁用 Envers
- c# - 移植出队 - 将循环从 C# 添加到 F#
- google-apps-script - 从谷歌表格中获取时间和时间
- 3d - 如何在 GDScript 中旋转移动对象以聚焦于另一个移动对象?
- django - UnboundLocalError - 赋值前引用的局部变量 'ret'
- reactjs - ReactJS 为什么我需要在这段代码中使用静态函数(Newbee)
- python - 在 Python 中制作 x,y,z 数据的热图