Comment faire python attendre une touche enfoncée?

571

Je veux que mon script attende que l'utilisateur appuie sur n'importe quelle touche.

Comment je fais ça?

Janusz
la source

Réponses:

543

Dans Python 3, utilisez input():

input("Press Enter to continue...")

Dans Python 2, utilisez raw_input():

raw_input("Press Enter to continue...")

Cependant, cela n'attend que l'utilisateur pour appuyer sur Entrée.

On peut vouloir utiliser msvcrt ((Windows / DOS uniquement) Le module msvcrt vous donne accès à un certain nombre de fonctions dans la bibliothèque d'exécution Microsoft Visual C / C ++ (MSVCRT)):

import msvcrt as m
def wait():
    m.getch()

Cela devrait attendre une pression sur une touche.

Information additionnelle:

en Python 3 raw_input()n'existe pas

En Python 2 input(prompt)est équivalent àeval(raw_input(prompt))

riza
la source
54
Je reçois cette erreur lorsque j'essaie de le faire en Python 2.7: "SyntaxError: EOF inattendu lors de l'analyse"
Jon Tirsen
8
@ Solarsaturn9 et un nombre croissant et non. Cette réponse n'a donc pas fonctionné pour moi et pour les nombreuses autres qui viennent ici.
ctrl-alt-delor du
5
@richard utilisant input () devrait également fonctionner sur d'autres plateformes. Il est ridicule d'ancrer des points pour fournir une solution alternative uniquement pour Windows lorsque la première solution est multi-plateforme.
Cory Buckley
7
@ Solarsaturn9 relisez la question et répondez à nouveau: inputne continue pas si vous appuyez sur une touche, uniquement si vous appuyez sur Entrée.
ctrl-alt-delor
13
@JonTirsen parce que Python 2.7 a une fonction appelée input qui évalue la chaîne que vous entrez. Pour corriger, utilisez raw_input
Samy Bencherif
316

Une façon de faire cela en Python 2, est d'utiliser raw_input():

raw_input("Press Enter to continue...")

En python3 c'est juste input()

Greg Hewgill
la source
17
Qu'en est-il quand il peut s'agir de l'une des nombreuses clés? Pas seulement enter?
noio
33
Avec Python 3+ , cela est devenu juste input().
palswim
Utilisation de six pour le code compatible Py2 & Py3:from six.moves import input; input("Press Enter to continue...")
rcoup
56

Sur ma boîte Linux, j'utilise le code suivant. Ceci est similaire au code que j'ai vu ailleurs (dans les anciennes FAQ python par exemple) mais ce code tourne dans une boucle serrée où ce code ne fonctionne pas et il y a beaucoup de cas de coins étranges que le code ne tient pas compte de cela le code le fait.

def read_single_keypress():
    """Waits for a single keypress on stdin.

    This is a silly function to call if you need to do it a lot because it has
    to store stdin's current setup, setup stdin for reading single keystrokes
    then read the single keystroke then revert stdin back after reading the
    keystroke.

    Returns a tuple of characters of the key that was pressed - on Linux, 
    pressing keys like up arrow results in a sequence of characters. Returns 
    ('\x03',) on KeyboardInterrupt which can happen when a signal gets
    handled.

    """
    import termios, fcntl, sys, os
    fd = sys.stdin.fileno()
    # save old state
    flags_save = fcntl.fcntl(fd, fcntl.F_GETFL)
    attrs_save = termios.tcgetattr(fd)
    # make raw - the way to do this comes from the termios(3) man page.
    attrs = list(attrs_save) # copy the stored version to update
    # iflag
    attrs[0] &= ~(termios.IGNBRK | termios.BRKINT | termios.PARMRK
                  | termios.ISTRIP | termios.INLCR | termios. IGNCR
                  | termios.ICRNL | termios.IXON )
    # oflag
    attrs[1] &= ~termios.OPOST
    # cflag
    attrs[2] &= ~(termios.CSIZE | termios. PARENB)
    attrs[2] |= termios.CS8
    # lflag
    attrs[3] &= ~(termios.ECHONL | termios.ECHO | termios.ICANON
                  | termios.ISIG | termios.IEXTEN)
    termios.tcsetattr(fd, termios.TCSANOW, attrs)
    # turn off non-blocking
    fcntl.fcntl(fd, fcntl.F_SETFL, flags_save & ~os.O_NONBLOCK)
    # read a single keystroke
    ret = []
    try:
        ret.append(sys.stdin.read(1)) # returns a single character
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save | os.O_NONBLOCK)
        c = sys.stdin.read(1) # returns a single character
        while len(c) > 0:
            ret.append(c)
            c = sys.stdin.read(1)
    except KeyboardInterrupt:
        ret.append('\x03')
    finally:
        # restore old state
        termios.tcsetattr(fd, termios.TCSAFLUSH, attrs_save)
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save)
    return tuple(ret)
mheyman
la source
Bien que ce soit ma préférée des réponses ici, comme les autres n'attrape pas des choses comme le changement de vitesse, le contrôle, etc.
Mala
1
@Mala qui n'est pratiquement pas possible en Python pur; vous devriez peut-être écrire un module C?
chat
J'obtiens "\ x03" lors d'une interruption clavier (Ctrl-C) sur mon système.
RDA
1
ctrl-c est un ascii 3 donc cela est attendu. Si vous voulez élever un signal sur ctrl-c, la solution simple est de mettre un if ord (return_value) == 3: os.kill (os.getpid (), signal.SIGINT) mais vous pouvez également désactiver le traitement du signal par attrs [0] | = termios.BRKINT, attrs [3]! = termios.ISIG, et supprimez le traitement sauf KeyboardInterrupt. Remarque - J'ai changé la valeur de retour de KeyboardInterrupt en '\ x03' en l'honneur de votre requête (et parce que cela fait que ce code retourne toujours une chaîne).
mheyman
Comment le code ci-dessus pourrait-il être ajusté pour qu'il renvoie un tuple pour une pression de touche complexe comme "Page Up" ou "Left Arrow"?
Derek
33

Si vous êtes d'accord avec les commandes système, vous pouvez utiliser les éléments suivants:

Linux:

import os
os.system('read -sn 1 -p "Press any key to continue..."')
print

Les fenêtres:

import os
os.system("pause")
CrouZ
la source
Si vous souhaitez continuer à fonctionner jusqu'à ce qu'un signal soit émis (comme SIGINT), vous pouvez également vérifier la valeur de retour de systempuis appeler sys.exit(0).
James Taylor
29

Simplement en utilisant

input("Press Enter to continue...")

provoquera une SyntaxError: EOF attendue lors de l'analyse.

Utilisation simple du correctif:

try:
    input("Press enter to continue")
except SyntaxError:
    pass
vrai
la source
5
Ne pas utiliser inputen python 2 - la fonction correcte est raw_input. En python 2, inputest équivalent à eval(raw_input()).
Blorgbeard est sorti le
2
Cela ignore toutes les touches sur lesquelles l'utilisateur appuie jusqu'à ce qu'il touche Entrée, ce qui est assez différent de ce que l'OP demande.
Jonathan Hartley
1
De plus, si vous deviez utiliser 'input', intercepter une SyntaxError n'est pas approprié. Quels que soient les types d'utilisateurs évalués, donc si, par exemple, ils tapent "1/0", une ZeroDivisionError est levée au lieu d'une SyntaxError et votre programme se fermera.
Jonathan Hartley
Comme l'a mentionné @Blorgbeard, une simple utilisation de raw_input ("Appuyez sur Entrée pour continuer ...") suffira. Je l'utilise souvent maintenant lors du débogage.
alltrue
15

Le manuel python fournit les éléments suivants:

import termios, fcntl, sys, os
fd = sys.stdin.fileno()

oldterm = termios.tcgetattr(fd)
newattr = termios.tcgetattr(fd)
newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
termios.tcsetattr(fd, termios.TCSANOW, newattr)

oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)

try:
    while 1:
        try:
            c = sys.stdin.read(1)
            print "Got character", repr(c)
        except IOError: pass
finally:
    termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
    fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)

qui peut être intégré dans votre cas d'utilisation.

Jaap Versteegh
la source
12
C'est une bonne pratique de copier la chose à laquelle vous créez un lien afin que les connaissances restent, même si le lien meurt (et ils le font!).
Richard
1
Comment puis-je faire fonctionner cela en Python 3.x? Dans 3.x, après avoir modifié l'instruction print pour qu'elle soit compatible, cela boucle simplement à l'infini et n'attend pas d'entrée. Cela fonctionne très bien en Python 2, cependant.
chat
Le lien a été mis à jour pour rediriger vers une autre page. Le nouveau lien est ici.
Matthias
15

Cross Platform, code Python 2/3:

# import sys, os

def wait_key():
    ''' Wait for a key press on the console and return it. '''
    result = None
    if os.name == 'nt':
        import msvcrt
        result = msvcrt.getch()
    else:
        import termios
        fd = sys.stdin.fileno()

        oldterm = termios.tcgetattr(fd)
        newattr = termios.tcgetattr(fd)
        newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
        termios.tcsetattr(fd, termios.TCSANOW, newattr)

        try:
            result = sys.stdin.read(1)
        except IOError:
            pass
        finally:
            termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)

    return result

J'ai supprimé le fctl / non-blocking parce qu'il donnait des IOErrors et je n'en avais pas besoin. J'utilise ce code spécifiquement parce que je veux qu'il se bloque. ;)

Addenda:

J'ai implémenté cela dans un package sur PyPI avec beaucoup d'autres goodies appelés console :

>>> from console.utils import wait_key

>>> wait_key()
'h'
Gringo Suave
la source
1
J'ai eu une erreur: ioctl inapproprié pour l'appareil '
Benoit
@Benoit quel OS?
Gringo Suave
Linux - Ubuntu 20.04
Benoit
14

Je ne connais pas de méthode indépendante de la plateforme, mais sous Windows, si vous utilisez le module msvcrt, vous pouvez utiliser sa fonction getch:

import msvcrt
c = msvcrt.getch()
print 'you entered', c

mscvcrt inclut également la fonction kbhit () non bloquante pour voir si une touche a été enfoncée sans attendre (pas sûr qu'il y ait une fonction curses correspondante). Sous UNIX, il y a le paquet curses, mais je ne sais pas si vous pouvez l'utiliser sans l'utiliser pour toute la sortie d'écran. Ce code fonctionne sous UNIX:

import curses
stdscr = curses.initscr()
c = stdscr.getch()
print 'you entered', chr(c)
curses.endwin()

Notez que curses.getch () renvoie l'ordinal de la touche enfoncée afin de lui donner la même sortie que je devais la transtyper.

John Gaines Jr.
la source
Utiliser des malédictions est beaucoup plus agréable que les exemples plutôt compliqués décrits par le manuel, même si cela implique une énorme dépendance. +1
Damian
4

Si vous voulez attendre la saisie (afin que l'utilisateur ne frappe pas le clavier, il ne se produira pas quelque chose d'inattendu), utilisez

sys.stdin.readline()
Andrew Pate
la source
2
L'intérêt est que l'utilisateur n'ait pas à appuyer uniquement sur la touche Entrée, pour par exemple pouvoir simplement gifler la barre d'espace. Si vous avez besoin d'Enter pour éviter que quelque chose d'inattendu ne se produise, c'est une mauvaise conception.
Synetech
3

Je suis nouveau sur python et je pensais déjà que je suis trop stupide pour reproduire les suggestions les plus simples faites ici. Il s'avère qu'il y a un écueil à savoir:

Lorsqu'un script python est exécuté depuis IDLE, certaines commandes IO semblent se comporter complètement différemment (car il n'y a en fait pas de fenêtre de terminal).

Par exemple. msvcrt.getch n'est pas bloquant et renvoie toujours $ ff. Cela a déjà été signalé il y a longtemps (voir par exemple https://bugs.python.org/issue9290 ) - et il est marqué comme corrigé, le problème semble en quelque sorte persister dans les versions actuelles de python / IDLE.

Donc, si l'un des codes publiés ci-dessus ne fonctionne pas pour vous, essayez d'exécuter le script manuellement, et NON depuis IDLE .

ralfiii
la source
0

Si vous voulez voir s'ils ont appuyé sur une touche exacte (comme dire «b»), procédez comme suit:

while True:
    choice = raw_input("> ")

    if choice == 'b' :
        print "You win"
        input("yay")
        break
E40
la source
8
Cela oblige l'utilisateur à taper «b» (ou autre chose) puis à appuyer sur Entrée, ce qui est assez différent de ce que l'OP demande.
Jonathan Hartley
0

os.system semble invoquer toujours sh, qui ne reconnaît pas les options s et n pour la lecture. Cependant la commande read peut être passée à bash:

 os.system("""bash -c 'read -s -n 1 -p "Press any key to continue..."'""")
James King
la source
2
La documentation lue me fait penser qu'elle ne dépassera pas le délai sauf si vous spécifiez l'option -t.
James King