在python中检测按键?


102

我正在用python开发一个秒表类型的程序,我想知道如何检测是否按下了一个键(例如p表示暂停,s表示停止),而我不希望它像raw_input这样等待用户输入,然后继续执行。有人知道如何在while循环中执行此操作吗?

另外,我想做这个跨平台的,但是如果那不可能,那么我的主要开发目标是linux


for OS X stackoverflow.com/a/47197390/5638869可在Python 2和3中使用
neoDev

Answers:


68

Python有一个具有许多功能的键盘模块。安装它,也许使用以下命令:

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

1
我不确定使用linux,但对我来说它可以在Windows上使用。

71
keyboard显然需要在Linux中使用root:/
Inaimathi

我尝试了此解决方案,但是在安装模块后尝试导入该模块时,出现“ ImportError:没有名为'keyboard'的模块”,因此它不起作用。我检查了GitHub存储库,发现了一个相关的问题,但是并不能解决我的问题。然后,我尝试下载该存储库并执行其一些示例,但正如@Inaimathi之前所述,我得到了和“ ImportError:您必须是root用户才能在Linux上使用此库”。显然,这似乎是使用Python管理键盘的完整模块,但是对root的需求却非常缺乏:(
Ivanhercaz

3
“为避免依赖X,Linux部件读取原始设备文件(/ dev / input / input *),但这需要root。”
jrouquie

7
我不明白为什么try:except:会有用。
典型的Hog

48

对于那些在窗户上努力寻找可行答案的人,我的是:pynput

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)强调了一个潜在的问题,即:这个答案并不需要您在当前窗口中激活此脚本,Windows的解决方案是:

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()

7
@ nimig18 ...并且不需要root :)
cz

1
该解决方案存在一个问题(不确定替代方案):不必在控制台窗口中按下该键即可生效。想象一下,有一个脚本在按下ESC之前会做一些工作,但是随后您在另一个程序中按下了它。
Markus von Broady

1
@MarkusvonBroady我想win32gui足以解决它,我以一种可能至少对Windows用户有可能解决它的方式编辑了我的答案。
Mitrek

@Mitrek我尝试了这个,但是我的代码停止了进一步的执行,并停留在这里。它的工作方式类似于input()。我在selenium,firefox中执行了代码,但是一旦遇到此序列,就没有进一步的操作了。
Lakshmi Narayanan

1
应该已经被接受的答案,因为它在Linux和Windows中都可以工作
Akash Karnatak

31

正如OP关于raw_input的提及-这意味着他想要cli解决方案。Linux:curses是您想要的(Windows PDCurses)。Curses是cli软件的图形API,您不仅可以检测关键事件,还可以实现更多目标。

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

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)

真的很好 不得不永远搜索之前遇到它。似乎比乱砍termios等等更干净……
休·帕金斯

5
需要添加import os才能退出示例。
Malte

如果您选择win.nodelay(False)而不是True,则每秒将不会产生一百万个异常。
Johannes Hoff

24

使用keyboard模块可以做更多的事情。

以下是一些方法:


方法1:

使用功能read_key()

import keyboard

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

p按下该键将打破循环。


方法2:

使用功能wait

import keyboard

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

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


方法3:

使用功能on_press_key

import keyboard

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

它需要一个回调函数。我_之所以使用,是因为键盘功能将键盘事件返回到该功能。

一旦执行,当按下键时它将运行该功能。您可以通过运行以下行来停止所有挂钩:

keyboard.unhook_all()

方法4:

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

import keyboard

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

p按下将打破循环。


笔记:

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

11
使用键盘模块的最大缺点是它要求您以ROOT用户身份运行。这使模块在我的代码中成为僵尸。仅轮询是否已按下键并不需要root特权。我已经阅读了文档,并理解了为什么限制会在模块中退出,但是如果您只需要轮询一个键,
就去

先生,非常有用的信息共享!我想知道我是否可以keyboard.wait()等待超过1个按键,并在按下其中任何一个按键时继续操作
Preetkaran Singh,

@PreetkaranSingh wait()没有提供此功能。您将不得不将keyboard.read_key()if条件包装在while循环中。请参阅方法#1
Black Thunder

谢谢先生!,您想了解一下suppress关键字的用法keyboard.read_key(),何时使用以及何时不使用....
Preetkaran Singh,

@PreetkaranSingh我愿意,但是我没有关于抑制论点的足够信息
Black Thunder

13

对于Windows,您可以这样使用msvcrt

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

7
msvcrt是仅Windows模块。
Dunatotatos '16

1
其实,我现在用pynput,这可能是一个更好的答案
Benjie

请注意,在OS X(不了解Linux)上运行的pynput必须以root用户身份运行才能正常工作。对于某些人来说,这可能不是一个开始。
·魏斯

我可能宣誓要问的问题是“跨平台”还是“ Linux” ...
Aaron Mann

10

使用此代码查找按下了哪个键

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()

不过,这里是事情,我使用macOS并分别安装了Pynput和键盘,并且程序运行时没有任何错误,但只能检测(在python shell上)特殊键。字母数字键未检测到,相反,就好像我在外壳上写代码一样。您知道可能是什么问题吗?
Dario DenizErgün19年

相同的代码在shell中对我有用。请检查一下。键盘包装不需要此代码。
Manivannan Murugavel

1
这是在Linux中使用的方法,因为键盘lib需要root。
大卫,

1
该解决方案将检测所有击键;还有那些发生在不同终端窗口中的事件。不幸的是,这严重限制了其可能的用例。
Serge Stroobandt

6

使用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()

2

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

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

# Requiered libraries - - - -
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

如果您想要该porgram的完整源代码,则可以在这里查看或下载它:

秘钥游戏(GitHub)

(注意:秘密按键为:Ctrl+ F12

我希望您可以作为一个例子,并为那些来此信息的人提供帮助。



1
key = cv2.waitKey(1)

这是来自openCV软件包。它无需等待即可检测到按键。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.