rilevare la pressione dei tasti in Python?


106

Sto realizzando un programma di tipo cronometro in python e vorrei sapere come rilevare se viene premuto un tasto (come p per pausa es per stop), e non vorrei che fosse qualcosa come raw_input che aspetta il input dell'utente prima di continuare l'esecuzione. Qualcuno sa come farlo in un ciclo while?

Inoltre, vorrei rendere questo multipiattaforma, ma se ciò non è possibile, il mio principale obiettivo di sviluppo è Linux


per OS X stackoverflow.com/a/47197390/5638869 funziona in Python 2 e 3
neoDev

Risposte:


71

Python ha un modulo tastiera con molte funzionalità. Installalo, magari con questo comando:

pip3 install keyboard

Quindi usalo nel codice come:

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

2
Non sono sicuro per Linux ma funziona su Windows per me.

75
keyboardapparentemente richiede root in linux: /
Inaimathi

Ho provato questa soluzione ma quando provo a importare il modulo dopo averlo installato, ottengo un "ImportError: Nessun modulo denominato" tastiera "", quindi non ha funzionato. Ho controllato nel repository GitHub e trovo un problema correlato , ma non mi risolve il problema. Quindi, ho provato a scaricare il repository e ad eseguire alcuni dei suoi esempi ma ottengo e "ImportError: Devi essere root per usare questa libreria su Linux", come ha commentato prima @Inaimathi. Apparentemente sembra un modulo completo per gestire la tastiera con Python, ma il requisito di root è una grande mancanza :(
Ivanhercaz

3
"Per evitare di dipendere da X, le parti Linux leggono i file di dispositivo non elaborati (/ dev / input / input *) ma questo richiede root."
jrouquie

8
Non vedo perché la prova: tranne: sarebbe utile.
Tipico porco

50

Per coloro che sono su Windows e stavano lottando per trovare una risposta funzionante, ecco la mia: 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 funzione sopra stamperà il tasto che stai premendo e avvierà un'azione mentre rilasci il tasto "esc". La documentazione della tastiera è qui per un utilizzo più vario.

Markus von Broady ha evidenziato un potenziale problema che è: questa risposta non richiede che tu sia nella finestra corrente per attivare questo script, una soluzione a Windows sarebbe:

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 ... e non richiede root :)
cz

1
C'è un problema con questa soluzione (non sono sicuro delle alternative): il tasto non deve essere premuto all'interno di una finestra della console perché abbia effetto. Immagina di avere uno script che fa un lavoro finché non viene premuto ESC, ma poi lo premi in un altro programma.
Markus von Broady

1
@MarkusvonBroady Immagino che win32gui sarebbe sufficiente per risolverlo, ho modificato la mia risposta in un modo che potrebbe potenzialmente risolverla almeno per gli utenti di Windows.
Mitrek

@Mitrek Ho provato questo, ma il mio codice interrompe l'ulteriore esecuzione ed è bloccato qui. Funziona come input (). Ho il codice in esecuzione in selenio, Firefox, ma non appena viene rilevata questa sequenza, non ci sono ulteriori azioni.
Lakshmi Narayanan

1
Avrebbe dovuto essere la risposta accettata, perché funziona sia su Linux che su Windows
Akash Karnatak

31

Come menzionato da OP su raw_input, significa che vuole la soluzione cli. Linux: curses è quello che vuoi (windows PDCurses). Curses, è un'API grafica per il software cli, puoi ottenere molto di più che rilevare eventi chiave.

Questo codice rileverà i tasti finché non viene premuta una nuova riga.

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)

Questo è davvero carino. Ho dovuto cercare per sempre prima di incontrarlo. Sembra molto più pulito che andare in giro con termiose così via ...
Hugh Perkins

5
necessario aggiungere import osper poter uscire dall'esempio.
malte

Se lo fai win.nodelay(False)invece di True, non genererà un milione di eccezioni al secondo.
Johannes Hoff,

25

Ci sono più cose che possono essere fatte con keyboardmodule.

Ecco alcuni metodi:


Metodo # 1:

Utilizzando la funzione read_key():

import keyboard

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

Questo interromperà il ciclo quando pviene premuto il tasto .


Metodo n. 2:

Utilizzo della funzione wait:

import keyboard

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

Aspetterà che tu prema pe continui il codice mentre viene premuto.


Metodo n. 3:

Utilizzando la funzione on_press_key:

import keyboard

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

Ha bisogno di una funzione di callback. Ho usato _perché la funzione della tastiera restituisce l'evento della tastiera a quella funzione.

Una volta eseguito, eseguirà la funzione quando viene premuto il tasto. Puoi interrompere tutti gli hook eseguendo questa riga:

keyboard.unhook_all()

Metodo n. 4:

Questo metodo è in qualche modo già risposto dall'utente8167727 ma non sono d'accordo con il codice che hanno creato. Utilizzerà la funzione is_pressedma in un altro modo:

import keyboard

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

Interromperà il ciclo quando pviene premuto.


Appunti:

  • keyboard leggerà i tasti premuti dall'intero sistema operativo.
  • keyboard richiede root su linux

11
Il più grande NEGATIVO dell'utilizzo del modulo tastiera è il requisito che esegui come utente ROOT. Questo rende il modulo verboten nel mio codice. Solo per interrogare se un tasto è stato premuto non richiede i privilegi di root. Ho letto il documento e capisco perché la limitazione esce nel modulo, ma cerca altrove se tutto ciò di cui hai bisogno è interrogare una chiave ...
muman

Informazioni molto utili condivise, signore! Volevo sapere se posso keyboard.wait()aspettare più di 1 tasto e continuare se viene premuto uno dei due
Preetkaran Singh

@PreetkaranSingh wait()non fornisce questa funzionalità. Dovrai usare keyboard.read_key()con una condizione if racchiusa in un ciclo while. Guarda il metodo # 1
Black Thunder

Grazie Signore!, suppresskeyboard.read_key()
Vorresti

@PreetkaranSingh Lo farei ma non ho abbastanza informazioni sull'argomento di soppressione
Black Thunder

14

Per Windows potresti usare in msvcrtquesto modo:

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

7
msvcrt è un modulo solo per Windows.
Dunatotatos

1
In realtà ora uso pynput, questa potrebbe essere una risposta migliore
Benjie

Nota che pynput per funzionare su OS X (non so su Linux) deve essere eseguito come root per funzionare. Potrebbe non essere un inizio per alcune persone.
Gabe Weiss

Avrei giurato che la domanda fosse per "multipiattaforma" o "linux" ...
Aaron Mann,

10

Usa questo codice per trovare il tasto premuto

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

Il fatto è che sto usando macOS e ho installato sia pynput che tastiera separatamente, e il programma funziona senza errori ma può solo rilevare (sulla shell python) tasti speciali. Le chiavi alfanumeriche non vengono rilevate e al contrario, sono considerate come se stessi scrivendo codice sulla shell. Sai quale potrebbe essere il problema?
Dario Deniz Ergün

Lo stesso codice ha funzionato per me nella shell. Per favore controllalo. Il pacchetto della tastiera non necessita di questo codice.
Manivannan Murugavel

1
Questa è la strada da percorrere in Linux, poiché la libreria della tastiera necessita di root.
David

1
Questa soluzione rileverà tutti i tasti premuti; anche quelli che si verificano in una finestra di terminale diversa. Sfortunatamente, questo limita fortemente i suoi possibili casi d'uso.
Serge Stroobandt

6

Usa PyGame per avere una finestra e poi puoi ottenere gli eventi chiave.

Per la lettera 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

Quindi ho creato questo .. tipo di gioco .. basato su questo post (usando la libreria msvcr e Python 3.7).

Quella che segue è la "funzione principale" del gioco, ovvero il rilevamento dei tasti premuti:

# 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

Se vuoi il codice sorgente completo del programma puoi vederlo o scaricarlo da qui:

The Secret Key Game (GitHub)

(nota: la pressione dei tasti segreta è: Ctrl+ F12)

Spero che tu possa servire da esempio e da aiuto per coloro che vengono a consultare queste informazioni.



1
key = cv2.waitKey(1)

Questo è dal pacchetto openCV. Rileva la pressione di un tasto senza attendere.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.