raw_input
这样的方法,因为它会在继续执行之前等待用户的输入。有人知道如何在while循环中实现这个功能吗?
我希望能够在多个平台上运行,但如果不可能的话,我的主要开发目标是Linux。
raw_input
这样的方法,因为它会在继续执行之前等待用户的输入。您没有提到这是一个图形用户界面程序还是命令行程序,但大多数GUI框架都包括一种捕获和处理键盘输入的方式。例如,使用tkinter
(在Py3中),您可以绑定到特定事件,然后在函数中处理它。例如:
import tkinter as tk
def key_handler(event=None):
if event and event.keysym in ('s', 'p'):
'do something'
r = tk.Tk()
t = tk.Text()
t.pack()
r.bind('<Key>', key_handler)
r.mainloop()
以上方法,当您在文本窗口中输入文字时,key_handler
例程会在您按下每个(或几乎每个)按键时被调用。
您可以从终端运行以下示例进行测试:
import curses
screen = curses.initscr()
curses.noecho()
curses.cbreak()
screen.keypad(True)
try:
while True:
char = screen.getch()
if char == ord('q'):
break
elif char == curses.KEY_UP:
print('up')
elif char == curses.KEY_DOWN:
print('down')
elif char == curses.KEY_RIGHT:
print('right')
elif char == curses.KEY_LEFT:
print('left')
elif char == ord('s'):
print('stop')
finally:
curses.nocbreak(); screen.keypad(0); curses.echo()
curses.endwin()
使用keyboard
包,特别是在Linux上,不是一个恰当的解决方案,因为该包需要root权限才能运行。我们可以很容易地使用getkey包来实现这一点。这类似于C语言函数getchar。
安装它:
pip install getkey
然后使用它:
from getkey import getkey
while True: #Breaks when key is pressed
key = getkey()
print(key) #Optionally prints out the key.
break
def Ginput(str):
"""
Now, this function is like the native input() function. It can accept a prompt string, print it out, and when one key is pressed, it will return the key to the caller.
"""
print(str, end='')
while True:
key = getkey()
print(key)
return key
使用方法如下:
inp = Ginput("\n Press any key to continue: ")
print("You pressed " + inp)
这里提供一种跨平台的解决方案,支持阻塞和非阻塞方式,并且不需要任何外部库:
import contextlib as _contextlib
try:
import msvcrt as _msvcrt
# Length 0 sequences, length 1 sequences...
_ESCAPE_SEQUENCES = [frozenset(("\x00", "\xe0"))]
_next_input = _msvcrt.getwch
_set_terminal_raw = _contextlib.nullcontext
_input_ready = _msvcrt.kbhit
except ImportError: # Unix
import sys as _sys, tty as _tty, termios as _termios, \
select as _select, functools as _functools
# Length 0 sequences, length 1 sequences...
_ESCAPE_SEQUENCES = [
frozenset(("\x1b",)),
frozenset(("\x1b\x5b", "\x1b\x4f"))]
@_contextlib.contextmanager
def _set_terminal_raw():
fd = _sys.stdin.fileno()
old_settings = _termios.tcgetattr(fd)
try:
_tty.setraw(_sys.stdin.fileno())
yield
finally:
_termios.tcsetattr(fd, _termios.TCSADRAIN, old_settings)
_next_input = _functools.partial(_sys.stdin.read, 1)
def _input_ready():
return _select.select([_sys.stdin], [], [], 0) == ([_sys.stdin], [], [])
_MAX_ESCAPE_SEQUENCE_LENGTH = len(_ESCAPE_SEQUENCES)
def _get_keystroke():
key = _next_input()
while (len(key) <= _MAX_ESCAPE_SEQUENCE_LENGTH and
key in _ESCAPE_SEQUENCES[len(key)-1]):
key += _next_input()
return key
def _flush():
while _input_ready():
_next_input()
def key_pressed(key: str = None, *, flush: bool = True) -> bool:
"""Return True if the specified key has been pressed
Args:
key: The key to check for. If None, any key will do.
flush: If True (default), flush the input buffer after the key was found.
Return:
boolean stating whether a key was pressed.
"""
with _set_terminal_raw():
if key is None:
if not _input_ready():
return False
if flush:
_flush()
return True
while _input_ready():
keystroke = _get_keystroke()
if keystroke == key:
if flush:
_flush()
return True
return False
def print_key() -> None:
"""Print the key that was pressed
Useful for debugging and figuring out keys.
"""
with _set_terminal_raw():
_flush()
print("\\x" + "\\x".join(map("{:02x}".format, map(ord, _get_keystroke()))))
def wait_key(key=None, *, pre_flush=False, post_flush=True) -> str:
"""Wait for a specific key to be pressed.
Args:
key: The key to check for. If None, any key will do.
pre_flush: If True, flush the input buffer before waiting for input.
Useful in case you wish to ignore previously pressed keys.
post_flush: If True (default), flush the input buffer after the key was
found. Useful for ignoring multiple key-presses.
Returns:
The key that was pressed.
"""
with _set_terminal_raw():
if pre_flush:
_flush()
if key is None:
key = _get_keystroke()
if post_flush:
_flush()
return key
while _get_keystroke() != key:
pass
if post_flush:
_flush()
return key
您可以在while循环中使用key_pressed()
:
while True:
time.sleep(5)
if key_pressed():
break
while True:
time.sleep(5)
if key_pressed("\x00\x48"): # Up arrow key on Windows.
break
使用print_key()
查找特殊键:
>>> print_key()
# Press up key
\x00\x48
或者等待直到按下某个键:
>>> wait_key("a") # Stop and ignore all inputs until "a" is pressed.
get_pressed()
函数:import pygame
while True:
keys = pygame.key.get_pressed()
if (keys[pygame.K_LEFT]):
pos_x -= 5
elif (keys[pygame.K_RIGHT]):
pos_x += 5
elif (keys[pygame.K_UP]):
pos_y -= 5
elif (keys[pygame.K_DOWN]):
pos_y += 5
我正在寻找如何连续检测不同的按键,直到例如Ctrl + C
中断程序从而停止监听并相应不同的按键。
使用以下代码:
while True:
if keyboard.is_pressed("down"):
print("Reach the bottom!")
if keyboard.is_pressed("up"):
print("Reach the top!")
if keyboard.is_pressed("ctrl+c"):
break
如果我按下 向下箭头 或 向上箭头,它会导致程序不断地发送响应文本。我认为这是因为它在 while 循环中,即使你只按一次,它也会被触发多次(正如 doc 中所述,我在阅读后意识到了这一点)。
那时,我还没有去阅读文档,我尝试添加 time.sleep()
。
while True:
if keyboard.is_pressed("down"):
print("Reach the bottom!")
time.sleep(0.5)
if keyboard.is_pressed("up"):
print("Reach the top!")
time.sleep(0.5)
if keyboard.is_pressed("ctrl+c"):
break
这解决了垃圾邮件问题。
但是,这不是一个很好的方法,因为在箭头键上连续快速按下时,只会触发一次,而不是我按下的次数,因为程序将休眠0.5秒,意味着发生在那个0.5秒的“键盘事件”将不被计算。
所以,我继续阅读文档并想到在这部分中执行此操作的想法。
while True:
# Wait for the next event.
event = keyboard.read_event()
if event.event_type == keyboard.KEY_DOWN and event.name == 'down':
# do whatever function you wanna here
if event.event_type == keyboard.KEY_DOWN and event.name == 'up':
# do whatever function you wanna here
if keyboard.is_pressed("ctrl+c"):
break
现在,它运行得很好! 说实话,我没有深入研究过文档,以前用过,但我已经忘记了内容,如果您知道或找到任何更好的方法来执行类似的功能,请告诉我!
谢谢,祝您今天过得愉快!