如何检测按键?

我正在用 Python 编写一个秒表类型的程序,我想知道如何检测一个键是否被按下(比如 p表示暂停,s表示停止) ,我不希望它像 raw_input那样,在继续执行之前等待用户的输入。

有人知道在 while 循环中怎么做吗?

我希望使这个跨平台,但是,如果这是不可能的,那么我的主要开发目标是 Linux。

766806 次浏览

使用 PyGame 创建一个窗口,然后就可以获得关键事件。

字母 p:

import pygame, sys
import pygame.locals


pygame.init()
BLACK = (0,0,0)
WIDTH = 1280
HEIGHT = 1024
windowSurface = pygame.display.set_mode((WIDTH, HEIGHT), 0, 32)


windowSurface.fill(BLACK)


while True:
for event in pygame.event.get():
if event.key == pygame.K_p: # replace the 'p' to whatever key you wanted to be pressed
pass #Do what you want to here
if event.type == pygame.locals.QUIT:
pygame.quit()
sys.exit()

正如 OP 提到的 raw _ input-这意味着他想要 cli 解决方案。 Linux: 诅咒是您想要的(windows PDCurses)。诅咒,是一个图形化的 API 为 cli 软件,可以实现的不仅仅是检测关键事件。

此代码将检测键,直到按下新行为止。

import curses
import os


def main(win):
win.nodelay(True)
key=""
win.clear()
win.addstr("Detected key:")
while 1:
try:
key = win.getkey()
win.clear()
win.addstr("Detected key:")
win.addstr(str(key))
if key == os.linesep:
break
except Exception as e:
# No input
pass


curses.wrapper(main)

对于 窗户,你可以这样使用 msvcrt:

   import msvcrt
while True:
if msvcrt.kbhit():
key = msvcrt.getch()
print(key)   # just to show the result

Python 有一个具有许多特性的 < strong > 键盘 模块:

pip3 install keyboard

然后在代码中使用它,比如:

import keyboard  # using module keyboard
while True:  # making a loop
try:  # used try so that if user pressed other than the given key error will not be shown
if keyboard.is_pressed('q'):  # if key 'q' is pressed
print('You Pressed A Key!')
break  # finishing the loop
except:
break  # if user pressed a key other than the given key the loop will break

对于那些站在窗户上,努力寻找工作答案的人来说,我的答案是: 输入

from pynput.keyboard import Key, Listener


def on_press(key):
print('{0} pressed'.format(
key))


def on_release(key):
print('{0} release'.format(
key))
if key == Key.esc:
# Stop listener
return False


# Collect events until released
with Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()

上面的函数将打印您正在按下的任何键,并在您释放“ esc”键时启动一个操作。键盘文档是 给你,用法更为多样。

Markus von Broady 强调了一个潜在的问题,那就是: 这个答案不需要你在当前窗口中激活这个脚本,一个窗口的解决方案是:

from win32gui import GetWindowText, GetForegroundWindow
current_window = (GetWindowText(GetForegroundWindow()))
desired_window_name = "Stopwatch" #Whatever the name of your window should be


#Infinite loops are dangerous.
while True: #Don't rely on this line of code too much and make sure to adapt this to your project.
if current_window == desired_window_name:


with Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()

我根据这篇文章(使用 msvcr 库和 Python 3.7)制作了这种游戏。

以下是游戏的主要功能,即检测按下的键:

import msvcrt


def _secret_key(self):
# Get the key pressed by the user and check if he/she wins.


bk = chr(10) + "-"*25 + chr(10)


while True:
print(bk + "Press any key(s)" + bk)
#asks the user to type any key(s)


kp = str(msvcrt.getch()).replace("b'", "").replace("'", "")
# Store key's value.


if r'\xe0' in kp:
kp += str(msvcrt.getch()).replace("b'", "").replace("'", "")
# Refactor the variable in case of multi press.


if kp == r'\xe0\x8a':
# If user pressed the secret key, the game ends.
# \x8a is CTRL+F12, that's the secret key.


print(bk + "CONGRATULATIONS YOU PRESSED THE SECRET KEYS!\a" + bk)
print("Press any key to exit the game")
msvcrt.getch()
break
else:
print("    You pressed:'", kp + "', that's not the secret key(s)\n")
if self.select_continue() == "n":
if self.secondary_options():
self._main_menu()
break

如果你想要的程序的完整源代码,你可以看到它或下载它 来自 GitHub

秘密按键是:

Ctrl + F12

使用此代码查找所按的键

from pynput import keyboard


def on_press(key):
try:
print('alphanumeric key {0} pressed'.format(
key.char))
except AttributeError:
print('special key {0} pressed'.format(
key))


def on_release(key):
print('{0} released'.format(
key))
if key == keyboard.Key.esc:
# Stop listener
return False


# Collect events until released
with keyboard.Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
import cv2


key = cv2.waitKey(1)

这是从 OpenCV包。delay参数是它等待按键的毫秒数。在这种情况下,1毫秒。根据文件pollKey()无需等待即可使用。

更多的事情可以做与 keyboard模块。 可以使用 pip install keyboard安装此模块 以下是一些方法:


方法一:

使用函数 强 > read_key():

import keyboard


while True:
if keyboard.read_key() == "p":
print("You pressed p")
break

这会在按下键 p时打破循环。


方法二:

使用函数 强 > wait:

import keyboard


keyboard.wait("p")
print("You pressed p")

它将等待您按下 p并在按下时继续代码。


方法三:

使用函数 强 > on_press_key:

import keyboard


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

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

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

keyboard.unhook_all()

方法四:

这个方法已经被 User8167727回答过了,但是我不同意他们编写的代码。它将以另一种方式使用函数 强 > is_pressed:

import keyboard


while True:
if keyboard.is_pressed("p"):
print("You pressed p")
break

它将在按下 p时中断循环。


方法五:

你也可以使用 强 > keyboard.record。它记录所有按下和释放的键,直到按下 escape键或在 until arg 中定义的键,并返回一个 keyboard.KeyboardEvent元素列表。

import keyboard


keyboard.record(until="p")
print("You pressed p")

备注:

  • keyboard将从整个操作系统中读取按键。
  • keyboard需要 Linux 上的 root 用户

您没有提到这是否是一个 GUI 程序,但是大多数 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()

使用上面的代码,当您键入 Text 小部件时,将为您按下的每个(或几乎每个)键调用 key_handler例程。

新发展公司对这个问题本身的评论可能很容易被忽略,但是它链接到了一个在这里的任何答案中都没有提到的解决方案。

使用此解决方案不需要导入 keyboard

解决方案从 另一个问题拷贝,所有学分到@neDev。

这在 macOS Sierra 和 Python 2.7.10和3.6.3上对我很有用

import sys,tty,os,termios
def getkey():
old_settings = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin.fileno())
try:
while True:
b = os.read(sys.stdin.fileno(), 3).decode()
if len(b) == 3:
k = ord(b[2])
else:
k = ord(b)
key_mapping = {
127: 'backspace',
10: 'return',
32: 'space',
9: 'tab',
27: 'esc',
65: 'up',
66: 'down',
67: 'right',
68: 'left'
}
return key_mapping.get(k, chr(k))
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
try:
while True:
k = getkey()
if k == 'esc':
quit()
else:
print(k)
except (KeyboardInterrupt, SystemExit):
os.system('stty sane')
print('stopping.')

使用 keyboard包,尤其是在 Linux 上,不是一个合适的解决方案,因为该包需要 root 权限才能运行。我们可以很容易地用 获取密钥包实现这一点。这类似于 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 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()

即使通过 ssh 也可以工作的非根版本: 嘘,键盘,

然后写剧本,比如:

from sshkeyboard import listen_keyboard


def press(key):
print(f"'{key}' pressed")


def release(key):
print(f"'{key}' released")


listen_keyboard(
on_press=press,
on_release=release,
)

它会印刷:

'a' pressed
'a' released

按下 A键时,默认情况下 ESC键结束侦听。

它需要的代码比例如诅咒,tkinter 和 getch 更少。而且它不需要像键盘模块那样的 root 访问。

你可以使用 玩具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

下面是一个跨平台的解决方案,包括阻塞和非阻塞,不需要任何外部库:

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.