détecter une pression sur une touche en python?

104

Je crée un programme de type chronomètre en python et j'aimerais savoir comment détecter si une touche est enfoncée (comme p pour pause et s pour stop), et je n'aimerais pas que ce soit quelque chose comme raw_input qui attend le entrée de l'utilisateur avant de poursuivre l'exécution. Quelqu'un sait comment faire cela dans une boucle while?

Aussi, j'aimerais créer cette multiplateforme, mais si ce n'est pas possible, ma principale cible de développement est linux

lobuo
la source
pour OS X stackoverflow.com/a/47197390/5638869 fonctionne en Python 2 et 3
neoDev

Réponses:

69

Python a un module clavier avec de nombreuses fonctionnalités. Installez-le, peut-être avec cette commande:

pip3 install keyboard

Ensuite, utilisez-le dans du code comme:

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
Communauté
la source
1
Je ne suis pas sûr pour Linux mais cela fonctionne sur Windows pour moi.
72
keyboardnécessite apparemment la racine sous linux: /
Inaimathi
J'ai essayé cette solution mais quand j'essaye d'importer le module après l'avoir installé, j'obtiens un "ImportError: No module named 'keyboard'", donc ça n'a pas fonctionné. J'ai vérifié dans le dépôt GitHub et je trouve un problème connexe , mais cela ne me résout pas le problème. Ensuite, j'ai essayé de télécharger le référentiel et d'exécuter certains de ses exemples, mais j'obtiens un message "ImportError: vous devez être root pour utiliser cette bibliothèque sous Linux", comme @Inaimathi l'a déjà commenté. Apparemment, cela semble un module complet pour gérer le clavier avec Python, mais l'exigence de root est un gros manque :(
Ivanhercaz
3
"Pour éviter de dépendre de X, la partie Linux lit les fichiers bruts de périphérique (/ dev / input / input *) mais cela nécessite la racine."
jrouquie
7
Je ne vois pas pourquoi essayer: sauf: serait utile.
TypiqueHog
49

Pour ceux qui sont sous windows et qui ont du mal à trouver une réponse fonctionnelle, voici la mienne: 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()

La fonction ci-dessus imprime la touche sur laquelle vous appuyez et lance une action lorsque vous relâchez la touche «esc». La documentation du clavier est ici pour une utilisation plus variée.

Markus von Broady a mis en évidence un problème potentiel qui est: Cette réponse ne nécessite pas que vous soyez dans la fenêtre actuelle pour que ce script soit activé, une solution aux fenêtres serait:

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()
Mitrek
la source
7
@ nimig18 ... et ne nécessite pas de root :)
cz
1
Il y a un problème avec cette solution (pas sûr des alternatives): il n'est pas nécessaire d'appuyer sur la touche dans une fenêtre de console pour qu'elle prenne effet. Imaginez avoir un script qui fait un travail jusqu'à ce que vous appuyiez sur ESC, mais ensuite vous appuyez dessus dans un autre programme.
Markus von Broady le
1
@MarkusvonBroady Je suppose que win32gui suffirait à le résoudre, j'ai modifié ma réponse de manière à la résoudre au moins pour les utilisateurs de Windows.
Mitrek
@Mitrek J'ai essayé cela, mais mon code arrête toute exécution supplémentaire et est bloqué ici. Cela fonctionne comme input (). J'ai le code en cours d'exécution dans sélénium, Firefox, mais dès que cette séquence est rencontrée, il n'y a plus d'action.
Lakshmi Narayanan
1
Cela aurait dû être la réponse acceptée, car cela fonctionne à la fois sous Linux et Windows
Akash Karnatak
31

Comme OP le mentionne à propos de raw_input - cela signifie qu'il veut une solution cli. Linux: les malédictions sont ce que vous voulez (windows PDCurses). Curses, est une API graphique pour le logiciel cli, vous pouvez réaliser plus que simplement détecter les événements clés.

Ce code détectera les touches jusqu'à ce qu'une nouvelle ligne soit pressée.

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)
Abc Xyz
la source
C'est vraiment sympa. J'ai dû chercher une éternité avant de le trouver. Cela semble beaucoup plus propre que de pirater avec termioset ainsi de suite ...
Hugh Perkins
5
nécessaire pour ajouter import osafin de pouvoir quitter quitter l'exemple.
malte
Si vous le faites à la win.nodelay(False)place True, cela ne générera pas un million d'exceptions par seconde.
Johannes Hoff le
24

Il y a plus de choses qui peuvent être faites avec keyboardmodule.

Voici quelques méthodes:


Méthode n ° 1:

Utilisation de la fonction read_key():

import keyboard

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

Cela va casser la boucle lorsque la touche pest enfoncée.


Méthode n ° 2:

Utilisation de la fonction wait:

import keyboard

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

Il attendra que vous appuyiez sur pet continuera le code pendant qu'il est enfoncé.


Méthode n ° 3:

Utilisation de la fonction on_press_key:

import keyboard

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

Il a besoin d'une fonction de rappel. J'ai utilisé _parce que la fonction clavier renvoie l'événement clavier à cette fonction.

Une fois exécuté, il exécutera la fonction lorsque la touche sera enfoncée. Vous pouvez arrêter tous les hooks en exécutant cette ligne:

keyboard.unhook_all()

Méthode n ° 4:

Cette méthode est en quelque sorte déjà répondue par user8167727 mais je ne suis pas d'accord avec le code qu'ils ont créé. Il utilisera la fonction is_pressedmais d'une autre manière:

import keyboard

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

Cela cassera la boucle lorsque vous pappuyez sur.


Remarques:

  • keyboard lira les pressions sur les touches de l'ensemble du système d'exploitation.
  • keyboard nécessite root sur linux
Tonnerre noir
la source
11
Le plus gros inconvénient de l'utilisation du module clavier est son exigence que vous exécutez en tant qu'utilisateur ROOT. Cela rend le module verboten dans mon code. Le simple fait d'interroger si une touche a été enfoncée ne nécessite pas de privilèges root. J'ai lu la doc et je comprends pourquoi la limitation existe dans le module, mais regardez ailleurs si tout ce dont vous avez besoin est d'interroger une clé ...
muman
Informations très utiles partagées, Monsieur! Je voulais savoir si je pouvais utiliser keyboard.wait()pour attendre plus d'une touche et continuer si l'une d'elles est enfoncée
Preetkaran Singh
@PreetkaranSingh wait()ne donne pas cette fonctionnalité. Vous devrez utiliser keyboard.read_key()avec une condition if emballée dans une boucle while. Voir la méthode n ° 1
Black Thunder
Merci Monsieur!, Aimeriez-vous nous éclairer sur l' suppressutilisation des mots - clés dans keyboard.read_key(), quand l'utiliser et quand pas ....
Preetkaran Singh
@PreetkaranSingh Je le ferais mais je n'ai pas assez d'informations sur l'argument de suppression
Black Thunder
14

Pour Windows, vous pouvez utiliser msvcrtcomme ceci:

   import msvcrt
   while True:
       if msvcrt.kbhit():
           key = msvcrt.getch()
           print(key)   # just to show the result
Benjie
la source
7
msvcrt est un module Windows uniquement.
Dunatotatos
1
J'utilise actuellement pynput, cela pourrait être une meilleure réponse
Benjie
Notez que pynput pour fonctionner sur OS X (je ne connais pas Linux) doit s'exécuter en tant que root pour fonctionner. Cela peut être un non-démarreur pour certaines personnes.
Gabe Weiss
J'aurais juré que la question était pour `` multiplate-forme '' ou `` linux '' ...
Aaron Mann le
10

Utilisez ce code pour trouver la touche enfoncée

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()
Manivannan Murugavel
la source
Voici le truc cependant, j'utilise macOS et installé à la fois pynput et clavier séparément, et le programme fonctionne sans aucune erreur mais ne peut détecter (sur le shell python) que les touches spéciales. Les touches alphanumériques ne sont pas détectées et au contraire, sont considérées comme si j'écrivais du code sur le shell. Savez-vous quel pourrait être le problème?
Dario Deniz Ergün
Le même code a fonctionné pour moi dans le shell. S'il te plaît vérifie le. Le package du clavier n'a pas besoin de ce code.
Manivannan Murugavel
1
C'est la voie à suivre sous Linux, car la bibliothèque de clavier a besoin de root.
David
1
Cette solution détectera toutes les frappes; également ceux qui se produisent dans une fenêtre de terminal différente. Malheureusement, cela limite considérablement ses cas d'utilisation possibles.
Serge Stroobandt
6

Utilisez PyGame pour avoir une fenêtre et ensuite vous pouvez obtenir les événements clés.

Pour la lettre 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()
AJ Uppal
la source
2

J'ai donc créé ce .. genre de jeu .. basé sur ce post (en utilisant la bibliothèque msvcr et Python 3.7).

Voici la "fonction principale" du jeu, qui consiste à détecter les touches enfoncées:

# 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

Si vous voulez le code source complet du porgram, vous pouvez le voir ou le télécharger à partir d'ici:

Le jeu de clé secrète (GitHub)

(note: la touche secrète est: Ctrl+ F12)

J'espère que vous pourrez servir d'exemple et d'aider ceux qui viennent consulter ces informations.

Ferd
la source
1
key = cv2.waitKey(1)

Ceci provient du package openCV. Il détecte une pression sur une touche sans attendre.

Eyllanesc
la source