tags:

views:

560

answers:

4

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?

+2  A: 

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.

DoR
+4  A: 

From http://code.activestate.com/recipes/134892/:

class _Getch:
    """Gets a single character from standard input.  Does not echo to the
screen."""
    def __init__(self):
        try:
            self.impl = _GetchWindows()
        except ImportError:
            self.impl = _GetchUnix()

    def __call__(self): return self.impl()


class _GetchUnix:
    def __init__(self):
        import tty, sys

    def __call__(self):
        import sys, tty, termios
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch


class _GetchWindows:
    def __init__(self):
        import msvcrt

    def __call__(self):
        import msvcrt
        return msvcrt.getch()


getch = _Getch()
chaos
Get thee behind me, Java
John Millikin
This might be better written where the imports and file handles are cached as members to avoid the setup overhead. But thx.
Nick
+14  A: 
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
A: 
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
-1 for system('pause')
Fu4ny
+1 for it is a simple solution, probably good enough for 90% of all cases.
ldigas
it needs enter.
nosklo
-1 For requiring enter.
DoR
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
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.
TokenMacGuy
premature optimization
Dustin Getz
Regardless of performance considerations, calling out to an external application for such a simple task is idiotic.
John Millikin
what the heck? Wasting even 10 minutes writing 15 lines of code when a mindless one liner will do is worse.
Dustin Getz