640

I want my script to wait until the user presses any key.
How do I do that?

martineau
  • 99,260
  • 22
  • 139
  • 249
Janusz
  • 176,216
  • 111
  • 293
  • 365

12 Answers12

644

In Python 3 use input():

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

In Python 2 use raw_input():

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

This only waits for the user to press enter though.

One might want to use msvcrt ((Windows/DOS only) The msvcrt module gives you access to a number of functions in the Microsoft Visual C/C++ Runtime Library (MSVCRT)):

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

This should wait for a key press.

Additional info:

in Python 3 raw_input() does not exist

In Python 2 input(prompt) is equivalent to eval(raw_input(prompt))

U3.1415926
  • 606
  • 9
  • 26
riza
  • 13,450
  • 7
  • 27
  • 29
  • 55
    I'm getting this error when I try to do this in Python 2.7: "SyntaxError: unexpected EOF while parsing" – Jon Tirsen Sep 17 '14 at 07:11
  • 8
    @Solarsaturn9 and an increasing and large number do not. Thus this answer did not work for me, and the many other that come here. – ctrl-alt-delor Oct 22 '15 at 22:00
  • 5
    @richard using input() should work on other platforms as well. It's ridiculous to dock points for providing a alternative Windows only solution when the first solution is multi-platform. – Cory Buckley Oct 23 '15 at 15:46
  • 8
    @Solarsaturn9 read the question and answer again: `input` does not continue if any key is pressed, only if enter is pressed. – ctrl-alt-delor Oct 23 '15 at 23:21
  • 13
    @JonTirsen that's because Python 2.7 has a function called input which evaluates the string you input. To fix, use raw_input – Samy Bencherif Dec 03 '15 at 03:16
  • 1
    For people using IDLE: `msvcrt.getch()` doesn't work there, only in the Python console. – Noumenon Mar 16 '17 at 18:45
  • Using [six](https://pythonhosted.org/six/) for Py2 _and_ Py3 compatible code: `from six.moves import input; input("Press Enter to continue...")` – rcoup Nov 29 '18 at 12:46
321

One way to do this in Python 2, is to use raw_input():

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

In python3 it's just input()

Warren P
  • 58,696
  • 38
  • 168
  • 301
Greg Hewgill
  • 828,234
  • 170
  • 1,097
  • 1,237
  • 17
    What about when it can be one of a number of keys? Not just `enter`? – noio Jan 11 '11 at 09:51
  • 34
    [With Python 3+](http://stackoverflow.com/questions/954834/easy-how-to-use-raw-input-in-3-1), this has changed to just `input()`. – palswim Sep 02 '11 at 17:10
  • Using [six](https://pythonhosted.org/six/) for Py2 & Py3 compatible code: `from six.moves import input; input("Press Enter to continue...")` – rcoup Nov 29 '18 at 12:45
58

On my linux box, I use the following code. This is similar to code I've seen elsewhere (in the old python FAQs for instance) but that code spins in a tight loop where this code doesn't and there are lots of odd corner cases that code doesn't account for that this code does.

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
  • 3,703
  • 32
  • 33
  • While this is my favorite of the answers here, like the others doesn't catch things like shift, control, etc – Mala Mar 03 '13 at 20:22
  • 1
    @Mala that pretty much isn't possible in pure Python; perhaps you should write a C module? – cat Jan 30 '16 at 20:50
  • I'm getting "\x03" on keyboard interrupt (Ctrl-C) on my system. – GDR Aug 21 '18 at 03:48
  • 1
    ctrl-c is an ascii 3 so that is expected. If you want to raise a signal on ctrl-c, the easy solution is to put an if ord(returned_value) == 3: os.kill(os.getpid(), signal.SIGINT) but you could also turn off signal processing by attrs[0] |= termios.BRKINT, attrs[3] != termios.ISIG, and get rid of the except KeyboardInterrupt processing. Note - I changed the return value for KeyboardInterrupt into a '\x03' in honor of your query (and because that makes this code _always_ return a string). – mheyman Aug 23 '18 at 13:33
  • 1
    How could the above code be adjusted so that it returns a tuple for a complex key press like "Page Up" or "Left Arrow"? – Derek Mar 05 '19 at 07:11
  • 1
    I updated the code in your honor, Derek. That was a good question. I bounced back an forth between returning a string to returning a tuple as in your suggestion and ended with the tuple because it makes other code using the results clearer (in my opinion). Oh, the answer was to turn on non-blocking after the first character and read any additional characters. If you type real fast you can fool this... – mheyman Mar 11 '19 at 23:10
  • I liked this solution a lot. I've put up a gist with some utility I found useful in my case - a start at combining control sequences into one string and optional repeat filtering. https://gist.github.com/shaperilio/1b9065b149944d060a4da33d7bf6b78b – darda Feb 11 '21 at 17:14
36

If you are ok with depending on system commands you can use the following:

Linux and Mac OS X:

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

Windows:

import os
os.system("pause")
CrouZ
  • 1,463
  • 16
  • 16
  • If you want keep running until a signal is raised (like SIGINT), you could also check the return value from `system` and then call `sys.exit(0)`. – James Taylor Apr 18 '18 at 02:12
  • Is there an equivalent for OSX? – CarlosE Dec 30 '20 at 18:18
  • @CarlosE The Linux variant might work for OSX too. Please let me know if it does. – CrouZ Dec 30 '20 at 21:49
  • Unfortunately the Linux variant does not in OSX - the statement has no effect. Am running Big Sur (11.1). – CarlosE Jan 01 '21 at 17:38
  • 1
    @CarlosE I tested on MAC OS X 10.7 and there it works with both Python 3.7.6 and Python 2.7.1. How are you running it? According to this question, you need to run it from a terminal: https://stackoverflow.com/questions/58986403/mac-os-os-systemcommand-display-nothing – CrouZ Jan 10 '21 at 19:03
  • Thank you @CrouZ. You are right, when using the command line this works. In Jupyter it does not work, however. Are you aware of a solution for Jupyter? – CarlosE Jan 11 '21 at 21:22
  • @CarlosE Sorry, I have not used Jupyter so I don't know. – CrouZ Jan 14 '21 at 20:33
32

Simply using

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

will cause a SyntaxError: expected EOF while parsing.

Simple fix use:

try:
    input("Press enter to continue")
except SyntaxError:
    pass
alltrue
  • 469
  • 4
  • 5
  • 6
    Don't use `input` in python 2 - the correct function is `raw_input`. In python 2, `input` is equivalent to `eval(raw_input())`. – Blorgbeard Jul 28 '14 at 23:41
  • 3
    This ignores all keys the user presses, until they hit enter, which is quite different from what the OP is asking. – Jonathan Hartley Aug 24 '15 at 10:47
  • 1
    Also, if you were going to use 'input', catching a SyntaxError isn't appropriate. Whatever the user types gets evaluated, so if, for example, they type "1/0" then a ZeroDivisionError is raised instead of a SyntaxError, and your program will exit. – Jonathan Hartley Aug 24 '15 at 10:52
  • As @Blorgbeard mentioned, simply using raw_input("Press Enter to continue...") will suffice. I use it often now when debugging. – alltrue Aug 27 '15 at 01:02
20

Cross Platform, Python 2/3 code:

# 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

I removed the fctl/non-blocking stuff because it was giving IOErrors and I didn't need it. I'm using this code specifically because I want it to block. ;)

Addendum:

I implemented this in a package on PyPI with a lot of other goodies called console:

>>> from console.utils import wait_key

>>> wait_key()
'h'
Gringo Suave
  • 25,443
  • 6
  • 77
  • 69
18

The python manual provides the following:

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)

which can be rolled into your use case.

Richard
  • 44,865
  • 24
  • 144
  • 216
Jaap Versteegh
  • 731
  • 7
  • 15
  • 12
    It's good practice to copy the thing you're linking to so that the knowledge remains, even if the link dies (and they do!). – Richard Nov 01 '12 at 19:06
  • 1
    How can I make this work in Python 3.x? In 3.x, after changing the print statement to be compatible, this just loops infinitely and doesn't wait for input. It works great in Python 2, though. – cat Jan 11 '16 at 14:01
  • 1
    The link has been updated to redirect to a different page. The new link is [here.](https://docs.python.org/2/faq/library.html#how-do-i-get-a-single-keypress-at-a-time) – Matthias Mar 11 '18 at 05:45
  • in python3 this works after rewriting the print statement in a slightly more than 2to3 way: `if c: print(f"Got character {repr(c)}")`, as of now, [the python 3 faq](https://docs.python.org/3/faq/library.html#how-do-i-get-a-single-keypress-at-a-time) is just blank on this. – PeterK Dec 02 '20 at 20:31
14

I don't know of a platform independent way of doing it, but under Windows, if you use the msvcrt module, you can use its getch function:

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

mscvcrt also includes the non-blocking kbhit() function to see if a key was pressed without waiting (not sure if there's a corresponding curses function). Under UNIX, there is the curses package, but not sure if you can use it without using it for all of the screen output. This code works under UNIX:

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

Note that curses.getch() returns the ordinal of the key pressed so to make it have the same output I had to cast it.

John Gaines Jr.
  • 9,766
  • 1
  • 23
  • 25
  • Using curses is a lot nicer than the rather convoluted examples described by the manual, even if it involves a huge dependency. +1 – Damian May 03 '16 at 05:09
4

I am new to python and I was already thinking I am too stupid to reproduce the simplest suggestions made here. It turns out, there's a pitfall one should know:

When a python-script is executed from IDLE, some IO-commands seem to behave completely different (as there is actually no terminal window).

Eg. msvcrt.getch is non-blocking and always returns $ff. This has already been reported long ago (see e.g. https://bugs.python.org/issue9290 ) - and it's marked as fixed, somehow the problem seems to persist in current versions of python/IDLE.

So if any of the code posted above doesn't work for you, try running the script manually, and NOT from IDLE.

ralfiii
  • 430
  • 3
  • 10
4

If you want to wait for enter (so the user knocking the keyboard does not cause something un-intended to happen) use

sys.stdin.readline()
andrew pate
  • 2,773
  • 26
  • 17
  • 3
    The whole point is for the user to not have to press only the Enter key, to for example be able to just slap the spacebar. If you require Enter to avoid something unintended from happening, then that's bad design. – Synetech Sep 05 '19 at 00:56
1

os.system seems to always invoke sh, which does not recognize the s and n options for read. However the read command can be passed to bash:

 os.system("""bash -c 'read -s -n 1 -p "Press any key to continue..."'""")
Maxime Lorant
  • 28,973
  • 16
  • 79
  • 93
James King
  • 5,469
  • 3
  • 22
  • 40
-2

If you want to see if they pressed a exact key (like say 'b') Do this:

while True:
    choice = raw_input("> ")

    if choice == 'b' :
        print "You win"
        input("yay")
        break
Achal Dave
  • 3,311
  • 1
  • 22
  • 31
E40
  • 37
  • 1
  • 10
    This requires the user to type 'b' (or something else) then press enter, which is quite different from what the OP is asking for. – Jonathan Hartley Aug 24 '15 at 10:45