使用 curses 立即检测用户输入
Use curses to detect user input immediately
我在 python2.7 中使用诅咒来控制机器人。我想用例如引导它w
键,告诉它应该前进。这是我的代码,去掉了所有机器人控制:
import curses
from time import sleep
if __name__ == "__main__":
shell = curses.initscr()
shell.nodelay(True)
while True:
key = shell.getch()
if key == 119:
print("key w pressed")
sleep(0.03)
这很好用,只是我必须按 enter 键才能识别密钥。所以我可以多次按下 w
,当我按下 enter 时,机器人会完全按照它应该做的去做,或者在这个例子中,文本 key w pressed
出现的次数与我按下它的次数一样多。但我希望这会立即发生,即不必按回车键。如何实现?
将 curses.cbreak()
添加到您的设置中,并在清理时调用 curses.nocbreak()
将终端恢复到可用状态。
您可以通过捕获 ctrl-c 作为异常来进行清理。例如:
try:
curses.cbreak()
while True:
key = shell.getch()
if key == 119:
print("key w pressed")
sleep(0.03)
except KeyboardInterrupt:
curses.nocbreak()
鉴于 OP 没有使用 window.keypad, calling either curses.raw or curses.cbreak 将给出(几乎)相同的结果以允许脚本读取未缓冲的字符。
调用curses.endwin()
is a more reliable way to restore things. Bear in mind that it is a wrapper around curses. curses simulates cbreak mode, setting the real terminal mode to raw. Calling curses.nocbreak
对真实终端模式无影响。
如果你调用 nocbreak
来清理而不是调用 endwin
,你将有额外的问题需要解决(参见 Clean up ncurses mess in terminal after a crash 例如),因为终端将处于原始模式(包括真正的 noecho
,这使得打字 stty sane^M
很痛苦)。
参考 endwin
、
的文档
A program should always call endwin before exiting or escaping from curses mode temporarily. This routine
o restores tty modes,
o moves the cursor to the lower left-hand corner of the
screen and
o resets the terminal into the proper non-visual mode.
如前所述,cbreak
和 raw
几乎 相同。主要区别在于程序如何响应键盘中断(如 ^C
)。如果您碰巧正在使用 ncurses,它会建立 signal handlers,它(对于 SIGINT
和 SIGTERM
)将调用 curses.endwin
。其他 curses 实现不会这样做,即使您的脚本调用 curses.endwin
也不确定它是否会按预期工作(因为 curses 倾向于调用不安全的流 I/O 函数,这些函数不能在信号处理程序)。
现有答案正确,cbreak()
将关闭缓冲输入模式,这意味着 getch()
将 return 立即按下一个键。
我建议使用 curses.wrapper()
函数。这将设置屏幕和缓冲,在这种情况下如何。但它也会捕获异常并确保终端在您的应用程序退出时 return 进入干净状态。了解一下 here
基于 OP 代码的示例是:
import curses
from time import sleep
def program_loop(stdscr):
while True:
key = stdscr.getch()
if key == 119:
print("key w pressed\r")
sleep(0.03)
if __name__ == "__main__":
curses.wrapper(program_loop)
我在 python2.7 中使用诅咒来控制机器人。我想用例如引导它w
键,告诉它应该前进。这是我的代码,去掉了所有机器人控制:
import curses
from time import sleep
if __name__ == "__main__":
shell = curses.initscr()
shell.nodelay(True)
while True:
key = shell.getch()
if key == 119:
print("key w pressed")
sleep(0.03)
这很好用,只是我必须按 enter 键才能识别密钥。所以我可以多次按下 w
,当我按下 enter 时,机器人会完全按照它应该做的去做,或者在这个例子中,文本 key w pressed
出现的次数与我按下它的次数一样多。但我希望这会立即发生,即不必按回车键。如何实现?
将 curses.cbreak()
添加到您的设置中,并在清理时调用 curses.nocbreak()
将终端恢复到可用状态。
您可以通过捕获 ctrl-c 作为异常来进行清理。例如:
try:
curses.cbreak()
while True:
key = shell.getch()
if key == 119:
print("key w pressed")
sleep(0.03)
except KeyboardInterrupt:
curses.nocbreak()
鉴于 OP 没有使用 window.keypad, calling either curses.raw or curses.cbreak 将给出(几乎)相同的结果以允许脚本读取未缓冲的字符。
调用curses.endwin()
is a more reliable way to restore things. Bear in mind that it is a wrapper around curses. curses simulates cbreak mode, setting the real terminal mode to raw. Calling curses.nocbreak
对真实终端模式无影响。
如果你调用 nocbreak
来清理而不是调用 endwin
,你将有额外的问题需要解决(参见 Clean up ncurses mess in terminal after a crash 例如),因为终端将处于原始模式(包括真正的 noecho
,这使得打字 stty sane^M
很痛苦)。
参考 endwin
、
A program should always call endwin before exiting or escaping from curses mode temporarily. This routine
o restores tty modes,
o moves the cursor to the lower left-hand corner of the
screen and
o resets the terminal into the proper non-visual mode.
如前所述,cbreak
和 raw
几乎 相同。主要区别在于程序如何响应键盘中断(如 ^C
)。如果您碰巧正在使用 ncurses,它会建立 signal handlers,它(对于 SIGINT
和 SIGTERM
)将调用 curses.endwin
。其他 curses 实现不会这样做,即使您的脚本调用 curses.endwin
也不确定它是否会按预期工作(因为 curses 倾向于调用不安全的流 I/O 函数,这些函数不能在信号处理程序)。
现有答案正确,cbreak()
将关闭缓冲输入模式,这意味着 getch()
将 return 立即按下一个键。
我建议使用 curses.wrapper()
函数。这将设置屏幕和缓冲,在这种情况下如何。但它也会捕获异常并确保终端在您的应用程序退出时 return 进入干净状态。了解一下 here
基于 OP 代码的示例是:
import curses
from time import sleep
def program_loop(stdscr):
while True:
key = stdscr.getch()
if key == 119:
print("key w pressed\r")
sleep(0.03)
if __name__ == "__main__":
curses.wrapper(program_loop)