35

How would I do a "hit any key" (or grab a menu option) in Python?

  • raw_input requires you hit return.
  • Windows msvcrt has getch() and getche().

Is there a portable way to do this using the standard libs?

Nick
  • 27,566
  • 12
  • 60
  • 72

7 Answers7

33
try:
    # Win32
    from msvcrt import getch
except ImportError:
    # UNIX
    def getch():
        import sys, tty, termios
        fd = sys.stdin.fileno()
        old = termios.tcgetattr(fd)
        try:
            tty.setraw(fd)
            return sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old)
John Millikin
  • 197,344
  • 39
  • 212
  • 226
10
try:
  os.system('pause')  #windows, doesn't require enter
except whatever_it_is:
  os.system('read -p "Press any key to continue"') #linux
Dustin Getz
  • 21,282
  • 15
  • 82
  • 131
  • 2
    +1 for it is a simple solution, probably good enough for 90% of all cases. – Rook Sep 08 '09 at 16:51
  • 1
    I just tested with Python 2.x and 3.x on Windows Vista, and it does not require Enter here. (Still does not handle something like indicating a menu choice via a single key press - but works at least on Vista for the "press any key to continue" case.) – Anon Sep 08 '09 at 17:30
  • 5
    spawning a sub-process for io sync is just plain useless. do not do this, it will ruin non-interactive performance for no good reason. – SingleNegationElimination Sep 08 '09 at 18:31
  • Regardless of performance considerations, calling out to an external application for such a simple task is idiotic. – John Millikin Sep 09 '09 at 20:41
  • 2
    what the heck? Wasting even 10 minutes writing 15 lines of code when a mindless one liner will do is worse. – Dustin Getz Sep 10 '09 at 00:40
  • Works fine in Python 2.7 on Windows 7: >>> def pause(): import os; os.system('pause') ... >>> pause() Press any key to continue . . . >>> – Cees Timmerman Jun 07 '12 at 13:20
  • 1
    Also, TokenMacGuy, waiting for any key to be pressed IS interactive performance. And JohnMillikin, specialized tools ARE the Unix philosophy. – Cees Timmerman Jun 07 '12 at 13:26
  • Same code, but instead of try-except I'd use platform.system() guards. You never know whether somebody reserved /opt/bin/pause because it's free anyways ... – indmg Sep 18 '13 at 06:00
  • Python3.4 on Ubuntu: The call to 'os.system' is weird. It doesn't raise at all, but instead prints some text to stderr and returns an int, presumably the child process id. I don't know how to detect that the system call didn't work, other than something yucky like wrapping stderr. – Jonathan Hartley Aug 24 '15 at 13:23
7

A couple years ago I wrote a small library to do this in a cross-platform way (inspired directly by John Millikin's answer above). In addition to getch, it comes with a pause function that prints 'Press any key to continue . . .':

pause()

You can provide a custom message too:

pause('Hit any key')

If the next step is to exit, it also comes with a convenience function that calls sys.exit(status):

pause_exit(status=0, message='Hit any key')

Install with pip install py-getch, or check it out here.

Joe
  • 16,328
  • 12
  • 61
  • 75
6

From the python docs:

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", `c`
        except IOError: pass
finally:
    termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
    fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)

This only works for Unix variants though. I don't think there is a cross-platform way.

Isaiah
  • 4,201
  • 4
  • 27
  • 40
  • This should be the solution. – Wes Modes Jan 14 '17 at 18:46
  • 1
    The problem with this solution is that it consumes all available CPU cycles running the while loop. You can reduce this to almost nothing by inserting `time.sleep(0.1)` in the loop. If you insert this in place of "pass", then the loop will process strings of keystrokes as fast as possible, but when idle it will only check for characters 10 times a second. – gwideman Aug 29 '19 at 02:28
1

I implemented it like the following in Windows. getch() takes a one single character

import msvcrt
char = 0
print 'Press any key to continue'
while not char:
    char = msvcrt.getch()
v_kumar
  • 319
  • 4
  • 15
1

Another option:

import keyboard
print("Press any key to continue")
keyboard.read_key()
print("to be continued...")
Bill Mol
  • 31
  • 3
0

on linux platform, I use os.system to call /sbin/getkey command, e.g.

continue_ = os.system('/sbin/getkey -m "Please any key within %d seconds to continue..." -c  10')
if continue_:
   ...
else:
   ...

The benefit is it will show an countdown seconds to user, very interesting :)

Congbin Guo
  • 1,685
  • 2
  • 16
  • 16