如何在 Linux 终端上进行按键检测,python 中的低级样式
How to key press detection on a Linux terminal, low level style in python
我刚刚在 python 中实现了 Linux 命令 shell,仅使用 os
库的低级系统调用,如 fork()
等。
我想知道如何实现一个按键侦听器来侦听键 (UP|DOWN) 以滚动浏览我的 shell.
的历史记录
我想在不使用任何花哨的库的情况下做到这一点,但我也希望这不是超级复杂的事情。到目前为止,我的代码只有大约 100 行代码,我不想为了获得一个简单的功能而创建一个怪物 :D
我对这个问题的想法是,应该可以创建一个带有某种循环的子进程,它将监听向上 ^[[A
和向下 ^[[B
、按键和然后以某种方式将文本放入我的输入字段,就像普通终端一样。
目前为止我最感兴趣的是key-listener的可能性。但接下来我可能必须弄清楚如何将该文本输入到输入字段中。关于这一点,我在想我可能必须使用 sys
提供的一些 stdin
功能。
我只对让它在 Linux 上运行感兴趣,并希望继续使用低级系统调用,最好不要 Python 为我处理所有事情的库。这是一个学习练习。
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')
或者您可以使用函数 on_press_key
使用函数 on_press_key:
keyboard.on_press_key("p", lambda _:print("You pressed p"))
需要回调函数。我使用 _ 因为键盘功能 returns 该功能的键盘事件。
一旦执行,就会运行按键时的功能。您可以通过 运行 宁此行来停止所有挂钩:
keyboard.unhook_all()
有关详细信息,您可以在 Whosebug 上查看类似的 post,希望对您有所帮助
detect key press in python?
边注:
你在上面提到了 fork() 方法在 python 中我们可以使用
subprocess 内置模块在这里,所以导入 subprocess 我们就可以开始了。 运行 函数在这里特别用于在子 shell 中执行命令。对于那些来自 C 的人,这使我们免于分叉和创建子进程,然后等待子进程完成执行,让 Python 处理这一次。
执行用户输入命令的示例代码
def execute_commands(command):
try:
subprocess.run(command.split())
except Exception:
print("psh: command not found: {}".format(command))
默认情况下,标准输入被缓冲并使用规范模式。这允许您编辑您的输入。当你按下回车键时,输入可以读取Python。
如果您想要对输入进行较低级别的访问,您可以在标准输入文件描述符上使用 tty.setraw()
。这允许您使用 sys.stdin.read(1)
一次读取一个字符。请注意,在这种情况下,Python 脚本将负责处理特殊字符,您将失去一些功能,如字符回显和删除。有关详细信息,请查看 termios(3).
您可以在维基百科上阅读有关 escape sequences which are used for up and down keys 的内容。
如果您在一个流程中处理所有事情,您应该能够复制标准 shell 行为。
您可能还想尝试使用子进程(不是指模块 - 您可以使用 fork()
或 popen()
)。您将在主进程中解析未缓冲的输入并将其发送到子进程的标准输入(可以缓冲)。您可能需要进行一些 inter-process 通信才能与主进程共享历史记录。
这是以这种方式捕获输入所需的代码示例。请注意,它仅进行一些基本处理,需要更多工作才能适合您的 use-case.
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
我刚刚在 python 中实现了 Linux 命令 shell,仅使用 os
库的低级系统调用,如 fork()
等。
我想知道如何实现一个按键侦听器来侦听键 (UP|DOWN) 以滚动浏览我的 shell.
的历史记录我想在不使用任何花哨的库的情况下做到这一点,但我也希望这不是超级复杂的事情。到目前为止,我的代码只有大约 100 行代码,我不想为了获得一个简单的功能而创建一个怪物 :D
我对这个问题的想法是,应该可以创建一个带有某种循环的子进程,它将监听向上 ^[[A
和向下 ^[[B
、按键和然后以某种方式将文本放入我的输入字段,就像普通终端一样。
目前为止我最感兴趣的是key-listener的可能性。但接下来我可能必须弄清楚如何将该文本输入到输入字段中。关于这一点,我在想我可能必须使用 sys
提供的一些 stdin
功能。
我只对让它在 Linux 上运行感兴趣,并希望继续使用低级系统调用,最好不要 Python 为我处理所有事情的库。这是一个学习练习。
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')
或者您可以使用函数 on_press_key 使用函数 on_press_key:
keyboard.on_press_key("p", lambda _:print("You pressed p"))
需要回调函数。我使用 _ 因为键盘功能 returns 该功能的键盘事件。
一旦执行,就会运行按键时的功能。您可以通过 运行 宁此行来停止所有挂钩:
keyboard.unhook_all()
有关详细信息,您可以在 Whosebug 上查看类似的 post,希望对您有所帮助 detect key press in python?
边注: 你在上面提到了 fork() 方法在 python 中我们可以使用
subprocess 内置模块在这里,所以导入 subprocess 我们就可以开始了。 运行 函数在这里特别用于在子 shell 中执行命令。对于那些来自 C 的人,这使我们免于分叉和创建子进程,然后等待子进程完成执行,让 Python 处理这一次。
执行用户输入命令的示例代码
def execute_commands(command):
try:
subprocess.run(command.split())
except Exception:
print("psh: command not found: {}".format(command))
默认情况下,标准输入被缓冲并使用规范模式。这允许您编辑您的输入。当你按下回车键时,输入可以读取Python。
如果您想要对输入进行较低级别的访问,您可以在标准输入文件描述符上使用 tty.setraw()
。这允许您使用 sys.stdin.read(1)
一次读取一个字符。请注意,在这种情况下,Python 脚本将负责处理特殊字符,您将失去一些功能,如字符回显和删除。有关详细信息,请查看 termios(3).
您可以在维基百科上阅读有关 escape sequences which are used for up and down keys 的内容。
如果您在一个流程中处理所有事情,您应该能够复制标准 shell 行为。
您可能还想尝试使用子进程(不是指模块 - 您可以使用 fork()
或 popen()
)。您将在主进程中解析未缓冲的输入并将其发送到子进程的标准输入(可以缓冲)。您可能需要进行一些 inter-process 通信才能与主进程共享历史记录。
这是以这种方式捕获输入所需的代码示例。请注意,它仅进行一些基本处理,需要更多工作才能适合您的 use-case.
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