Python read a single character from the user

Multi tool use
Multi tool use












219















Is there a way of reading one single character from the user input? For instance, they press one key at the terminal and it is returned (sort of like getch()). I know there's a function in Windows for it, but I'd like something that is cross-platform.










share|improve this question

























  • On windows I ran into the same problem as in this question. The solution is to replace the msvcrt.getch with msvcrt.getwch, as suggested there.

    – A. Roy
    Sep 8 '18 at 18:53


















219















Is there a way of reading one single character from the user input? For instance, they press one key at the terminal and it is returned (sort of like getch()). I know there's a function in Windows for it, but I'd like something that is cross-platform.










share|improve this question

























  • On windows I ran into the same problem as in this question. The solution is to replace the msvcrt.getch with msvcrt.getwch, as suggested there.

    – A. Roy
    Sep 8 '18 at 18:53
















219












219








219


71






Is there a way of reading one single character from the user input? For instance, they press one key at the terminal and it is returned (sort of like getch()). I know there's a function in Windows for it, but I'd like something that is cross-platform.










share|improve this question
















Is there a way of reading one single character from the user input? For instance, they press one key at the terminal and it is returned (sort of like getch()). I know there's a function in Windows for it, but I'd like something that is cross-platform.







python input






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited May 10 '15 at 14:56









Masked Man

1




1










asked Feb 4 '09 at 7:08









Evan FosmarkEvan Fosmark

55.7k2894114




55.7k2894114













  • On windows I ran into the same problem as in this question. The solution is to replace the msvcrt.getch with msvcrt.getwch, as suggested there.

    – A. Roy
    Sep 8 '18 at 18:53





















  • On windows I ran into the same problem as in this question. The solution is to replace the msvcrt.getch with msvcrt.getwch, as suggested there.

    – A. Roy
    Sep 8 '18 at 18:53



















On windows I ran into the same problem as in this question. The solution is to replace the msvcrt.getch with msvcrt.getwch, as suggested there.

– A. Roy
Sep 8 '18 at 18:53







On windows I ran into the same problem as in this question. The solution is to replace the msvcrt.getch with msvcrt.getwch, as suggested there.

– A. Roy
Sep 8 '18 at 18:53














20 Answers
20






active

oldest

votes


















156














Here's a link to a site that says how you can read a single character in Windows, Linux and OSX: 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()





share|improve this answer





















  • 14





    code seems short enough that you could just include it, but +1 for finding a good (cross-platform) answer so quickly.

    – John Mulder
    Feb 4 '09 at 7:24






  • 4





    Does it handle non-latin (e.g., cyrillic) letters well? I am having a problem with that and can't figure out, if it is my mistake, or not.

    – Phlya
    Mar 29 '13 at 18:01






  • 4





    I don't like how the ImportError exception is used like some kind of if-statement; why not call platform.system() to check the OS?

    – Seismoid
    Sep 21 '14 at 20:19






  • 9





    @Seismoid: Asking for forgiveness is generally considered better, see stackoverflow.com/questions/12265451/…

    – dirkjot
    Apr 21 '15 at 11:18






  • 3





    Doesn't work on OS X: "old_settings = termios.tcgetattr(fd)" "termios.error: (25, 'Inappropriate ioctl for device')"

    – Sarge Borsch
    Sep 13 '15 at 18:35





















68














sys.stdin.read(1)


will basically read 1 byte from STDIN.



If you must use the method which does not wait for the n you can use this code as suggested in previous answer:



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


(taken from http://code.activestate.com/recipes/134892/)






share|improve this answer





















  • 24





    I find it odd that sys.stdin.read(1) waits for a n, lol. Thanks for the submission, though.

    – Evan Fosmark
    Feb 4 '09 at 8:00






  • 3





    One character or one byte? That's not the same.

    – chryss
    Feb 4 '09 at 15:08






  • 4





    @Evan, that's because python is in line buffered mode by default

    – John La Rooy
    Oct 13 '09 at 11:09






  • 4





    Note that this code blocks you from using ^C or ^D!

    – Tim R.
    Jun 26 '12 at 1:29






  • 2





    @EvanFosmark: it's not necessarily that sys.stdin.read(1) waits for n, it's that the terminal program deciding when to send other characters to your program doesn't write them until it sees 'n' - how else would you be able to press backspace and correct what you're typing? (the serious answer to that is - teach the python program to implement the line control, keep a buffer, process backspaces, but that's a different world you may not want to buy into when just "reading a character", and could make your line handling different from all the other programs on your system.)

    – Tony Delroy
    Feb 21 '14 at 6:49



















59














The ActiveState recipe quoted verbatim in two answers is over-engineered. It can be boiled down to this:



def _find_getch():
try:
import termios
except ImportError:
# Non-POSIX. Return msvcrt's (Windows') getch.
import msvcrt
return msvcrt.getch

# POSIX system. Create and return a getch that manipulates the tty.
import sys, tty
def _getch():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch

return _getch

getch = _find_getch()





share|improve this answer































    40














    Also worth trying is the readchar library, which is in part based on the ActiveState recipe mentioned in other answers.



    Installation:



    pip install readchar


    Usage:



    import readchar
    print("Reading a char:")
    print(repr(readchar.readchar()))
    print("Reading a key:")
    print(repr(readchar.readkey()))


    Tested on Windows and Linux with Python 2.7.



    On Windows, only keys which map to letters or ASCII control codes are supported (Backspace, Enter, Esc, Tab, Ctrl+letter). On GNU/Linux (depending on exact terminal, perhaps?) you also get Insert, Delete, Pg Up, Pg Dn, Home, End and F n keys... but then, there's issues separating these special keys from an Esc.



    Caveat: Like with most (all?) answers in here, signal keys like Ctrl+C, Ctrl+D and Ctrl+Z are caught and returned (as 'x03', 'x04' and 'x1a' respectively); your program can be come difficult to abort.






    share|improve this answer



















    • 3





      Works with Python 3 on Linux as well. Much better than getch, because readchar allows printing to stdout while waiting for key (via threads or asyncio).

      – wrobell
      Jun 5 '15 at 20:54






    • 1





      Tested on Kubuntu Linux, this works perfectly and is very Pythonic. Thank you!

      – dotancohen
      Aug 20 '15 at 13:30











    • Tested on Win10 + Python 3.5: ERROR:root:'in <string>' requires string as left operand, not bytes Traceback (most recent call last): File "..main.py", line 184, in wrapper result = func(*args, **kwargs) File "C:GitHubPython-Demodemoday_hello.py", line 41, in readch_eg print(readchar.readchar()) File "C:UsersipcjsAppDataLocalProgramsPythonPython35libsite-packagesreadcharreadchar_windows.py", line 14, in readchar while ch in 'x00xe0': TypeError: 'in <string>' requires string as left operand, not bytes

      – ipcjs
      Nov 5 '16 at 20:46













    • @ipcjs please report that bug to the maintainers

      – Melih Yıldız'
      Jul 5 '17 at 8:37











    • this is the best answer. adding a dependency to VS C++ library just for this functionality is crazy.

      – FistOfFury
      Dec 26 '17 at 14:54



















    15














    An alternative method:



    import os
    import sys
    import termios
    import fcntl

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


    From this blog post.






    share|improve this answer


























    • Does not seem to work for me - returns empty string immediately upon calling. On Linux with Python 3.6.

      – Marein
      Apr 6 '17 at 17:40








    • 1





      @Marein If you want it to block (wait for input), remove the | os.O_NONBLOCK. Otherwise, you can put it in a loop (good idea to sleep for a bit in the loop to keep from spinning).

      – Chris Gregg
      Feb 4 at 16:55



















    12














    I think it gets extremely clunky at this point, and debugging on the different platforms is a big mess.



    You'd be better off using something like pyglet, pygame, cocos2d - if you are doing something more elaborate than this and will need visuals, OR curses if you are going to work with the terminal.



    Curses is standard: http://docs.python.org/library/curses.html






    share|improve this answer



















    • 10





      I strongly disagree with this. To use curses you have to initscr() the terminal which clears the screen. This is unwanted behavior if the user only wants to use curses to get userinput without n.

      – dman
      Jun 26 '13 at 20:22



















    8














    This code, based off here, will correctly raise KeyboardInterrupt and EOFError if Ctrl+C or Ctrl+D are pressed.



    Should work on Windows and Linux. An OS X version is available from the original source.



    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):
    char = self.impl()
    if char == 'x03':
    raise KeyboardInterrupt
    elif char == 'x04':
    raise EOFError
    return char

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

    def __call__(self):
    import sys
    import tty
    import 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()





    share|improve this answer
























    • This code waits for n.

      – ChaimG
      Nov 15 '16 at 14:48



















    6














    The (currently) top-ranked answer (with the ActiveState code) is overly complicated. I don't see a reason to use classes when a mere function should suffice. Below are two implementations that accomplish the same thing but with more readable code.



    Both of these implementations:




    1. work just fine in Python 2 or Python 3

    2. work on Windows, OSX, and Linux

    3. read just one byte (i.e., they don't wait for a newline)

    4. don't depend on any external libraries

    5. are self-contained (no code outside of the function definition)


    Version 1: readable and simple



    def getChar():
    try:
    # for Windows-based systems
    import msvcrt # If successful, we are on Windows
    return msvcrt.getch()

    except ImportError:
    # for POSIX-based systems (with termios & tty support)
    import tty, sys, termios # raises ImportError if unsupported

    fd = sys.stdin.fileno()
    oldSettings = termios.tcgetattr(fd)

    try:
    tty.setcbreak(fd)
    answer = sys.stdin.read(1)
    finally:
    termios.tcsetattr(fd, termios.TCSADRAIN, oldSettings)

    return answer


    Version 2: avoid repeated imports and exception handling:



    [EDIT] I missed one advantage of the ActiveState code. If you plan to read characters multiple times, that code avoids the (negligible) cost of repeating the Windows import and the ImportError exception handling on Unix-like systems. While you probably should be more concerned about code readability than that negligible optimization, here is an alternative (it is similar to Louis's answer, but getChar() is self-contained) that functions the same as the ActiveState code and is more readable:



    def getChar():
    # figure out which function to use once, and store it in _func
    if "_func" not in getChar.__dict__:
    try:
    # for Windows-based systems
    import msvcrt # If successful, we are on Windows
    getChar._func=msvcrt.getch

    except ImportError:
    # for POSIX-based systems (with termios & tty support)
    import tty, sys, termios # raises ImportError if unsupported

    def _ttyRead():
    fd = sys.stdin.fileno()
    oldSettings = termios.tcgetattr(fd)

    try:
    tty.setcbreak(fd)
    answer = sys.stdin.read(1)
    finally:
    termios.tcsetattr(fd, termios.TCSADRAIN, oldSettings)

    return answer

    getChar._func=_ttyRead

    return getChar._func()


    Example code that exercises either of the getChar() versions above:



    from __future__ import print_function # put at top of file if using Python 2

    # Example of a prompt for one character of input
    promptStr = "Please give me a character:"
    responseStr = "Thank you for giving me a '{}'."
    print(promptStr, end="n> ")
    answer = getChar()
    print("n")
    print(responseStr.format(answer))





    share|improve this answer





















    • 1





      I ran into an issue with tty.setraw() when printing messages while simultaneously waiting for a key (multi-threaded). Long story short, I found that using tty.setcbreak() lets you get a single character without breaking all the other normal stuff. Long story in this answer

      – TheDavidFactor
      May 21 '16 at 3:50











    • Nice, I was hoping there would be a cleaner way of doing this

      – Phylliida
      May 5 '17 at 18:00



















    4














    This might be a use case for a context manager. Leaving aside allowances for Windows OS, here's my suggestion:



    #!/usr/bin/env python3
    # file: 'readchar.py'
    """
    Implementation of a way to get a single character of input
    without waiting for the user to hit <Enter>.
    (OS is Linux, Ubuntu 14.04)
    """

    import tty, sys, termios

    class ReadChar():
    def __enter__(self):
    self.fd = sys.stdin.fileno()
    self.old_settings = termios.tcgetattr(self.fd)
    tty.setraw(sys.stdin.fileno())
    return sys.stdin.read(1)
    def __exit__(self, type, value, traceback):
    termios.tcsetattr(self.fd, termios.TCSADRAIN, self.old_settings)

    def test():
    while True:
    with ReadChar() as rc:
    char = rc
    if ord(char) <= 32:
    print("You entered character with ordinal {}."
    .format(ord(char)))
    else:
    print("You entered character '{}'."
    .format(char))
    if char in "^C^D":
    sys.exit()

    if __name__ == "__main__":
    test()





    share|improve this answer


























    • You could also return self in __enter__ and have a read method that returns sys.stdin.read(1), then you could read multiple characters in one context.

      – L3viathan
      Apr 12 '17 at 6:46



















    4














    The answers here were informative, however I also wanted a way to get key presses asynchronously and fire off key presses in separate events, all in a thread-safe, cross-platform way. PyGame was also too bloated for me. So I made the following (in Python 2.7 but I suspect it's easily portable), which I figured I'd share here in case it was useful for anyone else. I stored this in a file named keyPress.py.



    class _Getch:
    """Gets a single character from standard input. Does not echo to the
    screen. From http://code.activestate.com/recipes/134892/"""
    def __init__(self):
    try:
    self.impl = _GetchWindows()
    except ImportError:
    try:
    self.impl = _GetchMacCarbon()
    except(AttributeError, ImportError):
    self.impl = _GetchUnix()

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


    class _GetchUnix:
    def __init__(self):
    import tty, sys, termios # import termios now or else you'll get the Unix version on the Mac

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

    class _GetchMacCarbon:
    """
    A function which returns the current ASCII key that is down;
    if no ASCII key is down, the null string is returned. The
    page http://www.mactech.com/macintosh-c/chap02-1.html was
    very helpful in figuring out how to do this.
    """
    def __init__(self):
    import Carbon
    Carbon.Evt #see if it has this (in Unix, it doesn't)

    def __call__(self):
    import Carbon
    if Carbon.Evt.EventAvail(0x0008)[0]==0: # 0x0008 is the keyDownMask
    return ''
    else:
    #
    # The event contains the following info:
    # (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1]
    #
    # The message (msg) contains the ASCII char which is
    # extracted with the 0x000000FF charCodeMask; this
    # number is converted to an ASCII character with chr() and
    # returned
    #
    (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1]
    return chr(msg & 0x000000FF)

    import threading


    # From https://stackoverflow.com/a/2022629/2924421
    class Event(list):
    def __call__(self, *args, **kwargs):
    for f in self:
    f(*args, **kwargs)

    def __repr__(self):
    return "Event(%s)" % list.__repr__(self)


    def getKey():
    inkey = _Getch()
    import sys
    for i in xrange(sys.maxint):
    k=inkey()
    if k<>'':break
    return k

    class KeyCallbackFunction():
    callbackParam = None
    actualFunction = None

    def __init__(self, actualFunction, callbackParam):
    self.actualFunction = actualFunction
    self.callbackParam = callbackParam

    def doCallback(self, inputKey):
    if not self.actualFunction is None:
    if self.callbackParam is None:
    callbackFunctionThread = threading.Thread(target=self.actualFunction, args=(inputKey,))
    else:
    callbackFunctionThread = threading.Thread(target=self.actualFunction, args=(inputKey,self.callbackParam))

    callbackFunctionThread.daemon = True
    callbackFunctionThread.start()



    class KeyCapture():


    gotKeyLock = threading.Lock()
    gotKeys =
    gotKeyEvent = threading.Event()

    keyBlockingSetKeyLock = threading.Lock()

    addingEventsLock = threading.Lock()
    keyReceiveEvents = Event()


    keysGotLock = threading.Lock()
    keysGot =

    keyBlockingKeyLockLossy = threading.Lock()
    keyBlockingKeyLossy = None
    keyBlockingEventLossy = threading.Event()

    keysBlockingGotLock = threading.Lock()
    keysBlockingGot =
    keyBlockingGotEvent = threading.Event()



    wantToStopLock = threading.Lock()
    wantToStop = False

    stoppedLock = threading.Lock()
    stopped = True

    isRunningEvent = False

    getKeyThread = None

    keyFunction = None
    keyArgs = None

    # Begin capturing keys. A seperate thread is launched that
    # captures key presses, and then these can be received via get,
    # getAsync, and adding an event via addEvent. Note that this
    # will prevent the system to accept keys as normal (say, if
    # you are in a python shell) because it overrides that key
    # capturing behavior.

    # If you start capture when it's already been started, a
    # InterruptedError("Keys are still being captured")
    # will be thrown

    # Note that get(), getAsync() and events are independent, so if a key is pressed:
    #
    # 1: Any calls to get() that are waiting, with lossy on, will return
    # that key
    # 2: It will be stored in the queue of get keys, so that get() with lossy
    # off will return the oldest key pressed not returned by get() yet.
    # 3: All events will be fired with that key as their input
    # 4: It will be stored in the list of getAsync() keys, where that list
    # will be returned and set to empty list on the next call to getAsync().
    # get() call with it, aand add it to the getAsync() list.
    def startCapture(self, keyFunction=None, args=None):
    # Make sure we aren't already capturing keys
    self.stoppedLock.acquire()
    if not self.stopped:
    self.stoppedLock.release()
    raise InterruptedError("Keys are still being captured")
    return
    self.stopped = False
    self.stoppedLock.release()

    # If we have captured before, we need to allow the get() calls to actually
    # wait for key presses now by clearing the event
    if self.keyBlockingEventLossy.is_set():
    self.keyBlockingEventLossy.clear()

    # Have one function that we call every time a key is captured, intended for stopping capture
    # as desired
    self.keyFunction = keyFunction
    self.keyArgs = args

    # Begin capturing keys (in a seperate thread)
    self.getKeyThread = threading.Thread(target=self._threadProcessKeyPresses)
    self.getKeyThread.daemon = True
    self.getKeyThread.start()

    # Process key captures (in a seperate thread)
    self.getKeyThread = threading.Thread(target=self._threadStoreKeyPresses)
    self.getKeyThread.daemon = True
    self.getKeyThread.start()


    def capturing(self):
    self.stoppedLock.acquire()
    isCapturing = not self.stopped
    self.stoppedLock.release()
    return isCapturing
    # Stops the thread that is capturing keys on the first opporunity
    # has to do so. It usually can't stop immediately because getting a key
    # is a blocking process, so this will probably stop capturing after the
    # next key is pressed.
    #
    # However, Sometimes if you call stopCapture it will stop before starting capturing the
    # next key, due to multithreading race conditions. So if you want to stop capturing
    # reliably, call stopCapture in a function added via addEvent. Then you are
    # guaranteed that capturing will stop immediately after the rest of the callback
    # functions are called (before starting to capture the next key).
    def stopCapture(self):
    self.wantToStopLock.acquire()
    self.wantToStop = True
    self.wantToStopLock.release()

    # Takes in a function that will be called every time a key is pressed (with that
    # key passed in as the first paramater in that function)
    def addEvent(self, keyPressEventFunction, args=None):
    self.addingEventsLock.acquire()
    callbackHolder = KeyCallbackFunction(keyPressEventFunction, args)
    self.keyReceiveEvents.append(callbackHolder.doCallback)
    self.addingEventsLock.release()
    def clearEvents(self):
    self.addingEventsLock.acquire()
    self.keyReceiveEvents = Event()
    self.addingEventsLock.release()
    # Gets a key captured by this KeyCapture, blocking until a key is pressed.
    # There is an optional lossy paramater:
    # If True all keys before this call are ignored, and the next pressed key
    # will be returned.
    # If False this will return the oldest key captured that hasn't
    # been returned by get yet. False is the default.
    def get(self, lossy=False):
    if lossy:
    # Wait for the next key to be pressed
    self.keyBlockingEventLossy.wait()
    self.keyBlockingKeyLockLossy.acquire()
    keyReceived = self.keyBlockingKeyLossy
    self.keyBlockingKeyLockLossy.release()
    return keyReceived
    else:
    while True:
    # Wait until a key is pressed
    self.keyBlockingGotEvent.wait()

    # Get the key pressed
    readKey = None
    self.keysBlockingGotLock.acquire()
    # Get a key if it exists
    if len(self.keysBlockingGot) != 0:
    readKey = self.keysBlockingGot.pop(0)
    # If we got the last one, tell us to wait
    if len(self.keysBlockingGot) == 0:
    self.keyBlockingGotEvent.clear()
    self.keysBlockingGotLock.release()

    # Process the key (if it actually exists)
    if not readKey is None:
    return readKey

    # Exit if we are stopping
    self.wantToStopLock.acquire()
    if self.wantToStop:
    self.wantToStopLock.release()
    return None
    self.wantToStopLock.release()




    def clearGetList(self):
    self.keysBlockingGotLock.acquire()
    self.keysBlockingGot =
    self.keysBlockingGotLock.release()

    # Gets a list of all keys pressed since the last call to getAsync, in order
    # from first pressed, second pressed, .., most recent pressed
    def getAsync(self):
    self.keysGotLock.acquire();
    keysPressedList = list(self.keysGot)
    self.keysGot =
    self.keysGotLock.release()
    return keysPressedList

    def clearAsyncList(self):
    self.keysGotLock.acquire();
    self.keysGot =
    self.keysGotLock.release();

    def _processKey(self, readKey):
    # Append to list for GetKeyAsync
    self.keysGotLock.acquire()
    self.keysGot.append(readKey)
    self.keysGotLock.release()

    # Call lossy blocking key events
    self.keyBlockingKeyLockLossy.acquire()
    self.keyBlockingKeyLossy = readKey
    self.keyBlockingEventLossy.set()
    self.keyBlockingEventLossy.clear()
    self.keyBlockingKeyLockLossy.release()

    # Call non-lossy blocking key events
    self.keysBlockingGotLock.acquire()
    self.keysBlockingGot.append(readKey)
    if len(self.keysBlockingGot) == 1:
    self.keyBlockingGotEvent.set()
    self.keysBlockingGotLock.release()

    # Call events added by AddEvent
    self.addingEventsLock.acquire()
    self.keyReceiveEvents(readKey)
    self.addingEventsLock.release()

    def _threadProcessKeyPresses(self):
    while True:
    # Wait until a key is pressed
    self.gotKeyEvent.wait()

    # Get the key pressed
    readKey = None
    self.gotKeyLock.acquire()
    # Get a key if it exists
    if len(self.gotKeys) != 0:
    readKey = self.gotKeys.pop(0)
    # If we got the last one, tell us to wait
    if len(self.gotKeys) == 0:
    self.gotKeyEvent.clear()
    self.gotKeyLock.release()

    # Process the key (if it actually exists)
    if not readKey is None:
    self._processKey(readKey)

    # Exit if we are stopping
    self.wantToStopLock.acquire()
    if self.wantToStop:
    self.wantToStopLock.release()
    break
    self.wantToStopLock.release()

    def _threadStoreKeyPresses(self):
    while True:
    # Get a key
    readKey = getKey()

    # Run the potential shut down function
    if not self.keyFunction is None:
    self.keyFunction(readKey, self.keyArgs)

    # Add the key to the list of pressed keys
    self.gotKeyLock.acquire()
    self.gotKeys.append(readKey)
    if len(self.gotKeys) == 1:
    self.gotKeyEvent.set()
    self.gotKeyLock.release()

    # Exit if we are stopping
    self.wantToStopLock.acquire()
    if self.wantToStop:
    self.wantToStopLock.release()
    self.gotKeyEvent.set()
    break
    self.wantToStopLock.release()


    # If we have reached here we stopped capturing

    # All we need to do to clean up is ensure that
    # all the calls to .get() now return None.
    # To ensure no calls are stuck never returning,
    # we will leave the event set so any tasks waiting
    # for it immediately exit. This will be unset upon
    # starting key capturing again.

    self.stoppedLock.acquire()

    # We also need to set this to True so we can start up
    # capturing again.
    self.stopped = True
    self.stopped = True

    self.keyBlockingKeyLockLossy.acquire()
    self.keyBlockingKeyLossy = None
    self.keyBlockingEventLossy.set()
    self.keyBlockingKeyLockLossy.release()

    self.keysBlockingGotLock.acquire()
    self.keyBlockingGotEvent.set()
    self.keysBlockingGotLock.release()

    self.stoppedLock.release()


    The idea is that you can either simply call keyPress.getKey(), which will read a key from the keyboard, then return it.



    If you want something more than that, I made a KeyCapture object. You can create one via something like keys = keyPress.KeyCapture().



    Then there are three things you can do:



    addEvent(functionName) takes in any function that takes in one parameter. Then every time a key is pressed, this function will be called with that key's string as it's input. These are ran in a separate thread, so you can block all you want in them and it won't mess up the functionality of the KeyCapturer nor delay the other events.



    get() returns a key in the same blocking way as before. It is now needed here because the keys are being captured via the KeyCapture object now, so keyPress.getKey() would conflict with that behavior and both of them would miss some keys since only one key can be captured at a time. Also, say the user presses 'a', then 'b', you call get(), the the user presses 'c'. That get() call will immediately return 'a', then if you call it again it will return 'b', then 'c'. If you call it again it will block until another key is pressed. This ensures that you don't miss any keys, in a blocking way if desired. So in this way it's a little different than keyPress.getKey() from before



    If you want the behavior of getKey() back, get(lossy=True) is like get(), except that it only returns keys pressed after the call to get(). So in the above example, get() would block until the user presses 'c', and then if you call it again it will block until another key is pressed.



    getAsync() is a little different. It's designed for something that does a lot of processing, then occasionally comes back and checks which keys were pressed. Thus getAsync() returns a list of all the keys pressed since the last call to getAsync(), in order from oldest key pressed to most recent key pressed. It also doesn't block, meaning that if no keys have been pressed since the last call to getAsync(), an empty will be returned.



    To actually start capturing keys, you need to call keys.startCapture() with your keys object made above. startCapture is non-blocking, and simply starts one thread that just records the key presses, and another thread to process those key presses. There are two threads to ensure that the thread that records key presses doesn't miss any keys.



    If you want to stop capturing keys, you can call keys.stopCapture() and it will stop capturing keys. However, since capturing a key is a blocking operation, the thread capturing keys might capture one more key after calling stopCapture().



    To prevent this, you can pass in an optional parameter(s) into startCapture(functionName, args) of a function that just does something like checks if a key equals 'c' and then exits. It's important that this function does very little before, for example, a sleep here will cause us to miss keys.



    However, if stopCapture() is called in this function, key captures will be stopped immediately, without trying to capture any more, and that all get() calls will be returned immediately, with None if no keys have been pressed yet.



    Also, since get() and getAsync() store all the previous keys pressed (until you retrieve them), you can call clearGetList() and clearAsyncList() to forget the keys previously pressed.



    Note that get(), getAsync() and events are independent, so if a key is pressed:
    1. One call to get() that is waiting, with lossy on, will return
    that key. The other waiting calls (if any) will continue waiting.
    2. That key will be stored in the queue of get keys, so that get() with lossy off will return the oldest key pressed not returned by get() yet.
    3. All events will be fired with that key as their input
    4. That key will be stored in the list of getAsync() keys, where that lis twill be returned and set to empty list on the next call to getAsync()



    If all this is too much, here is an example use case:



    import keyPress
    import time
    import threading

    def KeyPressed(k, printLock):
    printLock.acquire()
    print "Event: " + k
    printLock.release()
    time.sleep(4)
    printLock.acquire()
    print "Event after delay: " + k
    printLock.release()

    def GetKeyBlocking(keys, printLock):
    while keys.capturing():
    keyReceived = keys.get()
    time.sleep(1)
    printLock.acquire()
    if not keyReceived is None:
    print "Block " + keyReceived
    else:
    print "Block None"
    printLock.release()

    def GetKeyBlockingLossy(keys, printLock):
    while keys.capturing():
    keyReceived = keys.get(lossy=True)
    time.sleep(1)
    printLock.acquire()
    if not keyReceived is None:
    print "Lossy: " + keyReceived
    else:
    print "Lossy: None"
    printLock.release()

    def CheckToClose(k, (keys, printLock)):
    printLock.acquire()
    print "Close: " + k
    printLock.release()
    if k == "c":
    keys.stopCapture()

    printLock = threading.Lock()

    print "Press a key:"
    print "You pressed: " + keyPress.getKey()
    print ""

    keys = keyPress.KeyCapture()

    keys.addEvent(KeyPressed, printLock)



    print "Starting capture"

    keys.startCapture(CheckToClose, (keys, printLock))

    getKeyBlockingThread = threading.Thread(target=GetKeyBlocking, args=(keys, printLock))
    getKeyBlockingThread.daemon = True
    getKeyBlockingThread.start()


    getKeyBlockingThreadLossy = threading.Thread(target=GetKeyBlockingLossy, args=(keys, printLock))
    getKeyBlockingThreadLossy.daemon = True
    getKeyBlockingThreadLossy.start()

    while keys.capturing():
    keysPressed = keys.getAsync()
    printLock.acquire()
    if keysPressed != :
    print "Async: " + str(keysPressed)
    printLock.release()
    time.sleep(1)

    print "done capturing"


    It is working well for me from the simple test I made, but I will happily take others feedback as well if there is something I missed.



    I posted this here as well.






    share|improve this answer

































      3














      This is NON-BLOCKING, reads a key and and stores it in keypress.key.



      import Tkinter as tk


      class Keypress:
      def __init__(self):
      self.root = tk.Tk()
      self.root.geometry('300x200')
      self.root.bind('<KeyPress>', self.onKeyPress)

      def onKeyPress(self, event):
      self.key = event.char

      def __eq__(self, other):
      return self.key == other

      def __str__(self):
      return self.key


      in your programm



      keypress = Keypress()

      while something:
      do something
      if keypress == 'c':
      break
      elif keypress == 'i':
      print('info')
      else:
      print("i dont understand %s" % keypress)





      share|improve this answer





















      • 3





        does this work for command line applications?

        – ThorSummoner
        Jan 23 '15 at 7:36











      • Yes @ThorSummoner

        – Davoud Taghawi-Nejad
        Mar 27 '15 at 3:12






      • 1





        @ThorSummoner: This code has a number of problems — so no, it won't work for command line applications.

        – martineau
        Aug 31 '15 at 0:29











      • It runs for a command line application, given that the windows manager is running.

        – Davoud Taghawi-Nejad
        Aug 31 '15 at 17:36






      • 1





        So basically it doesn't work for command line applications...

        – Mehdi
        Nov 17 '15 at 13:06



















      3














      Try using this: http://home.wlu.edu/~levys/software/kbhit.py
      It's non-blocking (that means that you can have a while loop and detect a key press without stopping it) and cross-platform.



      import os

      # Windows
      if os.name == 'nt':
      import msvcrt

      # Posix (Linux, OS X)
      else:
      import sys
      import termios
      import atexit
      from select import select


      class KBHit:

      def __init__(self):
      '''Creates a KBHit object that you can call to do various keyboard things.'''

      if os.name == 'nt':
      pass

      else:

      # Save the terminal settings
      self.fd = sys.stdin.fileno()
      self.new_term = termios.tcgetattr(self.fd)
      self.old_term = termios.tcgetattr(self.fd)

      # New terminal setting unbuffered
      self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO)
      termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term)

      # Support normal-terminal reset at exit
      atexit.register(self.set_normal_term)


      def set_normal_term(self):
      ''' Resets to normal terminal. On Windows this is a no-op.
      '''

      if os.name == 'nt':
      pass

      else:
      termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term)


      def getch(self):
      ''' Returns a keyboard character after kbhit() has been called.
      Should not be called in the same program as getarrow().
      '''

      s = ''

      if os.name == 'nt':
      return msvcrt.getch().decode('utf-8')

      else:
      return sys.stdin.read(1)


      def getarrow(self):
      ''' Returns an arrow-key code after kbhit() has been called. Codes are
      0 : up
      1 : right
      2 : down
      3 : left
      Should not be called in the same program as getch().
      '''

      if os.name == 'nt':
      msvcrt.getch() # skip 0xE0
      c = msvcrt.getch()
      vals = [72, 77, 80, 75]

      else:
      c = sys.stdin.read(3)[2]
      vals = [65, 67, 66, 68]

      return vals.index(ord(c.decode('utf-8')))


      def kbhit(self):
      ''' Returns True if keyboard character was hit, False otherwise.
      '''
      if os.name == 'nt':
      return msvcrt.kbhit()

      else:
      dr,dw,de = select([sys.stdin], , , 0)
      return dr !=


      An example to use this:



      import kbhit

      kb = kbhit.KBHit()

      while(True):
      print("Key not pressed") #Do something
      if kb.kbhit(): #If a key is pressed:
      k_in = kb.getch() #Detect what key was pressed
      print("You pressed ", k_in, "!") #Do something
      kb.set_normal_term()


      Or you could use the getch module from PyPi. But this would block the while loop






      share|improve this answer

































        2














        Try this with pygame:



        import pygame
        pygame.init() // eliminate error, pygame.error: video system not initialized
        keys = pygame.key.get_pressed()

        if keys[pygame.K_SPACE]:
        d = "space key"

        print "You pressed the", d, "."





        share|improve this answer


























        • That is a neat idea, but it doesn't work on the command line: pygame.error: video system not initialized

          – dirkjot
          Apr 21 '15 at 11:15



















        2














        A comment in one of the other answers mentioned cbreak mode, which is important for Unix implementations because you generally don't want ^C (KeyboardError) to be consumed by getchar (as it will when you set the terminal to raw mode, as done by most other answers).



        Another important detail is that if you're looking to read one character and not one byte, you should read 4 bytes from the input stream, as that's the maximum number of bytes a single character will consist of in UTF-8 (Python 3+). Reading only a single byte will produce unexpected results for multi-byte characters such as keypad arrows.



        Here's my changed implementation for Unix:



        import contextlib
        import os
        import sys
        import termios
        import tty


        _MAX_CHARACTER_BYTE_LENGTH = 4


        @contextlib.contextmanager
        def _tty_reset(file_descriptor):
        """
        A context manager that saves the tty flags of a file descriptor upon
        entering and restores them upon exiting.
        """
        old_settings = termios.tcgetattr(file_descriptor)
        try:
        yield
        finally:
        termios.tcsetattr(file_descriptor, termios.TCSADRAIN, old_settings)


        def get_character(file=sys.stdin):
        """
        Read a single character from the given input stream (defaults to sys.stdin).
        """
        file_descriptor = file.fileno()
        with _tty_reset(file_descriptor):
        tty.setcbreak(file_descriptor)
        return os.read(file_descriptor, _MAX_CHARACTER_BYTE_LENGTH)





        share|improve this answer































          1














          The curses package in python can be used to enter "raw" mode for character input from the terminal with just a few statements. Curses' main use is to take over the screen for output, which may not be what you want. This code snippet uses print() statements instead, which are usable, but you must be aware of how curses changes line endings attached to output.



          #!/usr/bin/python3
          # Demo of single char terminal input in raw mode with the curses package.
          import sys, curses

          def run_one_char(dummy):
          'Run until a carriage return is entered'
          char = ' '
          print('Welcome to curses', flush=True)
          while ord(char) != 13:
          char = one_char()

          def one_char():
          'Read one character from the keyboard'
          print('r? ', flush= True, end = '')

          ## A blocking single char read in raw mode.
          char = sys.stdin.read(1)
          print('You entered %sr' % char)
          return char

          ## Must init curses before calling any functions
          curses.initscr()
          ## To make sure the terminal returns to its initial settings,
          ## and to set raw mode and guarantee cleanup on exit.
          curses.wrapper(run_one_char)
          print('Curses be gone!')





          share|improve this answer































            1














            The ActiveState's recipe seems to contain a little bug for "posix" systems that prevents Ctrl-C from interrupting (I'm using Mac). If I put the following code in my script:



            while(True):
            print(getch())


            I will never be able to terminate the script with Ctrl-C, and I have to kill my terminal to escape.



            I believe the following line is the cause, and it's also too brutal:



            tty.setraw(sys.stdin.fileno())


            Asides from that, package tty is not really needed, termios is enough to handle it.



            Below is the improved code that works for me (Ctrl-C will interrupt), with the extra getche function that echo the char as you type:



            if sys.platform == 'win32':
            import msvcrt
            getch = msvcrt.getch
            getche = msvcrt.getche
            else:
            import sys
            import termios
            def __gen_ch_getter(echo):
            def __fun():
            fd = sys.stdin.fileno()
            oldattr = termios.tcgetattr(fd)
            newattr = oldattr[:]
            try:
            if echo:
            # disable ctrl character printing, otherwise, backspace will be printed as "^?"
            lflag = ~(termios.ICANON | termios.ECHOCTL)
            else:
            lflag = ~(termios.ICANON | termios.ECHO)
            newattr[3] &= lflag
            termios.tcsetattr(fd, termios.TCSADRAIN, newattr)
            ch = sys.stdin.read(1)
            if echo and ord(ch) == 127: # backspace
            # emulate backspace erasing
            # https://stackoverflow.com/a/47962872/404271
            sys.stdout.write('b b')
            finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, oldattr)
            return ch
            return __fun
            getch = __gen_ch_getter(False)
            getche = __gen_ch_getter(True)


            References:




            • https://pypi.python.org/pypi/getch






            share|improve this answer

































              0














              The build-in raw_input should help.



              for i in range(3):
              print ("So much work to do!")
              k = raw_input("Press any key to continue...")
              print ("Ok, back to work.")





              share|improve this answer



















              • 6





                raw_input is waiting for enter key

                – vac
                Dec 16 '15 at 22:03





















              0














              My solution for python3, not depending on any pip packages.



              # precondition: import tty, sys
              def query_yes_no(question, default=True):
              """
              Ask the user a yes/no question.
              Returns immediately upon reading one-char answer.
              Accepts multiple language characters for yes/no.
              """
              if not sys.stdin.isatty():
              return default
              if default:
              prompt = "[Y/n]?"
              other_answers = "n"
              else:
              prompt = "[y/N]?"
              other_answers = "yjosiá"

              print(question,prompt,flush= True,end=" ")
              oldttysettings = tty.tcgetattr(sys.stdin.fileno())
              try:
              tty.setraw(sys.stdin.fileno())
              return not sys.stdin.read(1).lower() in other_answers
              except:
              return default
              finally:
              tty.tcsetattr(sys.stdin.fileno(), tty.TCSADRAIN , oldttysettings)
              sys.stdout.write("rn")
              tty.tcdrain(sys.stdin.fileno())





              share|improve this answer































                0














                I believe that this is one the most elegant solution.



                import os

                if os.name == 'nt':
                import msvcrt
                def getch():
                return msvcrt.getch().decode()
                else:
                import sys, tty, termios
                fd = sys.stdin.fileno()
                old_settings = termios.tcgetattr(fd)
                def getch():
                try:
                tty.setraw(sys.stdin.fileno())
                ch = sys.stdin.read(1)
                finally:
                termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
                return ch


                and then use it in the code:



                if getch() == chr(ESC_ASCII_VALUE):
                print("ESC!")





                share|improve this answer































                  0














                  If I'm doing something complicated I'll use curses to read keys. But a lot of times I just want a simple Python 3 script that uses the standard library and can read arrow keys, so I do this:



                  import sys, termios, tty

                  key_Enter = 13
                  key_Esc = 27
                  key_Up = '33[A'
                  key_Dn = '33[B'
                  key_Rt = '33[C'
                  key_Lt = '33[D'

                  fdInput = sys.stdin.fileno()
                  termAttr = termios.tcgetattr(0)

                  def getch():
                  tty.setraw(fdInput)
                  ch = sys.stdin.buffer.raw.read(4).decode(sys.stdin.encoding)
                  if len(ch) == 1:
                  if ord(ch) < 32 or ord(ch) > 126:
                  ch = ord(ch)
                  elif ord(ch[0]) == 27:
                  ch = '33' + ch[1:]
                  termios.tcsetattr(fdInput, termios.TCSADRAIN, termAttr)
                  return ch





                  share|improve this answer
























                    protected by eyllanesc Jun 23 '18 at 22:25



                    Thank you for your interest in this question.
                    Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



                    Would you like to answer one of these unanswered questions instead?














                    20 Answers
                    20






                    active

                    oldest

                    votes








                    20 Answers
                    20






                    active

                    oldest

                    votes









                    active

                    oldest

                    votes






                    active

                    oldest

                    votes









                    156














                    Here's a link to a site that says how you can read a single character in Windows, Linux and OSX: 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()





                    share|improve this answer





















                    • 14





                      code seems short enough that you could just include it, but +1 for finding a good (cross-platform) answer so quickly.

                      – John Mulder
                      Feb 4 '09 at 7:24






                    • 4





                      Does it handle non-latin (e.g., cyrillic) letters well? I am having a problem with that and can't figure out, if it is my mistake, or not.

                      – Phlya
                      Mar 29 '13 at 18:01






                    • 4





                      I don't like how the ImportError exception is used like some kind of if-statement; why not call platform.system() to check the OS?

                      – Seismoid
                      Sep 21 '14 at 20:19






                    • 9





                      @Seismoid: Asking for forgiveness is generally considered better, see stackoverflow.com/questions/12265451/…

                      – dirkjot
                      Apr 21 '15 at 11:18






                    • 3





                      Doesn't work on OS X: "old_settings = termios.tcgetattr(fd)" "termios.error: (25, 'Inappropriate ioctl for device')"

                      – Sarge Borsch
                      Sep 13 '15 at 18:35


















                    156














                    Here's a link to a site that says how you can read a single character in Windows, Linux and OSX: 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()





                    share|improve this answer





















                    • 14





                      code seems short enough that you could just include it, but +1 for finding a good (cross-platform) answer so quickly.

                      – John Mulder
                      Feb 4 '09 at 7:24






                    • 4





                      Does it handle non-latin (e.g., cyrillic) letters well? I am having a problem with that and can't figure out, if it is my mistake, or not.

                      – Phlya
                      Mar 29 '13 at 18:01






                    • 4





                      I don't like how the ImportError exception is used like some kind of if-statement; why not call platform.system() to check the OS?

                      – Seismoid
                      Sep 21 '14 at 20:19






                    • 9





                      @Seismoid: Asking for forgiveness is generally considered better, see stackoverflow.com/questions/12265451/…

                      – dirkjot
                      Apr 21 '15 at 11:18






                    • 3





                      Doesn't work on OS X: "old_settings = termios.tcgetattr(fd)" "termios.error: (25, 'Inappropriate ioctl for device')"

                      – Sarge Borsch
                      Sep 13 '15 at 18:35
















                    156












                    156








                    156







                    Here's a link to a site that says how you can read a single character in Windows, Linux and OSX: 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()





                    share|improve this answer















                    Here's a link to a site that says how you can read a single character in Windows, Linux and OSX: 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()






                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Jan 2 '16 at 2:34









                    EddieOffermann

                    757




                    757










                    answered Feb 4 '09 at 7:11









                    tehvantehvan

                    7,52742330




                    7,52742330








                    • 14





                      code seems short enough that you could just include it, but +1 for finding a good (cross-platform) answer so quickly.

                      – John Mulder
                      Feb 4 '09 at 7:24






                    • 4





                      Does it handle non-latin (e.g., cyrillic) letters well? I am having a problem with that and can't figure out, if it is my mistake, or not.

                      – Phlya
                      Mar 29 '13 at 18:01






                    • 4





                      I don't like how the ImportError exception is used like some kind of if-statement; why not call platform.system() to check the OS?

                      – Seismoid
                      Sep 21 '14 at 20:19






                    • 9





                      @Seismoid: Asking for forgiveness is generally considered better, see stackoverflow.com/questions/12265451/…

                      – dirkjot
                      Apr 21 '15 at 11:18






                    • 3





                      Doesn't work on OS X: "old_settings = termios.tcgetattr(fd)" "termios.error: (25, 'Inappropriate ioctl for device')"

                      – Sarge Borsch
                      Sep 13 '15 at 18:35
















                    • 14





                      code seems short enough that you could just include it, but +1 for finding a good (cross-platform) answer so quickly.

                      – John Mulder
                      Feb 4 '09 at 7:24






                    • 4





                      Does it handle non-latin (e.g., cyrillic) letters well? I am having a problem with that and can't figure out, if it is my mistake, or not.

                      – Phlya
                      Mar 29 '13 at 18:01






                    • 4





                      I don't like how the ImportError exception is used like some kind of if-statement; why not call platform.system() to check the OS?

                      – Seismoid
                      Sep 21 '14 at 20:19






                    • 9





                      @Seismoid: Asking for forgiveness is generally considered better, see stackoverflow.com/questions/12265451/…

                      – dirkjot
                      Apr 21 '15 at 11:18






                    • 3





                      Doesn't work on OS X: "old_settings = termios.tcgetattr(fd)" "termios.error: (25, 'Inappropriate ioctl for device')"

                      – Sarge Borsch
                      Sep 13 '15 at 18:35










                    14




                    14





                    code seems short enough that you could just include it, but +1 for finding a good (cross-platform) answer so quickly.

                    – John Mulder
                    Feb 4 '09 at 7:24





                    code seems short enough that you could just include it, but +1 for finding a good (cross-platform) answer so quickly.

                    – John Mulder
                    Feb 4 '09 at 7:24




                    4




                    4





                    Does it handle non-latin (e.g., cyrillic) letters well? I am having a problem with that and can't figure out, if it is my mistake, or not.

                    – Phlya
                    Mar 29 '13 at 18:01





                    Does it handle non-latin (e.g., cyrillic) letters well? I am having a problem with that and can't figure out, if it is my mistake, or not.

                    – Phlya
                    Mar 29 '13 at 18:01




                    4




                    4





                    I don't like how the ImportError exception is used like some kind of if-statement; why not call platform.system() to check the OS?

                    – Seismoid
                    Sep 21 '14 at 20:19





                    I don't like how the ImportError exception is used like some kind of if-statement; why not call platform.system() to check the OS?

                    – Seismoid
                    Sep 21 '14 at 20:19




                    9




                    9





                    @Seismoid: Asking for forgiveness is generally considered better, see stackoverflow.com/questions/12265451/…

                    – dirkjot
                    Apr 21 '15 at 11:18





                    @Seismoid: Asking for forgiveness is generally considered better, see stackoverflow.com/questions/12265451/…

                    – dirkjot
                    Apr 21 '15 at 11:18




                    3




                    3





                    Doesn't work on OS X: "old_settings = termios.tcgetattr(fd)" "termios.error: (25, 'Inappropriate ioctl for device')"

                    – Sarge Borsch
                    Sep 13 '15 at 18:35







                    Doesn't work on OS X: "old_settings = termios.tcgetattr(fd)" "termios.error: (25, 'Inappropriate ioctl for device')"

                    – Sarge Borsch
                    Sep 13 '15 at 18:35















                    68














                    sys.stdin.read(1)


                    will basically read 1 byte from STDIN.



                    If you must use the method which does not wait for the n you can use this code as suggested in previous answer:



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


                    (taken from http://code.activestate.com/recipes/134892/)






                    share|improve this answer





















                    • 24





                      I find it odd that sys.stdin.read(1) waits for a n, lol. Thanks for the submission, though.

                      – Evan Fosmark
                      Feb 4 '09 at 8:00






                    • 3





                      One character or one byte? That's not the same.

                      – chryss
                      Feb 4 '09 at 15:08






                    • 4





                      @Evan, that's because python is in line buffered mode by default

                      – John La Rooy
                      Oct 13 '09 at 11:09






                    • 4





                      Note that this code blocks you from using ^C or ^D!

                      – Tim R.
                      Jun 26 '12 at 1:29






                    • 2





                      @EvanFosmark: it's not necessarily that sys.stdin.read(1) waits for n, it's that the terminal program deciding when to send other characters to your program doesn't write them until it sees 'n' - how else would you be able to press backspace and correct what you're typing? (the serious answer to that is - teach the python program to implement the line control, keep a buffer, process backspaces, but that's a different world you may not want to buy into when just "reading a character", and could make your line handling different from all the other programs on your system.)

                      – Tony Delroy
                      Feb 21 '14 at 6:49
















                    68














                    sys.stdin.read(1)


                    will basically read 1 byte from STDIN.



                    If you must use the method which does not wait for the n you can use this code as suggested in previous answer:



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


                    (taken from http://code.activestate.com/recipes/134892/)






                    share|improve this answer





















                    • 24





                      I find it odd that sys.stdin.read(1) waits for a n, lol. Thanks for the submission, though.

                      – Evan Fosmark
                      Feb 4 '09 at 8:00






                    • 3





                      One character or one byte? That's not the same.

                      – chryss
                      Feb 4 '09 at 15:08






                    • 4





                      @Evan, that's because python is in line buffered mode by default

                      – John La Rooy
                      Oct 13 '09 at 11:09






                    • 4





                      Note that this code blocks you from using ^C or ^D!

                      – Tim R.
                      Jun 26 '12 at 1:29






                    • 2





                      @EvanFosmark: it's not necessarily that sys.stdin.read(1) waits for n, it's that the terminal program deciding when to send other characters to your program doesn't write them until it sees 'n' - how else would you be able to press backspace and correct what you're typing? (the serious answer to that is - teach the python program to implement the line control, keep a buffer, process backspaces, but that's a different world you may not want to buy into when just "reading a character", and could make your line handling different from all the other programs on your system.)

                      – Tony Delroy
                      Feb 21 '14 at 6:49














                    68












                    68








                    68







                    sys.stdin.read(1)


                    will basically read 1 byte from STDIN.



                    If you must use the method which does not wait for the n you can use this code as suggested in previous answer:



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


                    (taken from http://code.activestate.com/recipes/134892/)






                    share|improve this answer















                    sys.stdin.read(1)


                    will basically read 1 byte from STDIN.



                    If you must use the method which does not wait for the n you can use this code as suggested in previous answer:



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


                    (taken from http://code.activestate.com/recipes/134892/)







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Oct 18 '12 at 13:16









                    mgilson

                    211k39411528




                    211k39411528










                    answered Feb 4 '09 at 7:30









                    Yuval AdamYuval Adam

                    111k75264362




                    111k75264362








                    • 24





                      I find it odd that sys.stdin.read(1) waits for a n, lol. Thanks for the submission, though.

                      – Evan Fosmark
                      Feb 4 '09 at 8:00






                    • 3





                      One character or one byte? That's not the same.

                      – chryss
                      Feb 4 '09 at 15:08






                    • 4





                      @Evan, that's because python is in line buffered mode by default

                      – John La Rooy
                      Oct 13 '09 at 11:09






                    • 4





                      Note that this code blocks you from using ^C or ^D!

                      – Tim R.
                      Jun 26 '12 at 1:29






                    • 2





                      @EvanFosmark: it's not necessarily that sys.stdin.read(1) waits for n, it's that the terminal program deciding when to send other characters to your program doesn't write them until it sees 'n' - how else would you be able to press backspace and correct what you're typing? (the serious answer to that is - teach the python program to implement the line control, keep a buffer, process backspaces, but that's a different world you may not want to buy into when just "reading a character", and could make your line handling different from all the other programs on your system.)

                      – Tony Delroy
                      Feb 21 '14 at 6:49














                    • 24





                      I find it odd that sys.stdin.read(1) waits for a n, lol. Thanks for the submission, though.

                      – Evan Fosmark
                      Feb 4 '09 at 8:00






                    • 3





                      One character or one byte? That's not the same.

                      – chryss
                      Feb 4 '09 at 15:08






                    • 4





                      @Evan, that's because python is in line buffered mode by default

                      – John La Rooy
                      Oct 13 '09 at 11:09






                    • 4





                      Note that this code blocks you from using ^C or ^D!

                      – Tim R.
                      Jun 26 '12 at 1:29






                    • 2





                      @EvanFosmark: it's not necessarily that sys.stdin.read(1) waits for n, it's that the terminal program deciding when to send other characters to your program doesn't write them until it sees 'n' - how else would you be able to press backspace and correct what you're typing? (the serious answer to that is - teach the python program to implement the line control, keep a buffer, process backspaces, but that's a different world you may not want to buy into when just "reading a character", and could make your line handling different from all the other programs on your system.)

                      – Tony Delroy
                      Feb 21 '14 at 6:49








                    24




                    24





                    I find it odd that sys.stdin.read(1) waits for a n, lol. Thanks for the submission, though.

                    – Evan Fosmark
                    Feb 4 '09 at 8:00





                    I find it odd that sys.stdin.read(1) waits for a n, lol. Thanks for the submission, though.

                    – Evan Fosmark
                    Feb 4 '09 at 8:00




                    3




                    3





                    One character or one byte? That's not the same.

                    – chryss
                    Feb 4 '09 at 15:08





                    One character or one byte? That's not the same.

                    – chryss
                    Feb 4 '09 at 15:08




                    4




                    4





                    @Evan, that's because python is in line buffered mode by default

                    – John La Rooy
                    Oct 13 '09 at 11:09





                    @Evan, that's because python is in line buffered mode by default

                    – John La Rooy
                    Oct 13 '09 at 11:09




                    4




                    4





                    Note that this code blocks you from using ^C or ^D!

                    – Tim R.
                    Jun 26 '12 at 1:29





                    Note that this code blocks you from using ^C or ^D!

                    – Tim R.
                    Jun 26 '12 at 1:29




                    2




                    2





                    @EvanFosmark: it's not necessarily that sys.stdin.read(1) waits for n, it's that the terminal program deciding when to send other characters to your program doesn't write them until it sees 'n' - how else would you be able to press backspace and correct what you're typing? (the serious answer to that is - teach the python program to implement the line control, keep a buffer, process backspaces, but that's a different world you may not want to buy into when just "reading a character", and could make your line handling different from all the other programs on your system.)

                    – Tony Delroy
                    Feb 21 '14 at 6:49





                    @EvanFosmark: it's not necessarily that sys.stdin.read(1) waits for n, it's that the terminal program deciding when to send other characters to your program doesn't write them until it sees 'n' - how else would you be able to press backspace and correct what you're typing? (the serious answer to that is - teach the python program to implement the line control, keep a buffer, process backspaces, but that's a different world you may not want to buy into when just "reading a character", and could make your line handling different from all the other programs on your system.)

                    – Tony Delroy
                    Feb 21 '14 at 6:49











                    59














                    The ActiveState recipe quoted verbatim in two answers is over-engineered. It can be boiled down to this:



                    def _find_getch():
                    try:
                    import termios
                    except ImportError:
                    # Non-POSIX. Return msvcrt's (Windows') getch.
                    import msvcrt
                    return msvcrt.getch

                    # POSIX system. Create and return a getch that manipulates the tty.
                    import sys, tty
                    def _getch():
                    fd = sys.stdin.fileno()
                    old_settings = termios.tcgetattr(fd)
                    try:
                    tty.setraw(fd)
                    ch = sys.stdin.read(1)
                    finally:
                    termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
                    return ch

                    return _getch

                    getch = _find_getch()





                    share|improve this answer




























                      59














                      The ActiveState recipe quoted verbatim in two answers is over-engineered. It can be boiled down to this:



                      def _find_getch():
                      try:
                      import termios
                      except ImportError:
                      # Non-POSIX. Return msvcrt's (Windows') getch.
                      import msvcrt
                      return msvcrt.getch

                      # POSIX system. Create and return a getch that manipulates the tty.
                      import sys, tty
                      def _getch():
                      fd = sys.stdin.fileno()
                      old_settings = termios.tcgetattr(fd)
                      try:
                      tty.setraw(fd)
                      ch = sys.stdin.read(1)
                      finally:
                      termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
                      return ch

                      return _getch

                      getch = _find_getch()





                      share|improve this answer


























                        59












                        59








                        59







                        The ActiveState recipe quoted verbatim in two answers is over-engineered. It can be boiled down to this:



                        def _find_getch():
                        try:
                        import termios
                        except ImportError:
                        # Non-POSIX. Return msvcrt's (Windows') getch.
                        import msvcrt
                        return msvcrt.getch

                        # POSIX system. Create and return a getch that manipulates the tty.
                        import sys, tty
                        def _getch():
                        fd = sys.stdin.fileno()
                        old_settings = termios.tcgetattr(fd)
                        try:
                        tty.setraw(fd)
                        ch = sys.stdin.read(1)
                        finally:
                        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
                        return ch

                        return _getch

                        getch = _find_getch()





                        share|improve this answer













                        The ActiveState recipe quoted verbatim in two answers is over-engineered. It can be boiled down to this:



                        def _find_getch():
                        try:
                        import termios
                        except ImportError:
                        # Non-POSIX. Return msvcrt's (Windows') getch.
                        import msvcrt
                        return msvcrt.getch

                        # POSIX system. Create and return a getch that manipulates the tty.
                        import sys, tty
                        def _getch():
                        fd = sys.stdin.fileno()
                        old_settings = termios.tcgetattr(fd)
                        try:
                        tty.setraw(fd)
                        ch = sys.stdin.read(1)
                        finally:
                        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
                        return ch

                        return _getch

                        getch = _find_getch()






                        share|improve this answer












                        share|improve this answer



                        share|improve this answer










                        answered Feb 9 '14 at 13:27









                        LouisLouis

                        95.1k22184236




                        95.1k22184236























                            40














                            Also worth trying is the readchar library, which is in part based on the ActiveState recipe mentioned in other answers.



                            Installation:



                            pip install readchar


                            Usage:



                            import readchar
                            print("Reading a char:")
                            print(repr(readchar.readchar()))
                            print("Reading a key:")
                            print(repr(readchar.readkey()))


                            Tested on Windows and Linux with Python 2.7.



                            On Windows, only keys which map to letters or ASCII control codes are supported (Backspace, Enter, Esc, Tab, Ctrl+letter). On GNU/Linux (depending on exact terminal, perhaps?) you also get Insert, Delete, Pg Up, Pg Dn, Home, End and F n keys... but then, there's issues separating these special keys from an Esc.



                            Caveat: Like with most (all?) answers in here, signal keys like Ctrl+C, Ctrl+D and Ctrl+Z are caught and returned (as 'x03', 'x04' and 'x1a' respectively); your program can be come difficult to abort.






                            share|improve this answer



















                            • 3





                              Works with Python 3 on Linux as well. Much better than getch, because readchar allows printing to stdout while waiting for key (via threads or asyncio).

                              – wrobell
                              Jun 5 '15 at 20:54






                            • 1





                              Tested on Kubuntu Linux, this works perfectly and is very Pythonic. Thank you!

                              – dotancohen
                              Aug 20 '15 at 13:30











                            • Tested on Win10 + Python 3.5: ERROR:root:'in <string>' requires string as left operand, not bytes Traceback (most recent call last): File "..main.py", line 184, in wrapper result = func(*args, **kwargs) File "C:GitHubPython-Demodemoday_hello.py", line 41, in readch_eg print(readchar.readchar()) File "C:UsersipcjsAppDataLocalProgramsPythonPython35libsite-packagesreadcharreadchar_windows.py", line 14, in readchar while ch in 'x00xe0': TypeError: 'in <string>' requires string as left operand, not bytes

                              – ipcjs
                              Nov 5 '16 at 20:46













                            • @ipcjs please report that bug to the maintainers

                              – Melih Yıldız'
                              Jul 5 '17 at 8:37











                            • this is the best answer. adding a dependency to VS C++ library just for this functionality is crazy.

                              – FistOfFury
                              Dec 26 '17 at 14:54
















                            40














                            Also worth trying is the readchar library, which is in part based on the ActiveState recipe mentioned in other answers.



                            Installation:



                            pip install readchar


                            Usage:



                            import readchar
                            print("Reading a char:")
                            print(repr(readchar.readchar()))
                            print("Reading a key:")
                            print(repr(readchar.readkey()))


                            Tested on Windows and Linux with Python 2.7.



                            On Windows, only keys which map to letters or ASCII control codes are supported (Backspace, Enter, Esc, Tab, Ctrl+letter). On GNU/Linux (depending on exact terminal, perhaps?) you also get Insert, Delete, Pg Up, Pg Dn, Home, End and F n keys... but then, there's issues separating these special keys from an Esc.



                            Caveat: Like with most (all?) answers in here, signal keys like Ctrl+C, Ctrl+D and Ctrl+Z are caught and returned (as 'x03', 'x04' and 'x1a' respectively); your program can be come difficult to abort.






                            share|improve this answer



















                            • 3





                              Works with Python 3 on Linux as well. Much better than getch, because readchar allows printing to stdout while waiting for key (via threads or asyncio).

                              – wrobell
                              Jun 5 '15 at 20:54






                            • 1





                              Tested on Kubuntu Linux, this works perfectly and is very Pythonic. Thank you!

                              – dotancohen
                              Aug 20 '15 at 13:30











                            • Tested on Win10 + Python 3.5: ERROR:root:'in <string>' requires string as left operand, not bytes Traceback (most recent call last): File "..main.py", line 184, in wrapper result = func(*args, **kwargs) File "C:GitHubPython-Demodemoday_hello.py", line 41, in readch_eg print(readchar.readchar()) File "C:UsersipcjsAppDataLocalProgramsPythonPython35libsite-packagesreadcharreadchar_windows.py", line 14, in readchar while ch in 'x00xe0': TypeError: 'in <string>' requires string as left operand, not bytes

                              – ipcjs
                              Nov 5 '16 at 20:46













                            • @ipcjs please report that bug to the maintainers

                              – Melih Yıldız'
                              Jul 5 '17 at 8:37











                            • this is the best answer. adding a dependency to VS C++ library just for this functionality is crazy.

                              – FistOfFury
                              Dec 26 '17 at 14:54














                            40












                            40








                            40







                            Also worth trying is the readchar library, which is in part based on the ActiveState recipe mentioned in other answers.



                            Installation:



                            pip install readchar


                            Usage:



                            import readchar
                            print("Reading a char:")
                            print(repr(readchar.readchar()))
                            print("Reading a key:")
                            print(repr(readchar.readkey()))


                            Tested on Windows and Linux with Python 2.7.



                            On Windows, only keys which map to letters or ASCII control codes are supported (Backspace, Enter, Esc, Tab, Ctrl+letter). On GNU/Linux (depending on exact terminal, perhaps?) you also get Insert, Delete, Pg Up, Pg Dn, Home, End and F n keys... but then, there's issues separating these special keys from an Esc.



                            Caveat: Like with most (all?) answers in here, signal keys like Ctrl+C, Ctrl+D and Ctrl+Z are caught and returned (as 'x03', 'x04' and 'x1a' respectively); your program can be come difficult to abort.






                            share|improve this answer













                            Also worth trying is the readchar library, which is in part based on the ActiveState recipe mentioned in other answers.



                            Installation:



                            pip install readchar


                            Usage:



                            import readchar
                            print("Reading a char:")
                            print(repr(readchar.readchar()))
                            print("Reading a key:")
                            print(repr(readchar.readkey()))


                            Tested on Windows and Linux with Python 2.7.



                            On Windows, only keys which map to letters or ASCII control codes are supported (Backspace, Enter, Esc, Tab, Ctrl+letter). On GNU/Linux (depending on exact terminal, perhaps?) you also get Insert, Delete, Pg Up, Pg Dn, Home, End and F n keys... but then, there's issues separating these special keys from an Esc.



                            Caveat: Like with most (all?) answers in here, signal keys like Ctrl+C, Ctrl+D and Ctrl+Z are caught and returned (as 'x03', 'x04' and 'x1a' respectively); your program can be come difficult to abort.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Aug 16 '14 at 18:47









                            Søren LøvborgSøren Løvborg

                            6,06223435




                            6,06223435








                            • 3





                              Works with Python 3 on Linux as well. Much better than getch, because readchar allows printing to stdout while waiting for key (via threads or asyncio).

                              – wrobell
                              Jun 5 '15 at 20:54






                            • 1





                              Tested on Kubuntu Linux, this works perfectly and is very Pythonic. Thank you!

                              – dotancohen
                              Aug 20 '15 at 13:30











                            • Tested on Win10 + Python 3.5: ERROR:root:'in <string>' requires string as left operand, not bytes Traceback (most recent call last): File "..main.py", line 184, in wrapper result = func(*args, **kwargs) File "C:GitHubPython-Demodemoday_hello.py", line 41, in readch_eg print(readchar.readchar()) File "C:UsersipcjsAppDataLocalProgramsPythonPython35libsite-packagesreadcharreadchar_windows.py", line 14, in readchar while ch in 'x00xe0': TypeError: 'in <string>' requires string as left operand, not bytes

                              – ipcjs
                              Nov 5 '16 at 20:46













                            • @ipcjs please report that bug to the maintainers

                              – Melih Yıldız'
                              Jul 5 '17 at 8:37











                            • this is the best answer. adding a dependency to VS C++ library just for this functionality is crazy.

                              – FistOfFury
                              Dec 26 '17 at 14:54














                            • 3





                              Works with Python 3 on Linux as well. Much better than getch, because readchar allows printing to stdout while waiting for key (via threads or asyncio).

                              – wrobell
                              Jun 5 '15 at 20:54






                            • 1





                              Tested on Kubuntu Linux, this works perfectly and is very Pythonic. Thank you!

                              – dotancohen
                              Aug 20 '15 at 13:30











                            • Tested on Win10 + Python 3.5: ERROR:root:'in <string>' requires string as left operand, not bytes Traceback (most recent call last): File "..main.py", line 184, in wrapper result = func(*args, **kwargs) File "C:GitHubPython-Demodemoday_hello.py", line 41, in readch_eg print(readchar.readchar()) File "C:UsersipcjsAppDataLocalProgramsPythonPython35libsite-packagesreadcharreadchar_windows.py", line 14, in readchar while ch in 'x00xe0': TypeError: 'in <string>' requires string as left operand, not bytes

                              – ipcjs
                              Nov 5 '16 at 20:46













                            • @ipcjs please report that bug to the maintainers

                              – Melih Yıldız'
                              Jul 5 '17 at 8:37











                            • this is the best answer. adding a dependency to VS C++ library just for this functionality is crazy.

                              – FistOfFury
                              Dec 26 '17 at 14:54








                            3




                            3





                            Works with Python 3 on Linux as well. Much better than getch, because readchar allows printing to stdout while waiting for key (via threads or asyncio).

                            – wrobell
                            Jun 5 '15 at 20:54





                            Works with Python 3 on Linux as well. Much better than getch, because readchar allows printing to stdout while waiting for key (via threads or asyncio).

                            – wrobell
                            Jun 5 '15 at 20:54




                            1




                            1





                            Tested on Kubuntu Linux, this works perfectly and is very Pythonic. Thank you!

                            – dotancohen
                            Aug 20 '15 at 13:30





                            Tested on Kubuntu Linux, this works perfectly and is very Pythonic. Thank you!

                            – dotancohen
                            Aug 20 '15 at 13:30













                            Tested on Win10 + Python 3.5: ERROR:root:'in <string>' requires string as left operand, not bytes Traceback (most recent call last): File "..main.py", line 184, in wrapper result = func(*args, **kwargs) File "C:GitHubPython-Demodemoday_hello.py", line 41, in readch_eg print(readchar.readchar()) File "C:UsersipcjsAppDataLocalProgramsPythonPython35libsite-packagesreadcharreadchar_windows.py", line 14, in readchar while ch in 'x00xe0': TypeError: 'in <string>' requires string as left operand, not bytes

                            – ipcjs
                            Nov 5 '16 at 20:46







                            Tested on Win10 + Python 3.5: ERROR:root:'in <string>' requires string as left operand, not bytes Traceback (most recent call last): File "..main.py", line 184, in wrapper result = func(*args, **kwargs) File "C:GitHubPython-Demodemoday_hello.py", line 41, in readch_eg print(readchar.readchar()) File "C:UsersipcjsAppDataLocalProgramsPythonPython35libsite-packagesreadcharreadchar_windows.py", line 14, in readchar while ch in 'x00xe0': TypeError: 'in <string>' requires string as left operand, not bytes

                            – ipcjs
                            Nov 5 '16 at 20:46















                            @ipcjs please report that bug to the maintainers

                            – Melih Yıldız'
                            Jul 5 '17 at 8:37





                            @ipcjs please report that bug to the maintainers

                            – Melih Yıldız'
                            Jul 5 '17 at 8:37













                            this is the best answer. adding a dependency to VS C++ library just for this functionality is crazy.

                            – FistOfFury
                            Dec 26 '17 at 14:54





                            this is the best answer. adding a dependency to VS C++ library just for this functionality is crazy.

                            – FistOfFury
                            Dec 26 '17 at 14:54











                            15














                            An alternative method:



                            import os
                            import sys
                            import termios
                            import fcntl

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


                            From this blog post.






                            share|improve this answer


























                            • Does not seem to work for me - returns empty string immediately upon calling. On Linux with Python 3.6.

                              – Marein
                              Apr 6 '17 at 17:40








                            • 1





                              @Marein If you want it to block (wait for input), remove the | os.O_NONBLOCK. Otherwise, you can put it in a loop (good idea to sleep for a bit in the loop to keep from spinning).

                              – Chris Gregg
                              Feb 4 at 16:55
















                            15














                            An alternative method:



                            import os
                            import sys
                            import termios
                            import fcntl

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


                            From this blog post.






                            share|improve this answer


























                            • Does not seem to work for me - returns empty string immediately upon calling. On Linux with Python 3.6.

                              – Marein
                              Apr 6 '17 at 17:40








                            • 1





                              @Marein If you want it to block (wait for input), remove the | os.O_NONBLOCK. Otherwise, you can put it in a loop (good idea to sleep for a bit in the loop to keep from spinning).

                              – Chris Gregg
                              Feb 4 at 16:55














                            15












                            15








                            15







                            An alternative method:



                            import os
                            import sys
                            import termios
                            import fcntl

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


                            From this blog post.






                            share|improve this answer















                            An alternative method:



                            import os
                            import sys
                            import termios
                            import fcntl

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


                            From this blog post.







                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited May 22 '12 at 0:13









                            jdi

                            70k14121161




                            70k14121161










                            answered Aug 31 '11 at 15:30









                            TylerTyler

                            24k1177100




                            24k1177100













                            • Does not seem to work for me - returns empty string immediately upon calling. On Linux with Python 3.6.

                              – Marein
                              Apr 6 '17 at 17:40








                            • 1





                              @Marein If you want it to block (wait for input), remove the | os.O_NONBLOCK. Otherwise, you can put it in a loop (good idea to sleep for a bit in the loop to keep from spinning).

                              – Chris Gregg
                              Feb 4 at 16:55



















                            • Does not seem to work for me - returns empty string immediately upon calling. On Linux with Python 3.6.

                              – Marein
                              Apr 6 '17 at 17:40








                            • 1





                              @Marein If you want it to block (wait for input), remove the | os.O_NONBLOCK. Otherwise, you can put it in a loop (good idea to sleep for a bit in the loop to keep from spinning).

                              – Chris Gregg
                              Feb 4 at 16:55

















                            Does not seem to work for me - returns empty string immediately upon calling. On Linux with Python 3.6.

                            – Marein
                            Apr 6 '17 at 17:40







                            Does not seem to work for me - returns empty string immediately upon calling. On Linux with Python 3.6.

                            – Marein
                            Apr 6 '17 at 17:40






                            1




                            1





                            @Marein If you want it to block (wait for input), remove the | os.O_NONBLOCK. Otherwise, you can put it in a loop (good idea to sleep for a bit in the loop to keep from spinning).

                            – Chris Gregg
                            Feb 4 at 16:55





                            @Marein If you want it to block (wait for input), remove the | os.O_NONBLOCK. Otherwise, you can put it in a loop (good idea to sleep for a bit in the loop to keep from spinning).

                            – Chris Gregg
                            Feb 4 at 16:55











                            12














                            I think it gets extremely clunky at this point, and debugging on the different platforms is a big mess.



                            You'd be better off using something like pyglet, pygame, cocos2d - if you are doing something more elaborate than this and will need visuals, OR curses if you are going to work with the terminal.



                            Curses is standard: http://docs.python.org/library/curses.html






                            share|improve this answer



















                            • 10





                              I strongly disagree with this. To use curses you have to initscr() the terminal which clears the screen. This is unwanted behavior if the user only wants to use curses to get userinput without n.

                              – dman
                              Jun 26 '13 at 20:22
















                            12














                            I think it gets extremely clunky at this point, and debugging on the different platforms is a big mess.



                            You'd be better off using something like pyglet, pygame, cocos2d - if you are doing something more elaborate than this and will need visuals, OR curses if you are going to work with the terminal.



                            Curses is standard: http://docs.python.org/library/curses.html






                            share|improve this answer



















                            • 10





                              I strongly disagree with this. To use curses you have to initscr() the terminal which clears the screen. This is unwanted behavior if the user only wants to use curses to get userinput without n.

                              – dman
                              Jun 26 '13 at 20:22














                            12












                            12








                            12







                            I think it gets extremely clunky at this point, and debugging on the different platforms is a big mess.



                            You'd be better off using something like pyglet, pygame, cocos2d - if you are doing something more elaborate than this and will need visuals, OR curses if you are going to work with the terminal.



                            Curses is standard: http://docs.python.org/library/curses.html






                            share|improve this answer













                            I think it gets extremely clunky at this point, and debugging on the different platforms is a big mess.



                            You'd be better off using something like pyglet, pygame, cocos2d - if you are doing something more elaborate than this and will need visuals, OR curses if you are going to work with the terminal.



                            Curses is standard: http://docs.python.org/library/curses.html







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Feb 4 '09 at 11:04









                            nachiknachik

                            4813811




                            4813811








                            • 10





                              I strongly disagree with this. To use curses you have to initscr() the terminal which clears the screen. This is unwanted behavior if the user only wants to use curses to get userinput without n.

                              – dman
                              Jun 26 '13 at 20:22














                            • 10





                              I strongly disagree with this. To use curses you have to initscr() the terminal which clears the screen. This is unwanted behavior if the user only wants to use curses to get userinput without n.

                              – dman
                              Jun 26 '13 at 20:22








                            10




                            10





                            I strongly disagree with this. To use curses you have to initscr() the terminal which clears the screen. This is unwanted behavior if the user only wants to use curses to get userinput without n.

                            – dman
                            Jun 26 '13 at 20:22





                            I strongly disagree with this. To use curses you have to initscr() the terminal which clears the screen. This is unwanted behavior if the user only wants to use curses to get userinput without n.

                            – dman
                            Jun 26 '13 at 20:22











                            8














                            This code, based off here, will correctly raise KeyboardInterrupt and EOFError if Ctrl+C or Ctrl+D are pressed.



                            Should work on Windows and Linux. An OS X version is available from the original source.



                            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):
                            char = self.impl()
                            if char == 'x03':
                            raise KeyboardInterrupt
                            elif char == 'x04':
                            raise EOFError
                            return char

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

                            def __call__(self):
                            import sys
                            import tty
                            import 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()





                            share|improve this answer
























                            • This code waits for n.

                              – ChaimG
                              Nov 15 '16 at 14:48
















                            8














                            This code, based off here, will correctly raise KeyboardInterrupt and EOFError if Ctrl+C or Ctrl+D are pressed.



                            Should work on Windows and Linux. An OS X version is available from the original source.



                            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):
                            char = self.impl()
                            if char == 'x03':
                            raise KeyboardInterrupt
                            elif char == 'x04':
                            raise EOFError
                            return char

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

                            def __call__(self):
                            import sys
                            import tty
                            import 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()





                            share|improve this answer
























                            • This code waits for n.

                              – ChaimG
                              Nov 15 '16 at 14:48














                            8












                            8








                            8







                            This code, based off here, will correctly raise KeyboardInterrupt and EOFError if Ctrl+C or Ctrl+D are pressed.



                            Should work on Windows and Linux. An OS X version is available from the original source.



                            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):
                            char = self.impl()
                            if char == 'x03':
                            raise KeyboardInterrupt
                            elif char == 'x04':
                            raise EOFError
                            return char

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

                            def __call__(self):
                            import sys
                            import tty
                            import 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()





                            share|improve this answer













                            This code, based off here, will correctly raise KeyboardInterrupt and EOFError if Ctrl+C or Ctrl+D are pressed.



                            Should work on Windows and Linux. An OS X version is available from the original source.



                            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):
                            char = self.impl()
                            if char == 'x03':
                            raise KeyboardInterrupt
                            elif char == 'x04':
                            raise EOFError
                            return char

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

                            def __call__(self):
                            import sys
                            import tty
                            import 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()






                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Jan 1 '14 at 5:13









                            kirikiri

                            1,07411437




                            1,07411437













                            • This code waits for n.

                              – ChaimG
                              Nov 15 '16 at 14:48



















                            • This code waits for n.

                              – ChaimG
                              Nov 15 '16 at 14:48

















                            This code waits for n.

                            – ChaimG
                            Nov 15 '16 at 14:48





                            This code waits for n.

                            – ChaimG
                            Nov 15 '16 at 14:48











                            6














                            The (currently) top-ranked answer (with the ActiveState code) is overly complicated. I don't see a reason to use classes when a mere function should suffice. Below are two implementations that accomplish the same thing but with more readable code.



                            Both of these implementations:




                            1. work just fine in Python 2 or Python 3

                            2. work on Windows, OSX, and Linux

                            3. read just one byte (i.e., they don't wait for a newline)

                            4. don't depend on any external libraries

                            5. are self-contained (no code outside of the function definition)


                            Version 1: readable and simple



                            def getChar():
                            try:
                            # for Windows-based systems
                            import msvcrt # If successful, we are on Windows
                            return msvcrt.getch()

                            except ImportError:
                            # for POSIX-based systems (with termios & tty support)
                            import tty, sys, termios # raises ImportError if unsupported

                            fd = sys.stdin.fileno()
                            oldSettings = termios.tcgetattr(fd)

                            try:
                            tty.setcbreak(fd)
                            answer = sys.stdin.read(1)
                            finally:
                            termios.tcsetattr(fd, termios.TCSADRAIN, oldSettings)

                            return answer


                            Version 2: avoid repeated imports and exception handling:



                            [EDIT] I missed one advantage of the ActiveState code. If you plan to read characters multiple times, that code avoids the (negligible) cost of repeating the Windows import and the ImportError exception handling on Unix-like systems. While you probably should be more concerned about code readability than that negligible optimization, here is an alternative (it is similar to Louis's answer, but getChar() is self-contained) that functions the same as the ActiveState code and is more readable:



                            def getChar():
                            # figure out which function to use once, and store it in _func
                            if "_func" not in getChar.__dict__:
                            try:
                            # for Windows-based systems
                            import msvcrt # If successful, we are on Windows
                            getChar._func=msvcrt.getch

                            except ImportError:
                            # for POSIX-based systems (with termios & tty support)
                            import tty, sys, termios # raises ImportError if unsupported

                            def _ttyRead():
                            fd = sys.stdin.fileno()
                            oldSettings = termios.tcgetattr(fd)

                            try:
                            tty.setcbreak(fd)
                            answer = sys.stdin.read(1)
                            finally:
                            termios.tcsetattr(fd, termios.TCSADRAIN, oldSettings)

                            return answer

                            getChar._func=_ttyRead

                            return getChar._func()


                            Example code that exercises either of the getChar() versions above:



                            from __future__ import print_function # put at top of file if using Python 2

                            # Example of a prompt for one character of input
                            promptStr = "Please give me a character:"
                            responseStr = "Thank you for giving me a '{}'."
                            print(promptStr, end="n> ")
                            answer = getChar()
                            print("n")
                            print(responseStr.format(answer))





                            share|improve this answer





















                            • 1





                              I ran into an issue with tty.setraw() when printing messages while simultaneously waiting for a key (multi-threaded). Long story short, I found that using tty.setcbreak() lets you get a single character without breaking all the other normal stuff. Long story in this answer

                              – TheDavidFactor
                              May 21 '16 at 3:50











                            • Nice, I was hoping there would be a cleaner way of doing this

                              – Phylliida
                              May 5 '17 at 18:00
















                            6














                            The (currently) top-ranked answer (with the ActiveState code) is overly complicated. I don't see a reason to use classes when a mere function should suffice. Below are two implementations that accomplish the same thing but with more readable code.



                            Both of these implementations:




                            1. work just fine in Python 2 or Python 3

                            2. work on Windows, OSX, and Linux

                            3. read just one byte (i.e., they don't wait for a newline)

                            4. don't depend on any external libraries

                            5. are self-contained (no code outside of the function definition)


                            Version 1: readable and simple



                            def getChar():
                            try:
                            # for Windows-based systems
                            import msvcrt # If successful, we are on Windows
                            return msvcrt.getch()

                            except ImportError:
                            # for POSIX-based systems (with termios & tty support)
                            import tty, sys, termios # raises ImportError if unsupported

                            fd = sys.stdin.fileno()
                            oldSettings = termios.tcgetattr(fd)

                            try:
                            tty.setcbreak(fd)
                            answer = sys.stdin.read(1)
                            finally:
                            termios.tcsetattr(fd, termios.TCSADRAIN, oldSettings)

                            return answer


                            Version 2: avoid repeated imports and exception handling:



                            [EDIT] I missed one advantage of the ActiveState code. If you plan to read characters multiple times, that code avoids the (negligible) cost of repeating the Windows import and the ImportError exception handling on Unix-like systems. While you probably should be more concerned about code readability than that negligible optimization, here is an alternative (it is similar to Louis's answer, but getChar() is self-contained) that functions the same as the ActiveState code and is more readable:



                            def getChar():
                            # figure out which function to use once, and store it in _func
                            if "_func" not in getChar.__dict__:
                            try:
                            # for Windows-based systems
                            import msvcrt # If successful, we are on Windows
                            getChar._func=msvcrt.getch

                            except ImportError:
                            # for POSIX-based systems (with termios & tty support)
                            import tty, sys, termios # raises ImportError if unsupported

                            def _ttyRead():
                            fd = sys.stdin.fileno()
                            oldSettings = termios.tcgetattr(fd)

                            try:
                            tty.setcbreak(fd)
                            answer = sys.stdin.read(1)
                            finally:
                            termios.tcsetattr(fd, termios.TCSADRAIN, oldSettings)

                            return answer

                            getChar._func=_ttyRead

                            return getChar._func()


                            Example code that exercises either of the getChar() versions above:



                            from __future__ import print_function # put at top of file if using Python 2

                            # Example of a prompt for one character of input
                            promptStr = "Please give me a character:"
                            responseStr = "Thank you for giving me a '{}'."
                            print(promptStr, end="n> ")
                            answer = getChar()
                            print("n")
                            print(responseStr.format(answer))





                            share|improve this answer





















                            • 1





                              I ran into an issue with tty.setraw() when printing messages while simultaneously waiting for a key (multi-threaded). Long story short, I found that using tty.setcbreak() lets you get a single character without breaking all the other normal stuff. Long story in this answer

                              – TheDavidFactor
                              May 21 '16 at 3:50











                            • Nice, I was hoping there would be a cleaner way of doing this

                              – Phylliida
                              May 5 '17 at 18:00














                            6












                            6








                            6







                            The (currently) top-ranked answer (with the ActiveState code) is overly complicated. I don't see a reason to use classes when a mere function should suffice. Below are two implementations that accomplish the same thing but with more readable code.



                            Both of these implementations:




                            1. work just fine in Python 2 or Python 3

                            2. work on Windows, OSX, and Linux

                            3. read just one byte (i.e., they don't wait for a newline)

                            4. don't depend on any external libraries

                            5. are self-contained (no code outside of the function definition)


                            Version 1: readable and simple



                            def getChar():
                            try:
                            # for Windows-based systems
                            import msvcrt # If successful, we are on Windows
                            return msvcrt.getch()

                            except ImportError:
                            # for POSIX-based systems (with termios & tty support)
                            import tty, sys, termios # raises ImportError if unsupported

                            fd = sys.stdin.fileno()
                            oldSettings = termios.tcgetattr(fd)

                            try:
                            tty.setcbreak(fd)
                            answer = sys.stdin.read(1)
                            finally:
                            termios.tcsetattr(fd, termios.TCSADRAIN, oldSettings)

                            return answer


                            Version 2: avoid repeated imports and exception handling:



                            [EDIT] I missed one advantage of the ActiveState code. If you plan to read characters multiple times, that code avoids the (negligible) cost of repeating the Windows import and the ImportError exception handling on Unix-like systems. While you probably should be more concerned about code readability than that negligible optimization, here is an alternative (it is similar to Louis's answer, but getChar() is self-contained) that functions the same as the ActiveState code and is more readable:



                            def getChar():
                            # figure out which function to use once, and store it in _func
                            if "_func" not in getChar.__dict__:
                            try:
                            # for Windows-based systems
                            import msvcrt # If successful, we are on Windows
                            getChar._func=msvcrt.getch

                            except ImportError:
                            # for POSIX-based systems (with termios & tty support)
                            import tty, sys, termios # raises ImportError if unsupported

                            def _ttyRead():
                            fd = sys.stdin.fileno()
                            oldSettings = termios.tcgetattr(fd)

                            try:
                            tty.setcbreak(fd)
                            answer = sys.stdin.read(1)
                            finally:
                            termios.tcsetattr(fd, termios.TCSADRAIN, oldSettings)

                            return answer

                            getChar._func=_ttyRead

                            return getChar._func()


                            Example code that exercises either of the getChar() versions above:



                            from __future__ import print_function # put at top of file if using Python 2

                            # Example of a prompt for one character of input
                            promptStr = "Please give me a character:"
                            responseStr = "Thank you for giving me a '{}'."
                            print(promptStr, end="n> ")
                            answer = getChar()
                            print("n")
                            print(responseStr.format(answer))





                            share|improve this answer















                            The (currently) top-ranked answer (with the ActiveState code) is overly complicated. I don't see a reason to use classes when a mere function should suffice. Below are two implementations that accomplish the same thing but with more readable code.



                            Both of these implementations:




                            1. work just fine in Python 2 or Python 3

                            2. work on Windows, OSX, and Linux

                            3. read just one byte (i.e., they don't wait for a newline)

                            4. don't depend on any external libraries

                            5. are self-contained (no code outside of the function definition)


                            Version 1: readable and simple



                            def getChar():
                            try:
                            # for Windows-based systems
                            import msvcrt # If successful, we are on Windows
                            return msvcrt.getch()

                            except ImportError:
                            # for POSIX-based systems (with termios & tty support)
                            import tty, sys, termios # raises ImportError if unsupported

                            fd = sys.stdin.fileno()
                            oldSettings = termios.tcgetattr(fd)

                            try:
                            tty.setcbreak(fd)
                            answer = sys.stdin.read(1)
                            finally:
                            termios.tcsetattr(fd, termios.TCSADRAIN, oldSettings)

                            return answer


                            Version 2: avoid repeated imports and exception handling:



                            [EDIT] I missed one advantage of the ActiveState code. If you plan to read characters multiple times, that code avoids the (negligible) cost of repeating the Windows import and the ImportError exception handling on Unix-like systems. While you probably should be more concerned about code readability than that negligible optimization, here is an alternative (it is similar to Louis's answer, but getChar() is self-contained) that functions the same as the ActiveState code and is more readable:



                            def getChar():
                            # figure out which function to use once, and store it in _func
                            if "_func" not in getChar.__dict__:
                            try:
                            # for Windows-based systems
                            import msvcrt # If successful, we are on Windows
                            getChar._func=msvcrt.getch

                            except ImportError:
                            # for POSIX-based systems (with termios & tty support)
                            import tty, sys, termios # raises ImportError if unsupported

                            def _ttyRead():
                            fd = sys.stdin.fileno()
                            oldSettings = termios.tcgetattr(fd)

                            try:
                            tty.setcbreak(fd)
                            answer = sys.stdin.read(1)
                            finally:
                            termios.tcsetattr(fd, termios.TCSADRAIN, oldSettings)

                            return answer

                            getChar._func=_ttyRead

                            return getChar._func()


                            Example code that exercises either of the getChar() versions above:



                            from __future__ import print_function # put at top of file if using Python 2

                            # Example of a prompt for one character of input
                            promptStr = "Please give me a character:"
                            responseStr = "Thank you for giving me a '{}'."
                            print(promptStr, end="n> ")
                            answer = getChar()
                            print("n")
                            print(responseStr.format(answer))






                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Aug 24 '17 at 7:03









                            lucid_dreamer

                            17329




                            17329










                            answered May 2 '16 at 2:49









                            Matthew Strax-HaberMatthew Strax-Haber

                            7114




                            7114








                            • 1





                              I ran into an issue with tty.setraw() when printing messages while simultaneously waiting for a key (multi-threaded). Long story short, I found that using tty.setcbreak() lets you get a single character without breaking all the other normal stuff. Long story in this answer

                              – TheDavidFactor
                              May 21 '16 at 3:50











                            • Nice, I was hoping there would be a cleaner way of doing this

                              – Phylliida
                              May 5 '17 at 18:00














                            • 1





                              I ran into an issue with tty.setraw() when printing messages while simultaneously waiting for a key (multi-threaded). Long story short, I found that using tty.setcbreak() lets you get a single character without breaking all the other normal stuff. Long story in this answer

                              – TheDavidFactor
                              May 21 '16 at 3:50











                            • Nice, I was hoping there would be a cleaner way of doing this

                              – Phylliida
                              May 5 '17 at 18:00








                            1




                            1





                            I ran into an issue with tty.setraw() when printing messages while simultaneously waiting for a key (multi-threaded). Long story short, I found that using tty.setcbreak() lets you get a single character without breaking all the other normal stuff. Long story in this answer

                            – TheDavidFactor
                            May 21 '16 at 3:50





                            I ran into an issue with tty.setraw() when printing messages while simultaneously waiting for a key (multi-threaded). Long story short, I found that using tty.setcbreak() lets you get a single character without breaking all the other normal stuff. Long story in this answer

                            – TheDavidFactor
                            May 21 '16 at 3:50













                            Nice, I was hoping there would be a cleaner way of doing this

                            – Phylliida
                            May 5 '17 at 18:00





                            Nice, I was hoping there would be a cleaner way of doing this

                            – Phylliida
                            May 5 '17 at 18:00











                            4














                            This might be a use case for a context manager. Leaving aside allowances for Windows OS, here's my suggestion:



                            #!/usr/bin/env python3
                            # file: 'readchar.py'
                            """
                            Implementation of a way to get a single character of input
                            without waiting for the user to hit <Enter>.
                            (OS is Linux, Ubuntu 14.04)
                            """

                            import tty, sys, termios

                            class ReadChar():
                            def __enter__(self):
                            self.fd = sys.stdin.fileno()
                            self.old_settings = termios.tcgetattr(self.fd)
                            tty.setraw(sys.stdin.fileno())
                            return sys.stdin.read(1)
                            def __exit__(self, type, value, traceback):
                            termios.tcsetattr(self.fd, termios.TCSADRAIN, self.old_settings)

                            def test():
                            while True:
                            with ReadChar() as rc:
                            char = rc
                            if ord(char) <= 32:
                            print("You entered character with ordinal {}."
                            .format(ord(char)))
                            else:
                            print("You entered character '{}'."
                            .format(char))
                            if char in "^C^D":
                            sys.exit()

                            if __name__ == "__main__":
                            test()





                            share|improve this answer


























                            • You could also return self in __enter__ and have a read method that returns sys.stdin.read(1), then you could read multiple characters in one context.

                              – L3viathan
                              Apr 12 '17 at 6:46
















                            4














                            This might be a use case for a context manager. Leaving aside allowances for Windows OS, here's my suggestion:



                            #!/usr/bin/env python3
                            # file: 'readchar.py'
                            """
                            Implementation of a way to get a single character of input
                            without waiting for the user to hit <Enter>.
                            (OS is Linux, Ubuntu 14.04)
                            """

                            import tty, sys, termios

                            class ReadChar():
                            def __enter__(self):
                            self.fd = sys.stdin.fileno()
                            self.old_settings = termios.tcgetattr(self.fd)
                            tty.setraw(sys.stdin.fileno())
                            return sys.stdin.read(1)
                            def __exit__(self, type, value, traceback):
                            termios.tcsetattr(self.fd, termios.TCSADRAIN, self.old_settings)

                            def test():
                            while True:
                            with ReadChar() as rc:
                            char = rc
                            if ord(char) <= 32:
                            print("You entered character with ordinal {}."
                            .format(ord(char)))
                            else:
                            print("You entered character '{}'."
                            .format(char))
                            if char in "^C^D":
                            sys.exit()

                            if __name__ == "__main__":
                            test()





                            share|improve this answer


























                            • You could also return self in __enter__ and have a read method that returns sys.stdin.read(1), then you could read multiple characters in one context.

                              – L3viathan
                              Apr 12 '17 at 6:46














                            4












                            4








                            4







                            This might be a use case for a context manager. Leaving aside allowances for Windows OS, here's my suggestion:



                            #!/usr/bin/env python3
                            # file: 'readchar.py'
                            """
                            Implementation of a way to get a single character of input
                            without waiting for the user to hit <Enter>.
                            (OS is Linux, Ubuntu 14.04)
                            """

                            import tty, sys, termios

                            class ReadChar():
                            def __enter__(self):
                            self.fd = sys.stdin.fileno()
                            self.old_settings = termios.tcgetattr(self.fd)
                            tty.setraw(sys.stdin.fileno())
                            return sys.stdin.read(1)
                            def __exit__(self, type, value, traceback):
                            termios.tcsetattr(self.fd, termios.TCSADRAIN, self.old_settings)

                            def test():
                            while True:
                            with ReadChar() as rc:
                            char = rc
                            if ord(char) <= 32:
                            print("You entered character with ordinal {}."
                            .format(ord(char)))
                            else:
                            print("You entered character '{}'."
                            .format(char))
                            if char in "^C^D":
                            sys.exit()

                            if __name__ == "__main__":
                            test()





                            share|improve this answer















                            This might be a use case for a context manager. Leaving aside allowances for Windows OS, here's my suggestion:



                            #!/usr/bin/env python3
                            # file: 'readchar.py'
                            """
                            Implementation of a way to get a single character of input
                            without waiting for the user to hit <Enter>.
                            (OS is Linux, Ubuntu 14.04)
                            """

                            import tty, sys, termios

                            class ReadChar():
                            def __enter__(self):
                            self.fd = sys.stdin.fileno()
                            self.old_settings = termios.tcgetattr(self.fd)
                            tty.setraw(sys.stdin.fileno())
                            return sys.stdin.read(1)
                            def __exit__(self, type, value, traceback):
                            termios.tcsetattr(self.fd, termios.TCSADRAIN, self.old_settings)

                            def test():
                            while True:
                            with ReadChar() as rc:
                            char = rc
                            if ord(char) <= 32:
                            print("You entered character with ordinal {}."
                            .format(ord(char)))
                            else:
                            print("You entered character '{}'."
                            .format(char))
                            if char in "^C^D":
                            sys.exit()

                            if __name__ == "__main__":
                            test()






                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Sep 28 '14 at 20:24









                            ThP

                            1,87121423




                            1,87121423










                            answered Sep 28 '14 at 20:07









                            Alex KleiderAlex Kleider

                            411




                            411













                            • You could also return self in __enter__ and have a read method that returns sys.stdin.read(1), then you could read multiple characters in one context.

                              – L3viathan
                              Apr 12 '17 at 6:46



















                            • You could also return self in __enter__ and have a read method that returns sys.stdin.read(1), then you could read multiple characters in one context.

                              – L3viathan
                              Apr 12 '17 at 6:46

















                            You could also return self in __enter__ and have a read method that returns sys.stdin.read(1), then you could read multiple characters in one context.

                            – L3viathan
                            Apr 12 '17 at 6:46





                            You could also return self in __enter__ and have a read method that returns sys.stdin.read(1), then you could read multiple characters in one context.

                            – L3viathan
                            Apr 12 '17 at 6:46











                            4














                            The answers here were informative, however I also wanted a way to get key presses asynchronously and fire off key presses in separate events, all in a thread-safe, cross-platform way. PyGame was also too bloated for me. So I made the following (in Python 2.7 but I suspect it's easily portable), which I figured I'd share here in case it was useful for anyone else. I stored this in a file named keyPress.py.



                            class _Getch:
                            """Gets a single character from standard input. Does not echo to the
                            screen. From http://code.activestate.com/recipes/134892/"""
                            def __init__(self):
                            try:
                            self.impl = _GetchWindows()
                            except ImportError:
                            try:
                            self.impl = _GetchMacCarbon()
                            except(AttributeError, ImportError):
                            self.impl = _GetchUnix()

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


                            class _GetchUnix:
                            def __init__(self):
                            import tty, sys, termios # import termios now or else you'll get the Unix version on the Mac

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

                            class _GetchMacCarbon:
                            """
                            A function which returns the current ASCII key that is down;
                            if no ASCII key is down, the null string is returned. The
                            page http://www.mactech.com/macintosh-c/chap02-1.html was
                            very helpful in figuring out how to do this.
                            """
                            def __init__(self):
                            import Carbon
                            Carbon.Evt #see if it has this (in Unix, it doesn't)

                            def __call__(self):
                            import Carbon
                            if Carbon.Evt.EventAvail(0x0008)[0]==0: # 0x0008 is the keyDownMask
                            return ''
                            else:
                            #
                            # The event contains the following info:
                            # (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1]
                            #
                            # The message (msg) contains the ASCII char which is
                            # extracted with the 0x000000FF charCodeMask; this
                            # number is converted to an ASCII character with chr() and
                            # returned
                            #
                            (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1]
                            return chr(msg & 0x000000FF)

                            import threading


                            # From https://stackoverflow.com/a/2022629/2924421
                            class Event(list):
                            def __call__(self, *args, **kwargs):
                            for f in self:
                            f(*args, **kwargs)

                            def __repr__(self):
                            return "Event(%s)" % list.__repr__(self)


                            def getKey():
                            inkey = _Getch()
                            import sys
                            for i in xrange(sys.maxint):
                            k=inkey()
                            if k<>'':break
                            return k

                            class KeyCallbackFunction():
                            callbackParam = None
                            actualFunction = None

                            def __init__(self, actualFunction, callbackParam):
                            self.actualFunction = actualFunction
                            self.callbackParam = callbackParam

                            def doCallback(self, inputKey):
                            if not self.actualFunction is None:
                            if self.callbackParam is None:
                            callbackFunctionThread = threading.Thread(target=self.actualFunction, args=(inputKey,))
                            else:
                            callbackFunctionThread = threading.Thread(target=self.actualFunction, args=(inputKey,self.callbackParam))

                            callbackFunctionThread.daemon = True
                            callbackFunctionThread.start()



                            class KeyCapture():


                            gotKeyLock = threading.Lock()
                            gotKeys =
                            gotKeyEvent = threading.Event()

                            keyBlockingSetKeyLock = threading.Lock()

                            addingEventsLock = threading.Lock()
                            keyReceiveEvents = Event()


                            keysGotLock = threading.Lock()
                            keysGot =

                            keyBlockingKeyLockLossy = threading.Lock()
                            keyBlockingKeyLossy = None
                            keyBlockingEventLossy = threading.Event()

                            keysBlockingGotLock = threading.Lock()
                            keysBlockingGot =
                            keyBlockingGotEvent = threading.Event()



                            wantToStopLock = threading.Lock()
                            wantToStop = False

                            stoppedLock = threading.Lock()
                            stopped = True

                            isRunningEvent = False

                            getKeyThread = None

                            keyFunction = None
                            keyArgs = None

                            # Begin capturing keys. A seperate thread is launched that
                            # captures key presses, and then these can be received via get,
                            # getAsync, and adding an event via addEvent. Note that this
                            # will prevent the system to accept keys as normal (say, if
                            # you are in a python shell) because it overrides that key
                            # capturing behavior.

                            # If you start capture when it's already been started, a
                            # InterruptedError("Keys are still being captured")
                            # will be thrown

                            # Note that get(), getAsync() and events are independent, so if a key is pressed:
                            #
                            # 1: Any calls to get() that are waiting, with lossy on, will return
                            # that key
                            # 2: It will be stored in the queue of get keys, so that get() with lossy
                            # off will return the oldest key pressed not returned by get() yet.
                            # 3: All events will be fired with that key as their input
                            # 4: It will be stored in the list of getAsync() keys, where that list
                            # will be returned and set to empty list on the next call to getAsync().
                            # get() call with it, aand add it to the getAsync() list.
                            def startCapture(self, keyFunction=None, args=None):
                            # Make sure we aren't already capturing keys
                            self.stoppedLock.acquire()
                            if not self.stopped:
                            self.stoppedLock.release()
                            raise InterruptedError("Keys are still being captured")
                            return
                            self.stopped = False
                            self.stoppedLock.release()

                            # If we have captured before, we need to allow the get() calls to actually
                            # wait for key presses now by clearing the event
                            if self.keyBlockingEventLossy.is_set():
                            self.keyBlockingEventLossy.clear()

                            # Have one function that we call every time a key is captured, intended for stopping capture
                            # as desired
                            self.keyFunction = keyFunction
                            self.keyArgs = args

                            # Begin capturing keys (in a seperate thread)
                            self.getKeyThread = threading.Thread(target=self._threadProcessKeyPresses)
                            self.getKeyThread.daemon = True
                            self.getKeyThread.start()

                            # Process key captures (in a seperate thread)
                            self.getKeyThread = threading.Thread(target=self._threadStoreKeyPresses)
                            self.getKeyThread.daemon = True
                            self.getKeyThread.start()


                            def capturing(self):
                            self.stoppedLock.acquire()
                            isCapturing = not self.stopped
                            self.stoppedLock.release()
                            return isCapturing
                            # Stops the thread that is capturing keys on the first opporunity
                            # has to do so. It usually can't stop immediately because getting a key
                            # is a blocking process, so this will probably stop capturing after the
                            # next key is pressed.
                            #
                            # However, Sometimes if you call stopCapture it will stop before starting capturing the
                            # next key, due to multithreading race conditions. So if you want to stop capturing
                            # reliably, call stopCapture in a function added via addEvent. Then you are
                            # guaranteed that capturing will stop immediately after the rest of the callback
                            # functions are called (before starting to capture the next key).
                            def stopCapture(self):
                            self.wantToStopLock.acquire()
                            self.wantToStop = True
                            self.wantToStopLock.release()

                            # Takes in a function that will be called every time a key is pressed (with that
                            # key passed in as the first paramater in that function)
                            def addEvent(self, keyPressEventFunction, args=None):
                            self.addingEventsLock.acquire()
                            callbackHolder = KeyCallbackFunction(keyPressEventFunction, args)
                            self.keyReceiveEvents.append(callbackHolder.doCallback)
                            self.addingEventsLock.release()
                            def clearEvents(self):
                            self.addingEventsLock.acquire()
                            self.keyReceiveEvents = Event()
                            self.addingEventsLock.release()
                            # Gets a key captured by this KeyCapture, blocking until a key is pressed.
                            # There is an optional lossy paramater:
                            # If True all keys before this call are ignored, and the next pressed key
                            # will be returned.
                            # If False this will return the oldest key captured that hasn't
                            # been returned by get yet. False is the default.
                            def get(self, lossy=False):
                            if lossy:
                            # Wait for the next key to be pressed
                            self.keyBlockingEventLossy.wait()
                            self.keyBlockingKeyLockLossy.acquire()
                            keyReceived = self.keyBlockingKeyLossy
                            self.keyBlockingKeyLockLossy.release()
                            return keyReceived
                            else:
                            while True:
                            # Wait until a key is pressed
                            self.keyBlockingGotEvent.wait()

                            # Get the key pressed
                            readKey = None
                            self.keysBlockingGotLock.acquire()
                            # Get a key if it exists
                            if len(self.keysBlockingGot) != 0:
                            readKey = self.keysBlockingGot.pop(0)
                            # If we got the last one, tell us to wait
                            if len(self.keysBlockingGot) == 0:
                            self.keyBlockingGotEvent.clear()
                            self.keysBlockingGotLock.release()

                            # Process the key (if it actually exists)
                            if not readKey is None:
                            return readKey

                            # Exit if we are stopping
                            self.wantToStopLock.acquire()
                            if self.wantToStop:
                            self.wantToStopLock.release()
                            return None
                            self.wantToStopLock.release()




                            def clearGetList(self):
                            self.keysBlockingGotLock.acquire()
                            self.keysBlockingGot =
                            self.keysBlockingGotLock.release()

                            # Gets a list of all keys pressed since the last call to getAsync, in order
                            # from first pressed, second pressed, .., most recent pressed
                            def getAsync(self):
                            self.keysGotLock.acquire();
                            keysPressedList = list(self.keysGot)
                            self.keysGot =
                            self.keysGotLock.release()
                            return keysPressedList

                            def clearAsyncList(self):
                            self.keysGotLock.acquire();
                            self.keysGot =
                            self.keysGotLock.release();

                            def _processKey(self, readKey):
                            # Append to list for GetKeyAsync
                            self.keysGotLock.acquire()
                            self.keysGot.append(readKey)
                            self.keysGotLock.release()

                            # Call lossy blocking key events
                            self.keyBlockingKeyLockLossy.acquire()
                            self.keyBlockingKeyLossy = readKey
                            self.keyBlockingEventLossy.set()
                            self.keyBlockingEventLossy.clear()
                            self.keyBlockingKeyLockLossy.release()

                            # Call non-lossy blocking key events
                            self.keysBlockingGotLock.acquire()
                            self.keysBlockingGot.append(readKey)
                            if len(self.keysBlockingGot) == 1:
                            self.keyBlockingGotEvent.set()
                            self.keysBlockingGotLock.release()

                            # Call events added by AddEvent
                            self.addingEventsLock.acquire()
                            self.keyReceiveEvents(readKey)
                            self.addingEventsLock.release()

                            def _threadProcessKeyPresses(self):
                            while True:
                            # Wait until a key is pressed
                            self.gotKeyEvent.wait()

                            # Get the key pressed
                            readKey = None
                            self.gotKeyLock.acquire()
                            # Get a key if it exists
                            if len(self.gotKeys) != 0:
                            readKey = self.gotKeys.pop(0)
                            # If we got the last one, tell us to wait
                            if len(self.gotKeys) == 0:
                            self.gotKeyEvent.clear()
                            self.gotKeyLock.release()

                            # Process the key (if it actually exists)
                            if not readKey is None:
                            self._processKey(readKey)

                            # Exit if we are stopping
                            self.wantToStopLock.acquire()
                            if self.wantToStop:
                            self.wantToStopLock.release()
                            break
                            self.wantToStopLock.release()

                            def _threadStoreKeyPresses(self):
                            while True:
                            # Get a key
                            readKey = getKey()

                            # Run the potential shut down function
                            if not self.keyFunction is None:
                            self.keyFunction(readKey, self.keyArgs)

                            # Add the key to the list of pressed keys
                            self.gotKeyLock.acquire()
                            self.gotKeys.append(readKey)
                            if len(self.gotKeys) == 1:
                            self.gotKeyEvent.set()
                            self.gotKeyLock.release()

                            # Exit if we are stopping
                            self.wantToStopLock.acquire()
                            if self.wantToStop:
                            self.wantToStopLock.release()
                            self.gotKeyEvent.set()
                            break
                            self.wantToStopLock.release()


                            # If we have reached here we stopped capturing

                            # All we need to do to clean up is ensure that
                            # all the calls to .get() now return None.
                            # To ensure no calls are stuck never returning,
                            # we will leave the event set so any tasks waiting
                            # for it immediately exit. This will be unset upon
                            # starting key capturing again.

                            self.stoppedLock.acquire()

                            # We also need to set this to True so we can start up
                            # capturing again.
                            self.stopped = True
                            self.stopped = True

                            self.keyBlockingKeyLockLossy.acquire()
                            self.keyBlockingKeyLossy = None
                            self.keyBlockingEventLossy.set()
                            self.keyBlockingKeyLockLossy.release()

                            self.keysBlockingGotLock.acquire()
                            self.keyBlockingGotEvent.set()
                            self.keysBlockingGotLock.release()

                            self.stoppedLock.release()


                            The idea is that you can either simply call keyPress.getKey(), which will read a key from the keyboard, then return it.



                            If you want something more than that, I made a KeyCapture object. You can create one via something like keys = keyPress.KeyCapture().



                            Then there are three things you can do:



                            addEvent(functionName) takes in any function that takes in one parameter. Then every time a key is pressed, this function will be called with that key's string as it's input. These are ran in a separate thread, so you can block all you want in them and it won't mess up the functionality of the KeyCapturer nor delay the other events.



                            get() returns a key in the same blocking way as before. It is now needed here because the keys are being captured via the KeyCapture object now, so keyPress.getKey() would conflict with that behavior and both of them would miss some keys since only one key can be captured at a time. Also, say the user presses 'a', then 'b', you call get(), the the user presses 'c'. That get() call will immediately return 'a', then if you call it again it will return 'b', then 'c'. If you call it again it will block until another key is pressed. This ensures that you don't miss any keys, in a blocking way if desired. So in this way it's a little different than keyPress.getKey() from before



                            If you want the behavior of getKey() back, get(lossy=True) is like get(), except that it only returns keys pressed after the call to get(). So in the above example, get() would block until the user presses 'c', and then if you call it again it will block until another key is pressed.



                            getAsync() is a little different. It's designed for something that does a lot of processing, then occasionally comes back and checks which keys were pressed. Thus getAsync() returns a list of all the keys pressed since the last call to getAsync(), in order from oldest key pressed to most recent key pressed. It also doesn't block, meaning that if no keys have been pressed since the last call to getAsync(), an empty will be returned.



                            To actually start capturing keys, you need to call keys.startCapture() with your keys object made above. startCapture is non-blocking, and simply starts one thread that just records the key presses, and another thread to process those key presses. There are two threads to ensure that the thread that records key presses doesn't miss any keys.



                            If you want to stop capturing keys, you can call keys.stopCapture() and it will stop capturing keys. However, since capturing a key is a blocking operation, the thread capturing keys might capture one more key after calling stopCapture().



                            To prevent this, you can pass in an optional parameter(s) into startCapture(functionName, args) of a function that just does something like checks if a key equals 'c' and then exits. It's important that this function does very little before, for example, a sleep here will cause us to miss keys.



                            However, if stopCapture() is called in this function, key captures will be stopped immediately, without trying to capture any more, and that all get() calls will be returned immediately, with None if no keys have been pressed yet.



                            Also, since get() and getAsync() store all the previous keys pressed (until you retrieve them), you can call clearGetList() and clearAsyncList() to forget the keys previously pressed.



                            Note that get(), getAsync() and events are independent, so if a key is pressed:
                            1. One call to get() that is waiting, with lossy on, will return
                            that key. The other waiting calls (if any) will continue waiting.
                            2. That key will be stored in the queue of get keys, so that get() with lossy off will return the oldest key pressed not returned by get() yet.
                            3. All events will be fired with that key as their input
                            4. That key will be stored in the list of getAsync() keys, where that lis twill be returned and set to empty list on the next call to getAsync()



                            If all this is too much, here is an example use case:



                            import keyPress
                            import time
                            import threading

                            def KeyPressed(k, printLock):
                            printLock.acquire()
                            print "Event: " + k
                            printLock.release()
                            time.sleep(4)
                            printLock.acquire()
                            print "Event after delay: " + k
                            printLock.release()

                            def GetKeyBlocking(keys, printLock):
                            while keys.capturing():
                            keyReceived = keys.get()
                            time.sleep(1)
                            printLock.acquire()
                            if not keyReceived is None:
                            print "Block " + keyReceived
                            else:
                            print "Block None"
                            printLock.release()

                            def GetKeyBlockingLossy(keys, printLock):
                            while keys.capturing():
                            keyReceived = keys.get(lossy=True)
                            time.sleep(1)
                            printLock.acquire()
                            if not keyReceived is None:
                            print "Lossy: " + keyReceived
                            else:
                            print "Lossy: None"
                            printLock.release()

                            def CheckToClose(k, (keys, printLock)):
                            printLock.acquire()
                            print "Close: " + k
                            printLock.release()
                            if k == "c":
                            keys.stopCapture()

                            printLock = threading.Lock()

                            print "Press a key:"
                            print "You pressed: " + keyPress.getKey()
                            print ""

                            keys = keyPress.KeyCapture()

                            keys.addEvent(KeyPressed, printLock)



                            print "Starting capture"

                            keys.startCapture(CheckToClose, (keys, printLock))

                            getKeyBlockingThread = threading.Thread(target=GetKeyBlocking, args=(keys, printLock))
                            getKeyBlockingThread.daemon = True
                            getKeyBlockingThread.start()


                            getKeyBlockingThreadLossy = threading.Thread(target=GetKeyBlockingLossy, args=(keys, printLock))
                            getKeyBlockingThreadLossy.daemon = True
                            getKeyBlockingThreadLossy.start()

                            while keys.capturing():
                            keysPressed = keys.getAsync()
                            printLock.acquire()
                            if keysPressed != :
                            print "Async: " + str(keysPressed)
                            printLock.release()
                            time.sleep(1)

                            print "done capturing"


                            It is working well for me from the simple test I made, but I will happily take others feedback as well if there is something I missed.



                            I posted this here as well.






                            share|improve this answer






























                              4














                              The answers here were informative, however I also wanted a way to get key presses asynchronously and fire off key presses in separate events, all in a thread-safe, cross-platform way. PyGame was also too bloated for me. So I made the following (in Python 2.7 but I suspect it's easily portable), which I figured I'd share here in case it was useful for anyone else. I stored this in a file named keyPress.py.



                              class _Getch:
                              """Gets a single character from standard input. Does not echo to the
                              screen. From http://code.activestate.com/recipes/134892/"""
                              def __init__(self):
                              try:
                              self.impl = _GetchWindows()
                              except ImportError:
                              try:
                              self.impl = _GetchMacCarbon()
                              except(AttributeError, ImportError):
                              self.impl = _GetchUnix()

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


                              class _GetchUnix:
                              def __init__(self):
                              import tty, sys, termios # import termios now or else you'll get the Unix version on the Mac

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

                              class _GetchMacCarbon:
                              """
                              A function which returns the current ASCII key that is down;
                              if no ASCII key is down, the null string is returned. The
                              page http://www.mactech.com/macintosh-c/chap02-1.html was
                              very helpful in figuring out how to do this.
                              """
                              def __init__(self):
                              import Carbon
                              Carbon.Evt #see if it has this (in Unix, it doesn't)

                              def __call__(self):
                              import Carbon
                              if Carbon.Evt.EventAvail(0x0008)[0]==0: # 0x0008 is the keyDownMask
                              return ''
                              else:
                              #
                              # The event contains the following info:
                              # (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1]
                              #
                              # The message (msg) contains the ASCII char which is
                              # extracted with the 0x000000FF charCodeMask; this
                              # number is converted to an ASCII character with chr() and
                              # returned
                              #
                              (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1]
                              return chr(msg & 0x000000FF)

                              import threading


                              # From https://stackoverflow.com/a/2022629/2924421
                              class Event(list):
                              def __call__(self, *args, **kwargs):
                              for f in self:
                              f(*args, **kwargs)

                              def __repr__(self):
                              return "Event(%s)" % list.__repr__(self)


                              def getKey():
                              inkey = _Getch()
                              import sys
                              for i in xrange(sys.maxint):
                              k=inkey()
                              if k<>'':break
                              return k

                              class KeyCallbackFunction():
                              callbackParam = None
                              actualFunction = None

                              def __init__(self, actualFunction, callbackParam):
                              self.actualFunction = actualFunction
                              self.callbackParam = callbackParam

                              def doCallback(self, inputKey):
                              if not self.actualFunction is None:
                              if self.callbackParam is None:
                              callbackFunctionThread = threading.Thread(target=self.actualFunction, args=(inputKey,))
                              else:
                              callbackFunctionThread = threading.Thread(target=self.actualFunction, args=(inputKey,self.callbackParam))

                              callbackFunctionThread.daemon = True
                              callbackFunctionThread.start()



                              class KeyCapture():


                              gotKeyLock = threading.Lock()
                              gotKeys =
                              gotKeyEvent = threading.Event()

                              keyBlockingSetKeyLock = threading.Lock()

                              addingEventsLock = threading.Lock()
                              keyReceiveEvents = Event()


                              keysGotLock = threading.Lock()
                              keysGot =

                              keyBlockingKeyLockLossy = threading.Lock()
                              keyBlockingKeyLossy = None
                              keyBlockingEventLossy = threading.Event()

                              keysBlockingGotLock = threading.Lock()
                              keysBlockingGot =
                              keyBlockingGotEvent = threading.Event()



                              wantToStopLock = threading.Lock()
                              wantToStop = False

                              stoppedLock = threading.Lock()
                              stopped = True

                              isRunningEvent = False

                              getKeyThread = None

                              keyFunction = None
                              keyArgs = None

                              # Begin capturing keys. A seperate thread is launched that
                              # captures key presses, and then these can be received via get,
                              # getAsync, and adding an event via addEvent. Note that this
                              # will prevent the system to accept keys as normal (say, if
                              # you are in a python shell) because it overrides that key
                              # capturing behavior.

                              # If you start capture when it's already been started, a
                              # InterruptedError("Keys are still being captured")
                              # will be thrown

                              # Note that get(), getAsync() and events are independent, so if a key is pressed:
                              #
                              # 1: Any calls to get() that are waiting, with lossy on, will return
                              # that key
                              # 2: It will be stored in the queue of get keys, so that get() with lossy
                              # off will return the oldest key pressed not returned by get() yet.
                              # 3: All events will be fired with that key as their input
                              # 4: It will be stored in the list of getAsync() keys, where that list
                              # will be returned and set to empty list on the next call to getAsync().
                              # get() call with it, aand add it to the getAsync() list.
                              def startCapture(self, keyFunction=None, args=None):
                              # Make sure we aren't already capturing keys
                              self.stoppedLock.acquire()
                              if not self.stopped:
                              self.stoppedLock.release()
                              raise InterruptedError("Keys are still being captured")
                              return
                              self.stopped = False
                              self.stoppedLock.release()

                              # If we have captured before, we need to allow the get() calls to actually
                              # wait for key presses now by clearing the event
                              if self.keyBlockingEventLossy.is_set():
                              self.keyBlockingEventLossy.clear()

                              # Have one function that we call every time a key is captured, intended for stopping capture
                              # as desired
                              self.keyFunction = keyFunction
                              self.keyArgs = args

                              # Begin capturing keys (in a seperate thread)
                              self.getKeyThread = threading.Thread(target=self._threadProcessKeyPresses)
                              self.getKeyThread.daemon = True
                              self.getKeyThread.start()

                              # Process key captures (in a seperate thread)
                              self.getKeyThread = threading.Thread(target=self._threadStoreKeyPresses)
                              self.getKeyThread.daemon = True
                              self.getKeyThread.start()


                              def capturing(self):
                              self.stoppedLock.acquire()
                              isCapturing = not self.stopped
                              self.stoppedLock.release()
                              return isCapturing
                              # Stops the thread that is capturing keys on the first opporunity
                              # has to do so. It usually can't stop immediately because getting a key
                              # is a blocking process, so this will probably stop capturing after the
                              # next key is pressed.
                              #
                              # However, Sometimes if you call stopCapture it will stop before starting capturing the
                              # next key, due to multithreading race conditions. So if you want to stop capturing
                              # reliably, call stopCapture in a function added via addEvent. Then you are
                              # guaranteed that capturing will stop immediately after the rest of the callback
                              # functions are called (before starting to capture the next key).
                              def stopCapture(self):
                              self.wantToStopLock.acquire()
                              self.wantToStop = True
                              self.wantToStopLock.release()

                              # Takes in a function that will be called every time a key is pressed (with that
                              # key passed in as the first paramater in that function)
                              def addEvent(self, keyPressEventFunction, args=None):
                              self.addingEventsLock.acquire()
                              callbackHolder = KeyCallbackFunction(keyPressEventFunction, args)
                              self.keyReceiveEvents.append(callbackHolder.doCallback)
                              self.addingEventsLock.release()
                              def clearEvents(self):
                              self.addingEventsLock.acquire()
                              self.keyReceiveEvents = Event()
                              self.addingEventsLock.release()
                              # Gets a key captured by this KeyCapture, blocking until a key is pressed.
                              # There is an optional lossy paramater:
                              # If True all keys before this call are ignored, and the next pressed key
                              # will be returned.
                              # If False this will return the oldest key captured that hasn't
                              # been returned by get yet. False is the default.
                              def get(self, lossy=False):
                              if lossy:
                              # Wait for the next key to be pressed
                              self.keyBlockingEventLossy.wait()
                              self.keyBlockingKeyLockLossy.acquire()
                              keyReceived = self.keyBlockingKeyLossy
                              self.keyBlockingKeyLockLossy.release()
                              return keyReceived
                              else:
                              while True:
                              # Wait until a key is pressed
                              self.keyBlockingGotEvent.wait()

                              # Get the key pressed
                              readKey = None
                              self.keysBlockingGotLock.acquire()
                              # Get a key if it exists
                              if len(self.keysBlockingGot) != 0:
                              readKey = self.keysBlockingGot.pop(0)
                              # If we got the last one, tell us to wait
                              if len(self.keysBlockingGot) == 0:
                              self.keyBlockingGotEvent.clear()
                              self.keysBlockingGotLock.release()

                              # Process the key (if it actually exists)
                              if not readKey is None:
                              return readKey

                              # Exit if we are stopping
                              self.wantToStopLock.acquire()
                              if self.wantToStop:
                              self.wantToStopLock.release()
                              return None
                              self.wantToStopLock.release()




                              def clearGetList(self):
                              self.keysBlockingGotLock.acquire()
                              self.keysBlockingGot =
                              self.keysBlockingGotLock.release()

                              # Gets a list of all keys pressed since the last call to getAsync, in order
                              # from first pressed, second pressed, .., most recent pressed
                              def getAsync(self):
                              self.keysGotLock.acquire();
                              keysPressedList = list(self.keysGot)
                              self.keysGot =
                              self.keysGotLock.release()
                              return keysPressedList

                              def clearAsyncList(self):
                              self.keysGotLock.acquire();
                              self.keysGot =
                              self.keysGotLock.release();

                              def _processKey(self, readKey):
                              # Append to list for GetKeyAsync
                              self.keysGotLock.acquire()
                              self.keysGot.append(readKey)
                              self.keysGotLock.release()

                              # Call lossy blocking key events
                              self.keyBlockingKeyLockLossy.acquire()
                              self.keyBlockingKeyLossy = readKey
                              self.keyBlockingEventLossy.set()
                              self.keyBlockingEventLossy.clear()
                              self.keyBlockingKeyLockLossy.release()

                              # Call non-lossy blocking key events
                              self.keysBlockingGotLock.acquire()
                              self.keysBlockingGot.append(readKey)
                              if len(self.keysBlockingGot) == 1:
                              self.keyBlockingGotEvent.set()
                              self.keysBlockingGotLock.release()

                              # Call events added by AddEvent
                              self.addingEventsLock.acquire()
                              self.keyReceiveEvents(readKey)
                              self.addingEventsLock.release()

                              def _threadProcessKeyPresses(self):
                              while True:
                              # Wait until a key is pressed
                              self.gotKeyEvent.wait()

                              # Get the key pressed
                              readKey = None
                              self.gotKeyLock.acquire()
                              # Get a key if it exists
                              if len(self.gotKeys) != 0:
                              readKey = self.gotKeys.pop(0)
                              # If we got the last one, tell us to wait
                              if len(self.gotKeys) == 0:
                              self.gotKeyEvent.clear()
                              self.gotKeyLock.release()

                              # Process the key (if it actually exists)
                              if not readKey is None:
                              self._processKey(readKey)

                              # Exit if we are stopping
                              self.wantToStopLock.acquire()
                              if self.wantToStop:
                              self.wantToStopLock.release()
                              break
                              self.wantToStopLock.release()

                              def _threadStoreKeyPresses(self):
                              while True:
                              # Get a key
                              readKey = getKey()

                              # Run the potential shut down function
                              if not self.keyFunction is None:
                              self.keyFunction(readKey, self.keyArgs)

                              # Add the key to the list of pressed keys
                              self.gotKeyLock.acquire()
                              self.gotKeys.append(readKey)
                              if len(self.gotKeys) == 1:
                              self.gotKeyEvent.set()
                              self.gotKeyLock.release()

                              # Exit if we are stopping
                              self.wantToStopLock.acquire()
                              if self.wantToStop:
                              self.wantToStopLock.release()
                              self.gotKeyEvent.set()
                              break
                              self.wantToStopLock.release()


                              # If we have reached here we stopped capturing

                              # All we need to do to clean up is ensure that
                              # all the calls to .get() now return None.
                              # To ensure no calls are stuck never returning,
                              # we will leave the event set so any tasks waiting
                              # for it immediately exit. This will be unset upon
                              # starting key capturing again.

                              self.stoppedLock.acquire()

                              # We also need to set this to True so we can start up
                              # capturing again.
                              self.stopped = True
                              self.stopped = True

                              self.keyBlockingKeyLockLossy.acquire()
                              self.keyBlockingKeyLossy = None
                              self.keyBlockingEventLossy.set()
                              self.keyBlockingKeyLockLossy.release()

                              self.keysBlockingGotLock.acquire()
                              self.keyBlockingGotEvent.set()
                              self.keysBlockingGotLock.release()

                              self.stoppedLock.release()


                              The idea is that you can either simply call keyPress.getKey(), which will read a key from the keyboard, then return it.



                              If you want something more than that, I made a KeyCapture object. You can create one via something like keys = keyPress.KeyCapture().



                              Then there are three things you can do:



                              addEvent(functionName) takes in any function that takes in one parameter. Then every time a key is pressed, this function will be called with that key's string as it's input. These are ran in a separate thread, so you can block all you want in them and it won't mess up the functionality of the KeyCapturer nor delay the other events.



                              get() returns a key in the same blocking way as before. It is now needed here because the keys are being captured via the KeyCapture object now, so keyPress.getKey() would conflict with that behavior and both of them would miss some keys since only one key can be captured at a time. Also, say the user presses 'a', then 'b', you call get(), the the user presses 'c'. That get() call will immediately return 'a', then if you call it again it will return 'b', then 'c'. If you call it again it will block until another key is pressed. This ensures that you don't miss any keys, in a blocking way if desired. So in this way it's a little different than keyPress.getKey() from before



                              If you want the behavior of getKey() back, get(lossy=True) is like get(), except that it only returns keys pressed after the call to get(). So in the above example, get() would block until the user presses 'c', and then if you call it again it will block until another key is pressed.



                              getAsync() is a little different. It's designed for something that does a lot of processing, then occasionally comes back and checks which keys were pressed. Thus getAsync() returns a list of all the keys pressed since the last call to getAsync(), in order from oldest key pressed to most recent key pressed. It also doesn't block, meaning that if no keys have been pressed since the last call to getAsync(), an empty will be returned.



                              To actually start capturing keys, you need to call keys.startCapture() with your keys object made above. startCapture is non-blocking, and simply starts one thread that just records the key presses, and another thread to process those key presses. There are two threads to ensure that the thread that records key presses doesn't miss any keys.



                              If you want to stop capturing keys, you can call keys.stopCapture() and it will stop capturing keys. However, since capturing a key is a blocking operation, the thread capturing keys might capture one more key after calling stopCapture().



                              To prevent this, you can pass in an optional parameter(s) into startCapture(functionName, args) of a function that just does something like checks if a key equals 'c' and then exits. It's important that this function does very little before, for example, a sleep here will cause us to miss keys.



                              However, if stopCapture() is called in this function, key captures will be stopped immediately, without trying to capture any more, and that all get() calls will be returned immediately, with None if no keys have been pressed yet.



                              Also, since get() and getAsync() store all the previous keys pressed (until you retrieve them), you can call clearGetList() and clearAsyncList() to forget the keys previously pressed.



                              Note that get(), getAsync() and events are independent, so if a key is pressed:
                              1. One call to get() that is waiting, with lossy on, will return
                              that key. The other waiting calls (if any) will continue waiting.
                              2. That key will be stored in the queue of get keys, so that get() with lossy off will return the oldest key pressed not returned by get() yet.
                              3. All events will be fired with that key as their input
                              4. That key will be stored in the list of getAsync() keys, where that lis twill be returned and set to empty list on the next call to getAsync()



                              If all this is too much, here is an example use case:



                              import keyPress
                              import time
                              import threading

                              def KeyPressed(k, printLock):
                              printLock.acquire()
                              print "Event: " + k
                              printLock.release()
                              time.sleep(4)
                              printLock.acquire()
                              print "Event after delay: " + k
                              printLock.release()

                              def GetKeyBlocking(keys, printLock):
                              while keys.capturing():
                              keyReceived = keys.get()
                              time.sleep(1)
                              printLock.acquire()
                              if not keyReceived is None:
                              print "Block " + keyReceived
                              else:
                              print "Block None"
                              printLock.release()

                              def GetKeyBlockingLossy(keys, printLock):
                              while keys.capturing():
                              keyReceived = keys.get(lossy=True)
                              time.sleep(1)
                              printLock.acquire()
                              if not keyReceived is None:
                              print "Lossy: " + keyReceived
                              else:
                              print "Lossy: None"
                              printLock.release()

                              def CheckToClose(k, (keys, printLock)):
                              printLock.acquire()
                              print "Close: " + k
                              printLock.release()
                              if k == "c":
                              keys.stopCapture()

                              printLock = threading.Lock()

                              print "Press a key:"
                              print "You pressed: " + keyPress.getKey()
                              print ""

                              keys = keyPress.KeyCapture()

                              keys.addEvent(KeyPressed, printLock)



                              print "Starting capture"

                              keys.startCapture(CheckToClose, (keys, printLock))

                              getKeyBlockingThread = threading.Thread(target=GetKeyBlocking, args=(keys, printLock))
                              getKeyBlockingThread.daemon = True
                              getKeyBlockingThread.start()


                              getKeyBlockingThreadLossy = threading.Thread(target=GetKeyBlockingLossy, args=(keys, printLock))
                              getKeyBlockingThreadLossy.daemon = True
                              getKeyBlockingThreadLossy.start()

                              while keys.capturing():
                              keysPressed = keys.getAsync()
                              printLock.acquire()
                              if keysPressed != :
                              print "Async: " + str(keysPressed)
                              printLock.release()
                              time.sleep(1)

                              print "done capturing"


                              It is working well for me from the simple test I made, but I will happily take others feedback as well if there is something I missed.



                              I posted this here as well.






                              share|improve this answer




























                                4












                                4








                                4







                                The answers here were informative, however I also wanted a way to get key presses asynchronously and fire off key presses in separate events, all in a thread-safe, cross-platform way. PyGame was also too bloated for me. So I made the following (in Python 2.7 but I suspect it's easily portable), which I figured I'd share here in case it was useful for anyone else. I stored this in a file named keyPress.py.



                                class _Getch:
                                """Gets a single character from standard input. Does not echo to the
                                screen. From http://code.activestate.com/recipes/134892/"""
                                def __init__(self):
                                try:
                                self.impl = _GetchWindows()
                                except ImportError:
                                try:
                                self.impl = _GetchMacCarbon()
                                except(AttributeError, ImportError):
                                self.impl = _GetchUnix()

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


                                class _GetchUnix:
                                def __init__(self):
                                import tty, sys, termios # import termios now or else you'll get the Unix version on the Mac

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

                                class _GetchMacCarbon:
                                """
                                A function which returns the current ASCII key that is down;
                                if no ASCII key is down, the null string is returned. The
                                page http://www.mactech.com/macintosh-c/chap02-1.html was
                                very helpful in figuring out how to do this.
                                """
                                def __init__(self):
                                import Carbon
                                Carbon.Evt #see if it has this (in Unix, it doesn't)

                                def __call__(self):
                                import Carbon
                                if Carbon.Evt.EventAvail(0x0008)[0]==0: # 0x0008 is the keyDownMask
                                return ''
                                else:
                                #
                                # The event contains the following info:
                                # (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1]
                                #
                                # The message (msg) contains the ASCII char which is
                                # extracted with the 0x000000FF charCodeMask; this
                                # number is converted to an ASCII character with chr() and
                                # returned
                                #
                                (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1]
                                return chr(msg & 0x000000FF)

                                import threading


                                # From https://stackoverflow.com/a/2022629/2924421
                                class Event(list):
                                def __call__(self, *args, **kwargs):
                                for f in self:
                                f(*args, **kwargs)

                                def __repr__(self):
                                return "Event(%s)" % list.__repr__(self)


                                def getKey():
                                inkey = _Getch()
                                import sys
                                for i in xrange(sys.maxint):
                                k=inkey()
                                if k<>'':break
                                return k

                                class KeyCallbackFunction():
                                callbackParam = None
                                actualFunction = None

                                def __init__(self, actualFunction, callbackParam):
                                self.actualFunction = actualFunction
                                self.callbackParam = callbackParam

                                def doCallback(self, inputKey):
                                if not self.actualFunction is None:
                                if self.callbackParam is None:
                                callbackFunctionThread = threading.Thread(target=self.actualFunction, args=(inputKey,))
                                else:
                                callbackFunctionThread = threading.Thread(target=self.actualFunction, args=(inputKey,self.callbackParam))

                                callbackFunctionThread.daemon = True
                                callbackFunctionThread.start()



                                class KeyCapture():


                                gotKeyLock = threading.Lock()
                                gotKeys =
                                gotKeyEvent = threading.Event()

                                keyBlockingSetKeyLock = threading.Lock()

                                addingEventsLock = threading.Lock()
                                keyReceiveEvents = Event()


                                keysGotLock = threading.Lock()
                                keysGot =

                                keyBlockingKeyLockLossy = threading.Lock()
                                keyBlockingKeyLossy = None
                                keyBlockingEventLossy = threading.Event()

                                keysBlockingGotLock = threading.Lock()
                                keysBlockingGot =
                                keyBlockingGotEvent = threading.Event()



                                wantToStopLock = threading.Lock()
                                wantToStop = False

                                stoppedLock = threading.Lock()
                                stopped = True

                                isRunningEvent = False

                                getKeyThread = None

                                keyFunction = None
                                keyArgs = None

                                # Begin capturing keys. A seperate thread is launched that
                                # captures key presses, and then these can be received via get,
                                # getAsync, and adding an event via addEvent. Note that this
                                # will prevent the system to accept keys as normal (say, if
                                # you are in a python shell) because it overrides that key
                                # capturing behavior.

                                # If you start capture when it's already been started, a
                                # InterruptedError("Keys are still being captured")
                                # will be thrown

                                # Note that get(), getAsync() and events are independent, so if a key is pressed:
                                #
                                # 1: Any calls to get() that are waiting, with lossy on, will return
                                # that key
                                # 2: It will be stored in the queue of get keys, so that get() with lossy
                                # off will return the oldest key pressed not returned by get() yet.
                                # 3: All events will be fired with that key as their input
                                # 4: It will be stored in the list of getAsync() keys, where that list
                                # will be returned and set to empty list on the next call to getAsync().
                                # get() call with it, aand add it to the getAsync() list.
                                def startCapture(self, keyFunction=None, args=None):
                                # Make sure we aren't already capturing keys
                                self.stoppedLock.acquire()
                                if not self.stopped:
                                self.stoppedLock.release()
                                raise InterruptedError("Keys are still being captured")
                                return
                                self.stopped = False
                                self.stoppedLock.release()

                                # If we have captured before, we need to allow the get() calls to actually
                                # wait for key presses now by clearing the event
                                if self.keyBlockingEventLossy.is_set():
                                self.keyBlockingEventLossy.clear()

                                # Have one function that we call every time a key is captured, intended for stopping capture
                                # as desired
                                self.keyFunction = keyFunction
                                self.keyArgs = args

                                # Begin capturing keys (in a seperate thread)
                                self.getKeyThread = threading.Thread(target=self._threadProcessKeyPresses)
                                self.getKeyThread.daemon = True
                                self.getKeyThread.start()

                                # Process key captures (in a seperate thread)
                                self.getKeyThread = threading.Thread(target=self._threadStoreKeyPresses)
                                self.getKeyThread.daemon = True
                                self.getKeyThread.start()


                                def capturing(self):
                                self.stoppedLock.acquire()
                                isCapturing = not self.stopped
                                self.stoppedLock.release()
                                return isCapturing
                                # Stops the thread that is capturing keys on the first opporunity
                                # has to do so. It usually can't stop immediately because getting a key
                                # is a blocking process, so this will probably stop capturing after the
                                # next key is pressed.
                                #
                                # However, Sometimes if you call stopCapture it will stop before starting capturing the
                                # next key, due to multithreading race conditions. So if you want to stop capturing
                                # reliably, call stopCapture in a function added via addEvent. Then you are
                                # guaranteed that capturing will stop immediately after the rest of the callback
                                # functions are called (before starting to capture the next key).
                                def stopCapture(self):
                                self.wantToStopLock.acquire()
                                self.wantToStop = True
                                self.wantToStopLock.release()

                                # Takes in a function that will be called every time a key is pressed (with that
                                # key passed in as the first paramater in that function)
                                def addEvent(self, keyPressEventFunction, args=None):
                                self.addingEventsLock.acquire()
                                callbackHolder = KeyCallbackFunction(keyPressEventFunction, args)
                                self.keyReceiveEvents.append(callbackHolder.doCallback)
                                self.addingEventsLock.release()
                                def clearEvents(self):
                                self.addingEventsLock.acquire()
                                self.keyReceiveEvents = Event()
                                self.addingEventsLock.release()
                                # Gets a key captured by this KeyCapture, blocking until a key is pressed.
                                # There is an optional lossy paramater:
                                # If True all keys before this call are ignored, and the next pressed key
                                # will be returned.
                                # If False this will return the oldest key captured that hasn't
                                # been returned by get yet. False is the default.
                                def get(self, lossy=False):
                                if lossy:
                                # Wait for the next key to be pressed
                                self.keyBlockingEventLossy.wait()
                                self.keyBlockingKeyLockLossy.acquire()
                                keyReceived = self.keyBlockingKeyLossy
                                self.keyBlockingKeyLockLossy.release()
                                return keyReceived
                                else:
                                while True:
                                # Wait until a key is pressed
                                self.keyBlockingGotEvent.wait()

                                # Get the key pressed
                                readKey = None
                                self.keysBlockingGotLock.acquire()
                                # Get a key if it exists
                                if len(self.keysBlockingGot) != 0:
                                readKey = self.keysBlockingGot.pop(0)
                                # If we got the last one, tell us to wait
                                if len(self.keysBlockingGot) == 0:
                                self.keyBlockingGotEvent.clear()
                                self.keysBlockingGotLock.release()

                                # Process the key (if it actually exists)
                                if not readKey is None:
                                return readKey

                                # Exit if we are stopping
                                self.wantToStopLock.acquire()
                                if self.wantToStop:
                                self.wantToStopLock.release()
                                return None
                                self.wantToStopLock.release()




                                def clearGetList(self):
                                self.keysBlockingGotLock.acquire()
                                self.keysBlockingGot =
                                self.keysBlockingGotLock.release()

                                # Gets a list of all keys pressed since the last call to getAsync, in order
                                # from first pressed, second pressed, .., most recent pressed
                                def getAsync(self):
                                self.keysGotLock.acquire();
                                keysPressedList = list(self.keysGot)
                                self.keysGot =
                                self.keysGotLock.release()
                                return keysPressedList

                                def clearAsyncList(self):
                                self.keysGotLock.acquire();
                                self.keysGot =
                                self.keysGotLock.release();

                                def _processKey(self, readKey):
                                # Append to list for GetKeyAsync
                                self.keysGotLock.acquire()
                                self.keysGot.append(readKey)
                                self.keysGotLock.release()

                                # Call lossy blocking key events
                                self.keyBlockingKeyLockLossy.acquire()
                                self.keyBlockingKeyLossy = readKey
                                self.keyBlockingEventLossy.set()
                                self.keyBlockingEventLossy.clear()
                                self.keyBlockingKeyLockLossy.release()

                                # Call non-lossy blocking key events
                                self.keysBlockingGotLock.acquire()
                                self.keysBlockingGot.append(readKey)
                                if len(self.keysBlockingGot) == 1:
                                self.keyBlockingGotEvent.set()
                                self.keysBlockingGotLock.release()

                                # Call events added by AddEvent
                                self.addingEventsLock.acquire()
                                self.keyReceiveEvents(readKey)
                                self.addingEventsLock.release()

                                def _threadProcessKeyPresses(self):
                                while True:
                                # Wait until a key is pressed
                                self.gotKeyEvent.wait()

                                # Get the key pressed
                                readKey = None
                                self.gotKeyLock.acquire()
                                # Get a key if it exists
                                if len(self.gotKeys) != 0:
                                readKey = self.gotKeys.pop(0)
                                # If we got the last one, tell us to wait
                                if len(self.gotKeys) == 0:
                                self.gotKeyEvent.clear()
                                self.gotKeyLock.release()

                                # Process the key (if it actually exists)
                                if not readKey is None:
                                self._processKey(readKey)

                                # Exit if we are stopping
                                self.wantToStopLock.acquire()
                                if self.wantToStop:
                                self.wantToStopLock.release()
                                break
                                self.wantToStopLock.release()

                                def _threadStoreKeyPresses(self):
                                while True:
                                # Get a key
                                readKey = getKey()

                                # Run the potential shut down function
                                if not self.keyFunction is None:
                                self.keyFunction(readKey, self.keyArgs)

                                # Add the key to the list of pressed keys
                                self.gotKeyLock.acquire()
                                self.gotKeys.append(readKey)
                                if len(self.gotKeys) == 1:
                                self.gotKeyEvent.set()
                                self.gotKeyLock.release()

                                # Exit if we are stopping
                                self.wantToStopLock.acquire()
                                if self.wantToStop:
                                self.wantToStopLock.release()
                                self.gotKeyEvent.set()
                                break
                                self.wantToStopLock.release()


                                # If we have reached here we stopped capturing

                                # All we need to do to clean up is ensure that
                                # all the calls to .get() now return None.
                                # To ensure no calls are stuck never returning,
                                # we will leave the event set so any tasks waiting
                                # for it immediately exit. This will be unset upon
                                # starting key capturing again.

                                self.stoppedLock.acquire()

                                # We also need to set this to True so we can start up
                                # capturing again.
                                self.stopped = True
                                self.stopped = True

                                self.keyBlockingKeyLockLossy.acquire()
                                self.keyBlockingKeyLossy = None
                                self.keyBlockingEventLossy.set()
                                self.keyBlockingKeyLockLossy.release()

                                self.keysBlockingGotLock.acquire()
                                self.keyBlockingGotEvent.set()
                                self.keysBlockingGotLock.release()

                                self.stoppedLock.release()


                                The idea is that you can either simply call keyPress.getKey(), which will read a key from the keyboard, then return it.



                                If you want something more than that, I made a KeyCapture object. You can create one via something like keys = keyPress.KeyCapture().



                                Then there are three things you can do:



                                addEvent(functionName) takes in any function that takes in one parameter. Then every time a key is pressed, this function will be called with that key's string as it's input. These are ran in a separate thread, so you can block all you want in them and it won't mess up the functionality of the KeyCapturer nor delay the other events.



                                get() returns a key in the same blocking way as before. It is now needed here because the keys are being captured via the KeyCapture object now, so keyPress.getKey() would conflict with that behavior and both of them would miss some keys since only one key can be captured at a time. Also, say the user presses 'a', then 'b', you call get(), the the user presses 'c'. That get() call will immediately return 'a', then if you call it again it will return 'b', then 'c'. If you call it again it will block until another key is pressed. This ensures that you don't miss any keys, in a blocking way if desired. So in this way it's a little different than keyPress.getKey() from before



                                If you want the behavior of getKey() back, get(lossy=True) is like get(), except that it only returns keys pressed after the call to get(). So in the above example, get() would block until the user presses 'c', and then if you call it again it will block until another key is pressed.



                                getAsync() is a little different. It's designed for something that does a lot of processing, then occasionally comes back and checks which keys were pressed. Thus getAsync() returns a list of all the keys pressed since the last call to getAsync(), in order from oldest key pressed to most recent key pressed. It also doesn't block, meaning that if no keys have been pressed since the last call to getAsync(), an empty will be returned.



                                To actually start capturing keys, you need to call keys.startCapture() with your keys object made above. startCapture is non-blocking, and simply starts one thread that just records the key presses, and another thread to process those key presses. There are two threads to ensure that the thread that records key presses doesn't miss any keys.



                                If you want to stop capturing keys, you can call keys.stopCapture() and it will stop capturing keys. However, since capturing a key is a blocking operation, the thread capturing keys might capture one more key after calling stopCapture().



                                To prevent this, you can pass in an optional parameter(s) into startCapture(functionName, args) of a function that just does something like checks if a key equals 'c' and then exits. It's important that this function does very little before, for example, a sleep here will cause us to miss keys.



                                However, if stopCapture() is called in this function, key captures will be stopped immediately, without trying to capture any more, and that all get() calls will be returned immediately, with None if no keys have been pressed yet.



                                Also, since get() and getAsync() store all the previous keys pressed (until you retrieve them), you can call clearGetList() and clearAsyncList() to forget the keys previously pressed.



                                Note that get(), getAsync() and events are independent, so if a key is pressed:
                                1. One call to get() that is waiting, with lossy on, will return
                                that key. The other waiting calls (if any) will continue waiting.
                                2. That key will be stored in the queue of get keys, so that get() with lossy off will return the oldest key pressed not returned by get() yet.
                                3. All events will be fired with that key as their input
                                4. That key will be stored in the list of getAsync() keys, where that lis twill be returned and set to empty list on the next call to getAsync()



                                If all this is too much, here is an example use case:



                                import keyPress
                                import time
                                import threading

                                def KeyPressed(k, printLock):
                                printLock.acquire()
                                print "Event: " + k
                                printLock.release()
                                time.sleep(4)
                                printLock.acquire()
                                print "Event after delay: " + k
                                printLock.release()

                                def GetKeyBlocking(keys, printLock):
                                while keys.capturing():
                                keyReceived = keys.get()
                                time.sleep(1)
                                printLock.acquire()
                                if not keyReceived is None:
                                print "Block " + keyReceived
                                else:
                                print "Block None"
                                printLock.release()

                                def GetKeyBlockingLossy(keys, printLock):
                                while keys.capturing():
                                keyReceived = keys.get(lossy=True)
                                time.sleep(1)
                                printLock.acquire()
                                if not keyReceived is None:
                                print "Lossy: " + keyReceived
                                else:
                                print "Lossy: None"
                                printLock.release()

                                def CheckToClose(k, (keys, printLock)):
                                printLock.acquire()
                                print "Close: " + k
                                printLock.release()
                                if k == "c":
                                keys.stopCapture()

                                printLock = threading.Lock()

                                print "Press a key:"
                                print "You pressed: " + keyPress.getKey()
                                print ""

                                keys = keyPress.KeyCapture()

                                keys.addEvent(KeyPressed, printLock)



                                print "Starting capture"

                                keys.startCapture(CheckToClose, (keys, printLock))

                                getKeyBlockingThread = threading.Thread(target=GetKeyBlocking, args=(keys, printLock))
                                getKeyBlockingThread.daemon = True
                                getKeyBlockingThread.start()


                                getKeyBlockingThreadLossy = threading.Thread(target=GetKeyBlockingLossy, args=(keys, printLock))
                                getKeyBlockingThreadLossy.daemon = True
                                getKeyBlockingThreadLossy.start()

                                while keys.capturing():
                                keysPressed = keys.getAsync()
                                printLock.acquire()
                                if keysPressed != :
                                print "Async: " + str(keysPressed)
                                printLock.release()
                                time.sleep(1)

                                print "done capturing"


                                It is working well for me from the simple test I made, but I will happily take others feedback as well if there is something I missed.



                                I posted this here as well.






                                share|improve this answer















                                The answers here were informative, however I also wanted a way to get key presses asynchronously and fire off key presses in separate events, all in a thread-safe, cross-platform way. PyGame was also too bloated for me. So I made the following (in Python 2.7 but I suspect it's easily portable), which I figured I'd share here in case it was useful for anyone else. I stored this in a file named keyPress.py.



                                class _Getch:
                                """Gets a single character from standard input. Does not echo to the
                                screen. From http://code.activestate.com/recipes/134892/"""
                                def __init__(self):
                                try:
                                self.impl = _GetchWindows()
                                except ImportError:
                                try:
                                self.impl = _GetchMacCarbon()
                                except(AttributeError, ImportError):
                                self.impl = _GetchUnix()

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


                                class _GetchUnix:
                                def __init__(self):
                                import tty, sys, termios # import termios now or else you'll get the Unix version on the Mac

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

                                class _GetchMacCarbon:
                                """
                                A function which returns the current ASCII key that is down;
                                if no ASCII key is down, the null string is returned. The
                                page http://www.mactech.com/macintosh-c/chap02-1.html was
                                very helpful in figuring out how to do this.
                                """
                                def __init__(self):
                                import Carbon
                                Carbon.Evt #see if it has this (in Unix, it doesn't)

                                def __call__(self):
                                import Carbon
                                if Carbon.Evt.EventAvail(0x0008)[0]==0: # 0x0008 is the keyDownMask
                                return ''
                                else:
                                #
                                # The event contains the following info:
                                # (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1]
                                #
                                # The message (msg) contains the ASCII char which is
                                # extracted with the 0x000000FF charCodeMask; this
                                # number is converted to an ASCII character with chr() and
                                # returned
                                #
                                (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1]
                                return chr(msg & 0x000000FF)

                                import threading


                                # From https://stackoverflow.com/a/2022629/2924421
                                class Event(list):
                                def __call__(self, *args, **kwargs):
                                for f in self:
                                f(*args, **kwargs)

                                def __repr__(self):
                                return "Event(%s)" % list.__repr__(self)


                                def getKey():
                                inkey = _Getch()
                                import sys
                                for i in xrange(sys.maxint):
                                k=inkey()
                                if k<>'':break
                                return k

                                class KeyCallbackFunction():
                                callbackParam = None
                                actualFunction = None

                                def __init__(self, actualFunction, callbackParam):
                                self.actualFunction = actualFunction
                                self.callbackParam = callbackParam

                                def doCallback(self, inputKey):
                                if not self.actualFunction is None:
                                if self.callbackParam is None:
                                callbackFunctionThread = threading.Thread(target=self.actualFunction, args=(inputKey,))
                                else:
                                callbackFunctionThread = threading.Thread(target=self.actualFunction, args=(inputKey,self.callbackParam))

                                callbackFunctionThread.daemon = True
                                callbackFunctionThread.start()



                                class KeyCapture():


                                gotKeyLock = threading.Lock()
                                gotKeys =
                                gotKeyEvent = threading.Event()

                                keyBlockingSetKeyLock = threading.Lock()

                                addingEventsLock = threading.Lock()
                                keyReceiveEvents = Event()


                                keysGotLock = threading.Lock()
                                keysGot =

                                keyBlockingKeyLockLossy = threading.Lock()
                                keyBlockingKeyLossy = None
                                keyBlockingEventLossy = threading.Event()

                                keysBlockingGotLock = threading.Lock()
                                keysBlockingGot =
                                keyBlockingGotEvent = threading.Event()



                                wantToStopLock = threading.Lock()
                                wantToStop = False

                                stoppedLock = threading.Lock()
                                stopped = True

                                isRunningEvent = False

                                getKeyThread = None

                                keyFunction = None
                                keyArgs = None

                                # Begin capturing keys. A seperate thread is launched that
                                # captures key presses, and then these can be received via get,
                                # getAsync, and adding an event via addEvent. Note that this
                                # will prevent the system to accept keys as normal (say, if
                                # you are in a python shell) because it overrides that key
                                # capturing behavior.

                                # If you start capture when it's already been started, a
                                # InterruptedError("Keys are still being captured")
                                # will be thrown

                                # Note that get(), getAsync() and events are independent, so if a key is pressed:
                                #
                                # 1: Any calls to get() that are waiting, with lossy on, will return
                                # that key
                                # 2: It will be stored in the queue of get keys, so that get() with lossy
                                # off will return the oldest key pressed not returned by get() yet.
                                # 3: All events will be fired with that key as their input
                                # 4: It will be stored in the list of getAsync() keys, where that list
                                # will be returned and set to empty list on the next call to getAsync().
                                # get() call with it, aand add it to the getAsync() list.
                                def startCapture(self, keyFunction=None, args=None):
                                # Make sure we aren't already capturing keys
                                self.stoppedLock.acquire()
                                if not self.stopped:
                                self.stoppedLock.release()
                                raise InterruptedError("Keys are still being captured")
                                return
                                self.stopped = False
                                self.stoppedLock.release()

                                # If we have captured before, we need to allow the get() calls to actually
                                # wait for key presses now by clearing the event
                                if self.keyBlockingEventLossy.is_set():
                                self.keyBlockingEventLossy.clear()

                                # Have one function that we call every time a key is captured, intended for stopping capture
                                # as desired
                                self.keyFunction = keyFunction
                                self.keyArgs = args

                                # Begin capturing keys (in a seperate thread)
                                self.getKeyThread = threading.Thread(target=self._threadProcessKeyPresses)
                                self.getKeyThread.daemon = True
                                self.getKeyThread.start()

                                # Process key captures (in a seperate thread)
                                self.getKeyThread = threading.Thread(target=self._threadStoreKeyPresses)
                                self.getKeyThread.daemon = True
                                self.getKeyThread.start()


                                def capturing(self):
                                self.stoppedLock.acquire()
                                isCapturing = not self.stopped
                                self.stoppedLock.release()
                                return isCapturing
                                # Stops the thread that is capturing keys on the first opporunity
                                # has to do so. It usually can't stop immediately because getting a key
                                # is a blocking process, so this will probably stop capturing after the
                                # next key is pressed.
                                #
                                # However, Sometimes if you call stopCapture it will stop before starting capturing the
                                # next key, due to multithreading race conditions. So if you want to stop capturing
                                # reliably, call stopCapture in a function added via addEvent. Then you are
                                # guaranteed that capturing will stop immediately after the rest of the callback
                                # functions are called (before starting to capture the next key).
                                def stopCapture(self):
                                self.wantToStopLock.acquire()
                                self.wantToStop = True
                                self.wantToStopLock.release()

                                # Takes in a function that will be called every time a key is pressed (with that
                                # key passed in as the first paramater in that function)
                                def addEvent(self, keyPressEventFunction, args=None):
                                self.addingEventsLock.acquire()
                                callbackHolder = KeyCallbackFunction(keyPressEventFunction, args)
                                self.keyReceiveEvents.append(callbackHolder.doCallback)
                                self.addingEventsLock.release()
                                def clearEvents(self):
                                self.addingEventsLock.acquire()
                                self.keyReceiveEvents = Event()
                                self.addingEventsLock.release()
                                # Gets a key captured by this KeyCapture, blocking until a key is pressed.
                                # There is an optional lossy paramater:
                                # If True all keys before this call are ignored, and the next pressed key
                                # will be returned.
                                # If False this will return the oldest key captured that hasn't
                                # been returned by get yet. False is the default.
                                def get(self, lossy=False):
                                if lossy:
                                # Wait for the next key to be pressed
                                self.keyBlockingEventLossy.wait()
                                self.keyBlockingKeyLockLossy.acquire()
                                keyReceived = self.keyBlockingKeyLossy
                                self.keyBlockingKeyLockLossy.release()
                                return keyReceived
                                else:
                                while True:
                                # Wait until a key is pressed
                                self.keyBlockingGotEvent.wait()

                                # Get the key pressed
                                readKey = None
                                self.keysBlockingGotLock.acquire()
                                # Get a key if it exists
                                if len(self.keysBlockingGot) != 0:
                                readKey = self.keysBlockingGot.pop(0)
                                # If we got the last one, tell us to wait
                                if len(self.keysBlockingGot) == 0:
                                self.keyBlockingGotEvent.clear()
                                self.keysBlockingGotLock.release()

                                # Process the key (if it actually exists)
                                if not readKey is None:
                                return readKey

                                # Exit if we are stopping
                                self.wantToStopLock.acquire()
                                if self.wantToStop:
                                self.wantToStopLock.release()
                                return None
                                self.wantToStopLock.release()




                                def clearGetList(self):
                                self.keysBlockingGotLock.acquire()
                                self.keysBlockingGot =
                                self.keysBlockingGotLock.release()

                                # Gets a list of all keys pressed since the last call to getAsync, in order
                                # from first pressed, second pressed, .., most recent pressed
                                def getAsync(self):
                                self.keysGotLock.acquire();
                                keysPressedList = list(self.keysGot)
                                self.keysGot =
                                self.keysGotLock.release()
                                return keysPressedList

                                def clearAsyncList(self):
                                self.keysGotLock.acquire();
                                self.keysGot =
                                self.keysGotLock.release();

                                def _processKey(self, readKey):
                                # Append to list for GetKeyAsync
                                self.keysGotLock.acquire()
                                self.keysGot.append(readKey)
                                self.keysGotLock.release()

                                # Call lossy blocking key events
                                self.keyBlockingKeyLockLossy.acquire()
                                self.keyBlockingKeyLossy = readKey
                                self.keyBlockingEventLossy.set()
                                self.keyBlockingEventLossy.clear()
                                self.keyBlockingKeyLockLossy.release()

                                # Call non-lossy blocking key events
                                self.keysBlockingGotLock.acquire()
                                self.keysBlockingGot.append(readKey)
                                if len(self.keysBlockingGot) == 1:
                                self.keyBlockingGotEvent.set()
                                self.keysBlockingGotLock.release()

                                # Call events added by AddEvent
                                self.addingEventsLock.acquire()
                                self.keyReceiveEvents(readKey)
                                self.addingEventsLock.release()

                                def _threadProcessKeyPresses(self):
                                while True:
                                # Wait until a key is pressed
                                self.gotKeyEvent.wait()

                                # Get the key pressed
                                readKey = None
                                self.gotKeyLock.acquire()
                                # Get a key if it exists
                                if len(self.gotKeys) != 0:
                                readKey = self.gotKeys.pop(0)
                                # If we got the last one, tell us to wait
                                if len(self.gotKeys) == 0:
                                self.gotKeyEvent.clear()
                                self.gotKeyLock.release()

                                # Process the key (if it actually exists)
                                if not readKey is None:
                                self._processKey(readKey)

                                # Exit if we are stopping
                                self.wantToStopLock.acquire()
                                if self.wantToStop:
                                self.wantToStopLock.release()
                                break
                                self.wantToStopLock.release()

                                def _threadStoreKeyPresses(self):
                                while True:
                                # Get a key
                                readKey = getKey()

                                # Run the potential shut down function
                                if not self.keyFunction is None:
                                self.keyFunction(readKey, self.keyArgs)

                                # Add the key to the list of pressed keys
                                self.gotKeyLock.acquire()
                                self.gotKeys.append(readKey)
                                if len(self.gotKeys) == 1:
                                self.gotKeyEvent.set()
                                self.gotKeyLock.release()

                                # Exit if we are stopping
                                self.wantToStopLock.acquire()
                                if self.wantToStop:
                                self.wantToStopLock.release()
                                self.gotKeyEvent.set()
                                break
                                self.wantToStopLock.release()


                                # If we have reached here we stopped capturing

                                # All we need to do to clean up is ensure that
                                # all the calls to .get() now return None.
                                # To ensure no calls are stuck never returning,
                                # we will leave the event set so any tasks waiting
                                # for it immediately exit. This will be unset upon
                                # starting key capturing again.

                                self.stoppedLock.acquire()

                                # We also need to set this to True so we can start up
                                # capturing again.
                                self.stopped = True
                                self.stopped = True

                                self.keyBlockingKeyLockLossy.acquire()
                                self.keyBlockingKeyLossy = None
                                self.keyBlockingEventLossy.set()
                                self.keyBlockingKeyLockLossy.release()

                                self.keysBlockingGotLock.acquire()
                                self.keyBlockingGotEvent.set()
                                self.keysBlockingGotLock.release()

                                self.stoppedLock.release()


                                The idea is that you can either simply call keyPress.getKey(), which will read a key from the keyboard, then return it.



                                If you want something more than that, I made a KeyCapture object. You can create one via something like keys = keyPress.KeyCapture().



                                Then there are three things you can do:



                                addEvent(functionName) takes in any function that takes in one parameter. Then every time a key is pressed, this function will be called with that key's string as it's input. These are ran in a separate thread, so you can block all you want in them and it won't mess up the functionality of the KeyCapturer nor delay the other events.



                                get() returns a key in the same blocking way as before. It is now needed here because the keys are being captured via the KeyCapture object now, so keyPress.getKey() would conflict with that behavior and both of them would miss some keys since only one key can be captured at a time. Also, say the user presses 'a', then 'b', you call get(), the the user presses 'c'. That get() call will immediately return 'a', then if you call it again it will return 'b', then 'c'. If you call it again it will block until another key is pressed. This ensures that you don't miss any keys, in a blocking way if desired. So in this way it's a little different than keyPress.getKey() from before



                                If you want the behavior of getKey() back, get(lossy=True) is like get(), except that it only returns keys pressed after the call to get(). So in the above example, get() would block until the user presses 'c', and then if you call it again it will block until another key is pressed.



                                getAsync() is a little different. It's designed for something that does a lot of processing, then occasionally comes back and checks which keys were pressed. Thus getAsync() returns a list of all the keys pressed since the last call to getAsync(), in order from oldest key pressed to most recent key pressed. It also doesn't block, meaning that if no keys have been pressed since the last call to getAsync(), an empty will be returned.



                                To actually start capturing keys, you need to call keys.startCapture() with your keys object made above. startCapture is non-blocking, and simply starts one thread that just records the key presses, and another thread to process those key presses. There are two threads to ensure that the thread that records key presses doesn't miss any keys.



                                If you want to stop capturing keys, you can call keys.stopCapture() and it will stop capturing keys. However, since capturing a key is a blocking operation, the thread capturing keys might capture one more key after calling stopCapture().



                                To prevent this, you can pass in an optional parameter(s) into startCapture(functionName, args) of a function that just does something like checks if a key equals 'c' and then exits. It's important that this function does very little before, for example, a sleep here will cause us to miss keys.



                                However, if stopCapture() is called in this function, key captures will be stopped immediately, without trying to capture any more, and that all get() calls will be returned immediately, with None if no keys have been pressed yet.



                                Also, since get() and getAsync() store all the previous keys pressed (until you retrieve them), you can call clearGetList() and clearAsyncList() to forget the keys previously pressed.



                                Note that get(), getAsync() and events are independent, so if a key is pressed:
                                1. One call to get() that is waiting, with lossy on, will return
                                that key. The other waiting calls (if any) will continue waiting.
                                2. That key will be stored in the queue of get keys, so that get() with lossy off will return the oldest key pressed not returned by get() yet.
                                3. All events will be fired with that key as their input
                                4. That key will be stored in the list of getAsync() keys, where that lis twill be returned and set to empty list on the next call to getAsync()



                                If all this is too much, here is an example use case:



                                import keyPress
                                import time
                                import threading

                                def KeyPressed(k, printLock):
                                printLock.acquire()
                                print "Event: " + k
                                printLock.release()
                                time.sleep(4)
                                printLock.acquire()
                                print "Event after delay: " + k
                                printLock.release()

                                def GetKeyBlocking(keys, printLock):
                                while keys.capturing():
                                keyReceived = keys.get()
                                time.sleep(1)
                                printLock.acquire()
                                if not keyReceived is None:
                                print "Block " + keyReceived
                                else:
                                print "Block None"
                                printLock.release()

                                def GetKeyBlockingLossy(keys, printLock):
                                while keys.capturing():
                                keyReceived = keys.get(lossy=True)
                                time.sleep(1)
                                printLock.acquire()
                                if not keyReceived is None:
                                print "Lossy: " + keyReceived
                                else:
                                print "Lossy: None"
                                printLock.release()

                                def CheckToClose(k, (keys, printLock)):
                                printLock.acquire()
                                print "Close: " + k
                                printLock.release()
                                if k == "c":
                                keys.stopCapture()

                                printLock = threading.Lock()

                                print "Press a key:"
                                print "You pressed: " + keyPress.getKey()
                                print ""

                                keys = keyPress.KeyCapture()

                                keys.addEvent(KeyPressed, printLock)



                                print "Starting capture"

                                keys.startCapture(CheckToClose, (keys, printLock))

                                getKeyBlockingThread = threading.Thread(target=GetKeyBlocking, args=(keys, printLock))
                                getKeyBlockingThread.daemon = True
                                getKeyBlockingThread.start()


                                getKeyBlockingThreadLossy = threading.Thread(target=GetKeyBlockingLossy, args=(keys, printLock))
                                getKeyBlockingThreadLossy.daemon = True
                                getKeyBlockingThreadLossy.start()

                                while keys.capturing():
                                keysPressed = keys.getAsync()
                                printLock.acquire()
                                if keysPressed != :
                                print "Async: " + str(keysPressed)
                                printLock.release()
                                time.sleep(1)

                                print "done capturing"


                                It is working well for me from the simple test I made, but I will happily take others feedback as well if there is something I missed.



                                I posted this here as well.







                                share|improve this answer














                                share|improve this answer



                                share|improve this answer








                                edited May 23 '17 at 12:10









                                Community

                                11




                                11










                                answered Jul 31 '15 at 15:17









                                PhylliidaPhylliida

                                2,2541224




                                2,2541224























                                    3














                                    This is NON-BLOCKING, reads a key and and stores it in keypress.key.



                                    import Tkinter as tk


                                    class Keypress:
                                    def __init__(self):
                                    self.root = tk.Tk()
                                    self.root.geometry('300x200')
                                    self.root.bind('<KeyPress>', self.onKeyPress)

                                    def onKeyPress(self, event):
                                    self.key = event.char

                                    def __eq__(self, other):
                                    return self.key == other

                                    def __str__(self):
                                    return self.key


                                    in your programm



                                    keypress = Keypress()

                                    while something:
                                    do something
                                    if keypress == 'c':
                                    break
                                    elif keypress == 'i':
                                    print('info')
                                    else:
                                    print("i dont understand %s" % keypress)





                                    share|improve this answer





















                                    • 3





                                      does this work for command line applications?

                                      – ThorSummoner
                                      Jan 23 '15 at 7:36











                                    • Yes @ThorSummoner

                                      – Davoud Taghawi-Nejad
                                      Mar 27 '15 at 3:12






                                    • 1





                                      @ThorSummoner: This code has a number of problems — so no, it won't work for command line applications.

                                      – martineau
                                      Aug 31 '15 at 0:29











                                    • It runs for a command line application, given that the windows manager is running.

                                      – Davoud Taghawi-Nejad
                                      Aug 31 '15 at 17:36






                                    • 1





                                      So basically it doesn't work for command line applications...

                                      – Mehdi
                                      Nov 17 '15 at 13:06
















                                    3














                                    This is NON-BLOCKING, reads a key and and stores it in keypress.key.



                                    import Tkinter as tk


                                    class Keypress:
                                    def __init__(self):
                                    self.root = tk.Tk()
                                    self.root.geometry('300x200')
                                    self.root.bind('<KeyPress>', self.onKeyPress)

                                    def onKeyPress(self, event):
                                    self.key = event.char

                                    def __eq__(self, other):
                                    return self.key == other

                                    def __str__(self):
                                    return self.key


                                    in your programm



                                    keypress = Keypress()

                                    while something:
                                    do something
                                    if keypress == 'c':
                                    break
                                    elif keypress == 'i':
                                    print('info')
                                    else:
                                    print("i dont understand %s" % keypress)





                                    share|improve this answer





















                                    • 3





                                      does this work for command line applications?

                                      – ThorSummoner
                                      Jan 23 '15 at 7:36











                                    • Yes @ThorSummoner

                                      – Davoud Taghawi-Nejad
                                      Mar 27 '15 at 3:12






                                    • 1





                                      @ThorSummoner: This code has a number of problems — so no, it won't work for command line applications.

                                      – martineau
                                      Aug 31 '15 at 0:29











                                    • It runs for a command line application, given that the windows manager is running.

                                      – Davoud Taghawi-Nejad
                                      Aug 31 '15 at 17:36






                                    • 1





                                      So basically it doesn't work for command line applications...

                                      – Mehdi
                                      Nov 17 '15 at 13:06














                                    3












                                    3








                                    3







                                    This is NON-BLOCKING, reads a key and and stores it in keypress.key.



                                    import Tkinter as tk


                                    class Keypress:
                                    def __init__(self):
                                    self.root = tk.Tk()
                                    self.root.geometry('300x200')
                                    self.root.bind('<KeyPress>', self.onKeyPress)

                                    def onKeyPress(self, event):
                                    self.key = event.char

                                    def __eq__(self, other):
                                    return self.key == other

                                    def __str__(self):
                                    return self.key


                                    in your programm



                                    keypress = Keypress()

                                    while something:
                                    do something
                                    if keypress == 'c':
                                    break
                                    elif keypress == 'i':
                                    print('info')
                                    else:
                                    print("i dont understand %s" % keypress)





                                    share|improve this answer















                                    This is NON-BLOCKING, reads a key and and stores it in keypress.key.



                                    import Tkinter as tk


                                    class Keypress:
                                    def __init__(self):
                                    self.root = tk.Tk()
                                    self.root.geometry('300x200')
                                    self.root.bind('<KeyPress>', self.onKeyPress)

                                    def onKeyPress(self, event):
                                    self.key = event.char

                                    def __eq__(self, other):
                                    return self.key == other

                                    def __str__(self):
                                    return self.key


                                    in your programm



                                    keypress = Keypress()

                                    while something:
                                    do something
                                    if keypress == 'c':
                                    break
                                    elif keypress == 'i':
                                    print('info')
                                    else:
                                    print("i dont understand %s" % keypress)






                                    share|improve this answer














                                    share|improve this answer



                                    share|improve this answer








                                    edited Jun 22 '14 at 21:03

























                                    answered Jun 22 '14 at 20:40









                                    Davoud Taghawi-NejadDavoud Taghawi-Nejad

                                    9,04894365




                                    9,04894365








                                    • 3





                                      does this work for command line applications?

                                      – ThorSummoner
                                      Jan 23 '15 at 7:36











                                    • Yes @ThorSummoner

                                      – Davoud Taghawi-Nejad
                                      Mar 27 '15 at 3:12






                                    • 1





                                      @ThorSummoner: This code has a number of problems — so no, it won't work for command line applications.

                                      – martineau
                                      Aug 31 '15 at 0:29











                                    • It runs for a command line application, given that the windows manager is running.

                                      – Davoud Taghawi-Nejad
                                      Aug 31 '15 at 17:36






                                    • 1





                                      So basically it doesn't work for command line applications...

                                      – Mehdi
                                      Nov 17 '15 at 13:06














                                    • 3





                                      does this work for command line applications?

                                      – ThorSummoner
                                      Jan 23 '15 at 7:36











                                    • Yes @ThorSummoner

                                      – Davoud Taghawi-Nejad
                                      Mar 27 '15 at 3:12






                                    • 1





                                      @ThorSummoner: This code has a number of problems — so no, it won't work for command line applications.

                                      – martineau
                                      Aug 31 '15 at 0:29











                                    • It runs for a command line application, given that the windows manager is running.

                                      – Davoud Taghawi-Nejad
                                      Aug 31 '15 at 17:36






                                    • 1





                                      So basically it doesn't work for command line applications...

                                      – Mehdi
                                      Nov 17 '15 at 13:06








                                    3




                                    3





                                    does this work for command line applications?

                                    – ThorSummoner
                                    Jan 23 '15 at 7:36





                                    does this work for command line applications?

                                    – ThorSummoner
                                    Jan 23 '15 at 7:36













                                    Yes @ThorSummoner

                                    – Davoud Taghawi-Nejad
                                    Mar 27 '15 at 3:12





                                    Yes @ThorSummoner

                                    – Davoud Taghawi-Nejad
                                    Mar 27 '15 at 3:12




                                    1




                                    1





                                    @ThorSummoner: This code has a number of problems — so no, it won't work for command line applications.

                                    – martineau
                                    Aug 31 '15 at 0:29





                                    @ThorSummoner: This code has a number of problems — so no, it won't work for command line applications.

                                    – martineau
                                    Aug 31 '15 at 0:29













                                    It runs for a command line application, given that the windows manager is running.

                                    – Davoud Taghawi-Nejad
                                    Aug 31 '15 at 17:36





                                    It runs for a command line application, given that the windows manager is running.

                                    – Davoud Taghawi-Nejad
                                    Aug 31 '15 at 17:36




                                    1




                                    1





                                    So basically it doesn't work for command line applications...

                                    – Mehdi
                                    Nov 17 '15 at 13:06





                                    So basically it doesn't work for command line applications...

                                    – Mehdi
                                    Nov 17 '15 at 13:06











                                    3














                                    Try using this: http://home.wlu.edu/~levys/software/kbhit.py
                                    It's non-blocking (that means that you can have a while loop and detect a key press without stopping it) and cross-platform.



                                    import os

                                    # Windows
                                    if os.name == 'nt':
                                    import msvcrt

                                    # Posix (Linux, OS X)
                                    else:
                                    import sys
                                    import termios
                                    import atexit
                                    from select import select


                                    class KBHit:

                                    def __init__(self):
                                    '''Creates a KBHit object that you can call to do various keyboard things.'''

                                    if os.name == 'nt':
                                    pass

                                    else:

                                    # Save the terminal settings
                                    self.fd = sys.stdin.fileno()
                                    self.new_term = termios.tcgetattr(self.fd)
                                    self.old_term = termios.tcgetattr(self.fd)

                                    # New terminal setting unbuffered
                                    self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO)
                                    termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term)

                                    # Support normal-terminal reset at exit
                                    atexit.register(self.set_normal_term)


                                    def set_normal_term(self):
                                    ''' Resets to normal terminal. On Windows this is a no-op.
                                    '''

                                    if os.name == 'nt':
                                    pass

                                    else:
                                    termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term)


                                    def getch(self):
                                    ''' Returns a keyboard character after kbhit() has been called.
                                    Should not be called in the same program as getarrow().
                                    '''

                                    s = ''

                                    if os.name == 'nt':
                                    return msvcrt.getch().decode('utf-8')

                                    else:
                                    return sys.stdin.read(1)


                                    def getarrow(self):
                                    ''' Returns an arrow-key code after kbhit() has been called. Codes are
                                    0 : up
                                    1 : right
                                    2 : down
                                    3 : left
                                    Should not be called in the same program as getch().
                                    '''

                                    if os.name == 'nt':
                                    msvcrt.getch() # skip 0xE0
                                    c = msvcrt.getch()
                                    vals = [72, 77, 80, 75]

                                    else:
                                    c = sys.stdin.read(3)[2]
                                    vals = [65, 67, 66, 68]

                                    return vals.index(ord(c.decode('utf-8')))


                                    def kbhit(self):
                                    ''' Returns True if keyboard character was hit, False otherwise.
                                    '''
                                    if os.name == 'nt':
                                    return msvcrt.kbhit()

                                    else:
                                    dr,dw,de = select([sys.stdin], , , 0)
                                    return dr !=


                                    An example to use this:



                                    import kbhit

                                    kb = kbhit.KBHit()

                                    while(True):
                                    print("Key not pressed") #Do something
                                    if kb.kbhit(): #If a key is pressed:
                                    k_in = kb.getch() #Detect what key was pressed
                                    print("You pressed ", k_in, "!") #Do something
                                    kb.set_normal_term()


                                    Or you could use the getch module from PyPi. But this would block the while loop






                                    share|improve this answer






























                                      3














                                      Try using this: http://home.wlu.edu/~levys/software/kbhit.py
                                      It's non-blocking (that means that you can have a while loop and detect a key press without stopping it) and cross-platform.



                                      import os

                                      # Windows
                                      if os.name == 'nt':
                                      import msvcrt

                                      # Posix (Linux, OS X)
                                      else:
                                      import sys
                                      import termios
                                      import atexit
                                      from select import select


                                      class KBHit:

                                      def __init__(self):
                                      '''Creates a KBHit object that you can call to do various keyboard things.'''

                                      if os.name == 'nt':
                                      pass

                                      else:

                                      # Save the terminal settings
                                      self.fd = sys.stdin.fileno()
                                      self.new_term = termios.tcgetattr(self.fd)
                                      self.old_term = termios.tcgetattr(self.fd)

                                      # New terminal setting unbuffered
                                      self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO)
                                      termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term)

                                      # Support normal-terminal reset at exit
                                      atexit.register(self.set_normal_term)


                                      def set_normal_term(self):
                                      ''' Resets to normal terminal. On Windows this is a no-op.
                                      '''

                                      if os.name == 'nt':
                                      pass

                                      else:
                                      termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term)


                                      def getch(self):
                                      ''' Returns a keyboard character after kbhit() has been called.
                                      Should not be called in the same program as getarrow().
                                      '''

                                      s = ''

                                      if os.name == 'nt':
                                      return msvcrt.getch().decode('utf-8')

                                      else:
                                      return sys.stdin.read(1)


                                      def getarrow(self):
                                      ''' Returns an arrow-key code after kbhit() has been called. Codes are
                                      0 : up
                                      1 : right
                                      2 : down
                                      3 : left
                                      Should not be called in the same program as getch().
                                      '''

                                      if os.name == 'nt':
                                      msvcrt.getch() # skip 0xE0
                                      c = msvcrt.getch()
                                      vals = [72, 77, 80, 75]

                                      else:
                                      c = sys.stdin.read(3)[2]
                                      vals = [65, 67, 66, 68]

                                      return vals.index(ord(c.decode('utf-8')))


                                      def kbhit(self):
                                      ''' Returns True if keyboard character was hit, False otherwise.
                                      '''
                                      if os.name == 'nt':
                                      return msvcrt.kbhit()

                                      else:
                                      dr,dw,de = select([sys.stdin], , , 0)
                                      return dr !=


                                      An example to use this:



                                      import kbhit

                                      kb = kbhit.KBHit()

                                      while(True):
                                      print("Key not pressed") #Do something
                                      if kb.kbhit(): #If a key is pressed:
                                      k_in = kb.getch() #Detect what key was pressed
                                      print("You pressed ", k_in, "!") #Do something
                                      kb.set_normal_term()


                                      Or you could use the getch module from PyPi. But this would block the while loop






                                      share|improve this answer




























                                        3












                                        3








                                        3







                                        Try using this: http://home.wlu.edu/~levys/software/kbhit.py
                                        It's non-blocking (that means that you can have a while loop and detect a key press without stopping it) and cross-platform.



                                        import os

                                        # Windows
                                        if os.name == 'nt':
                                        import msvcrt

                                        # Posix (Linux, OS X)
                                        else:
                                        import sys
                                        import termios
                                        import atexit
                                        from select import select


                                        class KBHit:

                                        def __init__(self):
                                        '''Creates a KBHit object that you can call to do various keyboard things.'''

                                        if os.name == 'nt':
                                        pass

                                        else:

                                        # Save the terminal settings
                                        self.fd = sys.stdin.fileno()
                                        self.new_term = termios.tcgetattr(self.fd)
                                        self.old_term = termios.tcgetattr(self.fd)

                                        # New terminal setting unbuffered
                                        self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO)
                                        termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term)

                                        # Support normal-terminal reset at exit
                                        atexit.register(self.set_normal_term)


                                        def set_normal_term(self):
                                        ''' Resets to normal terminal. On Windows this is a no-op.
                                        '''

                                        if os.name == 'nt':
                                        pass

                                        else:
                                        termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term)


                                        def getch(self):
                                        ''' Returns a keyboard character after kbhit() has been called.
                                        Should not be called in the same program as getarrow().
                                        '''

                                        s = ''

                                        if os.name == 'nt':
                                        return msvcrt.getch().decode('utf-8')

                                        else:
                                        return sys.stdin.read(1)


                                        def getarrow(self):
                                        ''' Returns an arrow-key code after kbhit() has been called. Codes are
                                        0 : up
                                        1 : right
                                        2 : down
                                        3 : left
                                        Should not be called in the same program as getch().
                                        '''

                                        if os.name == 'nt':
                                        msvcrt.getch() # skip 0xE0
                                        c = msvcrt.getch()
                                        vals = [72, 77, 80, 75]

                                        else:
                                        c = sys.stdin.read(3)[2]
                                        vals = [65, 67, 66, 68]

                                        return vals.index(ord(c.decode('utf-8')))


                                        def kbhit(self):
                                        ''' Returns True if keyboard character was hit, False otherwise.
                                        '''
                                        if os.name == 'nt':
                                        return msvcrt.kbhit()

                                        else:
                                        dr,dw,de = select([sys.stdin], , , 0)
                                        return dr !=


                                        An example to use this:



                                        import kbhit

                                        kb = kbhit.KBHit()

                                        while(True):
                                        print("Key not pressed") #Do something
                                        if kb.kbhit(): #If a key is pressed:
                                        k_in = kb.getch() #Detect what key was pressed
                                        print("You pressed ", k_in, "!") #Do something
                                        kb.set_normal_term()


                                        Or you could use the getch module from PyPi. But this would block the while loop






                                        share|improve this answer















                                        Try using this: http://home.wlu.edu/~levys/software/kbhit.py
                                        It's non-blocking (that means that you can have a while loop and detect a key press without stopping it) and cross-platform.



                                        import os

                                        # Windows
                                        if os.name == 'nt':
                                        import msvcrt

                                        # Posix (Linux, OS X)
                                        else:
                                        import sys
                                        import termios
                                        import atexit
                                        from select import select


                                        class KBHit:

                                        def __init__(self):
                                        '''Creates a KBHit object that you can call to do various keyboard things.'''

                                        if os.name == 'nt':
                                        pass

                                        else:

                                        # Save the terminal settings
                                        self.fd = sys.stdin.fileno()
                                        self.new_term = termios.tcgetattr(self.fd)
                                        self.old_term = termios.tcgetattr(self.fd)

                                        # New terminal setting unbuffered
                                        self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO)
                                        termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term)

                                        # Support normal-terminal reset at exit
                                        atexit.register(self.set_normal_term)


                                        def set_normal_term(self):
                                        ''' Resets to normal terminal. On Windows this is a no-op.
                                        '''

                                        if os.name == 'nt':
                                        pass

                                        else:
                                        termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term)


                                        def getch(self):
                                        ''' Returns a keyboard character after kbhit() has been called.
                                        Should not be called in the same program as getarrow().
                                        '''

                                        s = ''

                                        if os.name == 'nt':
                                        return msvcrt.getch().decode('utf-8')

                                        else:
                                        return sys.stdin.read(1)


                                        def getarrow(self):
                                        ''' Returns an arrow-key code after kbhit() has been called. Codes are
                                        0 : up
                                        1 : right
                                        2 : down
                                        3 : left
                                        Should not be called in the same program as getch().
                                        '''

                                        if os.name == 'nt':
                                        msvcrt.getch() # skip 0xE0
                                        c = msvcrt.getch()
                                        vals = [72, 77, 80, 75]

                                        else:
                                        c = sys.stdin.read(3)[2]
                                        vals = [65, 67, 66, 68]

                                        return vals.index(ord(c.decode('utf-8')))


                                        def kbhit(self):
                                        ''' Returns True if keyboard character was hit, False otherwise.
                                        '''
                                        if os.name == 'nt':
                                        return msvcrt.kbhit()

                                        else:
                                        dr,dw,de = select([sys.stdin], , , 0)
                                        return dr !=


                                        An example to use this:



                                        import kbhit

                                        kb = kbhit.KBHit()

                                        while(True):
                                        print("Key not pressed") #Do something
                                        if kb.kbhit(): #If a key is pressed:
                                        k_in = kb.getch() #Detect what key was pressed
                                        print("You pressed ", k_in, "!") #Do something
                                        kb.set_normal_term()


                                        Or you could use the getch module from PyPi. But this would block the while loop







                                        share|improve this answer














                                        share|improve this answer



                                        share|improve this answer








                                        edited Apr 28 '17 at 20:40









                                        NinjaFart

                                        1,38611215




                                        1,38611215










                                        answered Jul 21 '15 at 21:42









                                        jdev6jdev6

                                        312




                                        312























                                            2














                                            Try this with pygame:



                                            import pygame
                                            pygame.init() // eliminate error, pygame.error: video system not initialized
                                            keys = pygame.key.get_pressed()

                                            if keys[pygame.K_SPACE]:
                                            d = "space key"

                                            print "You pressed the", d, "."





                                            share|improve this answer


























                                            • That is a neat idea, but it doesn't work on the command line: pygame.error: video system not initialized

                                              – dirkjot
                                              Apr 21 '15 at 11:15
















                                            2














                                            Try this with pygame:



                                            import pygame
                                            pygame.init() // eliminate error, pygame.error: video system not initialized
                                            keys = pygame.key.get_pressed()

                                            if keys[pygame.K_SPACE]:
                                            d = "space key"

                                            print "You pressed the", d, "."





                                            share|improve this answer


























                                            • That is a neat idea, but it doesn't work on the command line: pygame.error: video system not initialized

                                              – dirkjot
                                              Apr 21 '15 at 11:15














                                            2












                                            2








                                            2







                                            Try this with pygame:



                                            import pygame
                                            pygame.init() // eliminate error, pygame.error: video system not initialized
                                            keys = pygame.key.get_pressed()

                                            if keys[pygame.K_SPACE]:
                                            d = "space key"

                                            print "You pressed the", d, "."





                                            share|improve this answer















                                            Try this with pygame:



                                            import pygame
                                            pygame.init() // eliminate error, pygame.error: video system not initialized
                                            keys = pygame.key.get_pressed()

                                            if keys[pygame.K_SPACE]:
                                            d = "space key"

                                            print "You pressed the", d, "."






                                            share|improve this answer














                                            share|improve this answer



                                            share|improve this answer








                                            edited Apr 3 '16 at 14:08









                                            Hackaholic

                                            12.4k12541




                                            12.4k12541










                                            answered Feb 21 '15 at 0:36









                                            PyGuyPyGuy

                                            291




                                            291













                                            • That is a neat idea, but it doesn't work on the command line: pygame.error: video system not initialized

                                              – dirkjot
                                              Apr 21 '15 at 11:15



















                                            • That is a neat idea, but it doesn't work on the command line: pygame.error: video system not initialized

                                              – dirkjot
                                              Apr 21 '15 at 11:15

















                                            That is a neat idea, but it doesn't work on the command line: pygame.error: video system not initialized

                                            – dirkjot
                                            Apr 21 '15 at 11:15





                                            That is a neat idea, but it doesn't work on the command line: pygame.error: video system not initialized

                                            – dirkjot
                                            Apr 21 '15 at 11:15











                                            2














                                            A comment in one of the other answers mentioned cbreak mode, which is important for Unix implementations because you generally don't want ^C (KeyboardError) to be consumed by getchar (as it will when you set the terminal to raw mode, as done by most other answers).



                                            Another important detail is that if you're looking to read one character and not one byte, you should read 4 bytes from the input stream, as that's the maximum number of bytes a single character will consist of in UTF-8 (Python 3+). Reading only a single byte will produce unexpected results for multi-byte characters such as keypad arrows.



                                            Here's my changed implementation for Unix:



                                            import contextlib
                                            import os
                                            import sys
                                            import termios
                                            import tty


                                            _MAX_CHARACTER_BYTE_LENGTH = 4


                                            @contextlib.contextmanager
                                            def _tty_reset(file_descriptor):
                                            """
                                            A context manager that saves the tty flags of a file descriptor upon
                                            entering and restores them upon exiting.
                                            """
                                            old_settings = termios.tcgetattr(file_descriptor)
                                            try:
                                            yield
                                            finally:
                                            termios.tcsetattr(file_descriptor, termios.TCSADRAIN, old_settings)


                                            def get_character(file=sys.stdin):
                                            """
                                            Read a single character from the given input stream (defaults to sys.stdin).
                                            """
                                            file_descriptor = file.fileno()
                                            with _tty_reset(file_descriptor):
                                            tty.setcbreak(file_descriptor)
                                            return os.read(file_descriptor, _MAX_CHARACTER_BYTE_LENGTH)





                                            share|improve this answer




























                                              2














                                              A comment in one of the other answers mentioned cbreak mode, which is important for Unix implementations because you generally don't want ^C (KeyboardError) to be consumed by getchar (as it will when you set the terminal to raw mode, as done by most other answers).



                                              Another important detail is that if you're looking to read one character and not one byte, you should read 4 bytes from the input stream, as that's the maximum number of bytes a single character will consist of in UTF-8 (Python 3+). Reading only a single byte will produce unexpected results for multi-byte characters such as keypad arrows.



                                              Here's my changed implementation for Unix:



                                              import contextlib
                                              import os
                                              import sys
                                              import termios
                                              import tty


                                              _MAX_CHARACTER_BYTE_LENGTH = 4


                                              @contextlib.contextmanager
                                              def _tty_reset(file_descriptor):
                                              """
                                              A context manager that saves the tty flags of a file descriptor upon
                                              entering and restores them upon exiting.
                                              """
                                              old_settings = termios.tcgetattr(file_descriptor)
                                              try:
                                              yield
                                              finally:
                                              termios.tcsetattr(file_descriptor, termios.TCSADRAIN, old_settings)


                                              def get_character(file=sys.stdin):
                                              """
                                              Read a single character from the given input stream (defaults to sys.stdin).
                                              """
                                              file_descriptor = file.fileno()
                                              with _tty_reset(file_descriptor):
                                              tty.setcbreak(file_descriptor)
                                              return os.read(file_descriptor, _MAX_CHARACTER_BYTE_LENGTH)





                                              share|improve this answer


























                                                2












                                                2








                                                2







                                                A comment in one of the other answers mentioned cbreak mode, which is important for Unix implementations because you generally don't want ^C (KeyboardError) to be consumed by getchar (as it will when you set the terminal to raw mode, as done by most other answers).



                                                Another important detail is that if you're looking to read one character and not one byte, you should read 4 bytes from the input stream, as that's the maximum number of bytes a single character will consist of in UTF-8 (Python 3+). Reading only a single byte will produce unexpected results for multi-byte characters such as keypad arrows.



                                                Here's my changed implementation for Unix:



                                                import contextlib
                                                import os
                                                import sys
                                                import termios
                                                import tty


                                                _MAX_CHARACTER_BYTE_LENGTH = 4


                                                @contextlib.contextmanager
                                                def _tty_reset(file_descriptor):
                                                """
                                                A context manager that saves the tty flags of a file descriptor upon
                                                entering and restores them upon exiting.
                                                """
                                                old_settings = termios.tcgetattr(file_descriptor)
                                                try:
                                                yield
                                                finally:
                                                termios.tcsetattr(file_descriptor, termios.TCSADRAIN, old_settings)


                                                def get_character(file=sys.stdin):
                                                """
                                                Read a single character from the given input stream (defaults to sys.stdin).
                                                """
                                                file_descriptor = file.fileno()
                                                with _tty_reset(file_descriptor):
                                                tty.setcbreak(file_descriptor)
                                                return os.read(file_descriptor, _MAX_CHARACTER_BYTE_LENGTH)





                                                share|improve this answer













                                                A comment in one of the other answers mentioned cbreak mode, which is important for Unix implementations because you generally don't want ^C (KeyboardError) to be consumed by getchar (as it will when you set the terminal to raw mode, as done by most other answers).



                                                Another important detail is that if you're looking to read one character and not one byte, you should read 4 bytes from the input stream, as that's the maximum number of bytes a single character will consist of in UTF-8 (Python 3+). Reading only a single byte will produce unexpected results for multi-byte characters such as keypad arrows.



                                                Here's my changed implementation for Unix:



                                                import contextlib
                                                import os
                                                import sys
                                                import termios
                                                import tty


                                                _MAX_CHARACTER_BYTE_LENGTH = 4


                                                @contextlib.contextmanager
                                                def _tty_reset(file_descriptor):
                                                """
                                                A context manager that saves the tty flags of a file descriptor upon
                                                entering and restores them upon exiting.
                                                """
                                                old_settings = termios.tcgetattr(file_descriptor)
                                                try:
                                                yield
                                                finally:
                                                termios.tcsetattr(file_descriptor, termios.TCSADRAIN, old_settings)


                                                def get_character(file=sys.stdin):
                                                """
                                                Read a single character from the given input stream (defaults to sys.stdin).
                                                """
                                                file_descriptor = file.fileno()
                                                with _tty_reset(file_descriptor):
                                                tty.setcbreak(file_descriptor)
                                                return os.read(file_descriptor, _MAX_CHARACTER_BYTE_LENGTH)






                                                share|improve this answer












                                                share|improve this answer



                                                share|improve this answer










                                                answered Jul 23 '17 at 15:17









                                                NoahNoah

                                                759415




                                                759415























                                                    1














                                                    The curses package in python can be used to enter "raw" mode for character input from the terminal with just a few statements. Curses' main use is to take over the screen for output, which may not be what you want. This code snippet uses print() statements instead, which are usable, but you must be aware of how curses changes line endings attached to output.



                                                    #!/usr/bin/python3
                                                    # Demo of single char terminal input in raw mode with the curses package.
                                                    import sys, curses

                                                    def run_one_char(dummy):
                                                    'Run until a carriage return is entered'
                                                    char = ' '
                                                    print('Welcome to curses', flush=True)
                                                    while ord(char) != 13:
                                                    char = one_char()

                                                    def one_char():
                                                    'Read one character from the keyboard'
                                                    print('r? ', flush= True, end = '')

                                                    ## A blocking single char read in raw mode.
                                                    char = sys.stdin.read(1)
                                                    print('You entered %sr' % char)
                                                    return char

                                                    ## Must init curses before calling any functions
                                                    curses.initscr()
                                                    ## To make sure the terminal returns to its initial settings,
                                                    ## and to set raw mode and guarantee cleanup on exit.
                                                    curses.wrapper(run_one_char)
                                                    print('Curses be gone!')





                                                    share|improve this answer




























                                                      1














                                                      The curses package in python can be used to enter "raw" mode for character input from the terminal with just a few statements. Curses' main use is to take over the screen for output, which may not be what you want. This code snippet uses print() statements instead, which are usable, but you must be aware of how curses changes line endings attached to output.



                                                      #!/usr/bin/python3
                                                      # Demo of single char terminal input in raw mode with the curses package.
                                                      import sys, curses

                                                      def run_one_char(dummy):
                                                      'Run until a carriage return is entered'
                                                      char = ' '
                                                      print('Welcome to curses', flush=True)
                                                      while ord(char) != 13:
                                                      char = one_char()

                                                      def one_char():
                                                      'Read one character from the keyboard'
                                                      print('r? ', flush= True, end = '')

                                                      ## A blocking single char read in raw mode.
                                                      char = sys.stdin.read(1)
                                                      print('You entered %sr' % char)
                                                      return char

                                                      ## Must init curses before calling any functions
                                                      curses.initscr()
                                                      ## To make sure the terminal returns to its initial settings,
                                                      ## and to set raw mode and guarantee cleanup on exit.
                                                      curses.wrapper(run_one_char)
                                                      print('Curses be gone!')





                                                      share|improve this answer


























                                                        1












                                                        1








                                                        1







                                                        The curses package in python can be used to enter "raw" mode for character input from the terminal with just a few statements. Curses' main use is to take over the screen for output, which may not be what you want. This code snippet uses print() statements instead, which are usable, but you must be aware of how curses changes line endings attached to output.



                                                        #!/usr/bin/python3
                                                        # Demo of single char terminal input in raw mode with the curses package.
                                                        import sys, curses

                                                        def run_one_char(dummy):
                                                        'Run until a carriage return is entered'
                                                        char = ' '
                                                        print('Welcome to curses', flush=True)
                                                        while ord(char) != 13:
                                                        char = one_char()

                                                        def one_char():
                                                        'Read one character from the keyboard'
                                                        print('r? ', flush= True, end = '')

                                                        ## A blocking single char read in raw mode.
                                                        char = sys.stdin.read(1)
                                                        print('You entered %sr' % char)
                                                        return char

                                                        ## Must init curses before calling any functions
                                                        curses.initscr()
                                                        ## To make sure the terminal returns to its initial settings,
                                                        ## and to set raw mode and guarantee cleanup on exit.
                                                        curses.wrapper(run_one_char)
                                                        print('Curses be gone!')





                                                        share|improve this answer













                                                        The curses package in python can be used to enter "raw" mode for character input from the terminal with just a few statements. Curses' main use is to take over the screen for output, which may not be what you want. This code snippet uses print() statements instead, which are usable, but you must be aware of how curses changes line endings attached to output.



                                                        #!/usr/bin/python3
                                                        # Demo of single char terminal input in raw mode with the curses package.
                                                        import sys, curses

                                                        def run_one_char(dummy):
                                                        'Run until a carriage return is entered'
                                                        char = ' '
                                                        print('Welcome to curses', flush=True)
                                                        while ord(char) != 13:
                                                        char = one_char()

                                                        def one_char():
                                                        'Read one character from the keyboard'
                                                        print('r? ', flush= True, end = '')

                                                        ## A blocking single char read in raw mode.
                                                        char = sys.stdin.read(1)
                                                        print('You entered %sr' % char)
                                                        return char

                                                        ## Must init curses before calling any functions
                                                        curses.initscr()
                                                        ## To make sure the terminal returns to its initial settings,
                                                        ## and to set raw mode and guarantee cleanup on exit.
                                                        curses.wrapper(run_one_char)
                                                        print('Curses be gone!')






                                                        share|improve this answer












                                                        share|improve this answer



                                                        share|improve this answer










                                                        answered Dec 29 '14 at 17:38









                                                        John MarkJohn Mark

                                                        1417




                                                        1417























                                                            1














                                                            The ActiveState's recipe seems to contain a little bug for "posix" systems that prevents Ctrl-C from interrupting (I'm using Mac). If I put the following code in my script:



                                                            while(True):
                                                            print(getch())


                                                            I will never be able to terminate the script with Ctrl-C, and I have to kill my terminal to escape.



                                                            I believe the following line is the cause, and it's also too brutal:



                                                            tty.setraw(sys.stdin.fileno())


                                                            Asides from that, package tty is not really needed, termios is enough to handle it.



                                                            Below is the improved code that works for me (Ctrl-C will interrupt), with the extra getche function that echo the char as you type:



                                                            if sys.platform == 'win32':
                                                            import msvcrt
                                                            getch = msvcrt.getch
                                                            getche = msvcrt.getche
                                                            else:
                                                            import sys
                                                            import termios
                                                            def __gen_ch_getter(echo):
                                                            def __fun():
                                                            fd = sys.stdin.fileno()
                                                            oldattr = termios.tcgetattr(fd)
                                                            newattr = oldattr[:]
                                                            try:
                                                            if echo:
                                                            # disable ctrl character printing, otherwise, backspace will be printed as "^?"
                                                            lflag = ~(termios.ICANON | termios.ECHOCTL)
                                                            else:
                                                            lflag = ~(termios.ICANON | termios.ECHO)
                                                            newattr[3] &= lflag
                                                            termios.tcsetattr(fd, termios.TCSADRAIN, newattr)
                                                            ch = sys.stdin.read(1)
                                                            if echo and ord(ch) == 127: # backspace
                                                            # emulate backspace erasing
                                                            # https://stackoverflow.com/a/47962872/404271
                                                            sys.stdout.write('b b')
                                                            finally:
                                                            termios.tcsetattr(fd, termios.TCSADRAIN, oldattr)
                                                            return ch
                                                            return __fun
                                                            getch = __gen_ch_getter(False)
                                                            getche = __gen_ch_getter(True)


                                                            References:




                                                            • https://pypi.python.org/pypi/getch






                                                            share|improve this answer






























                                                              1














                                                              The ActiveState's recipe seems to contain a little bug for "posix" systems that prevents Ctrl-C from interrupting (I'm using Mac). If I put the following code in my script:



                                                              while(True):
                                                              print(getch())


                                                              I will never be able to terminate the script with Ctrl-C, and I have to kill my terminal to escape.



                                                              I believe the following line is the cause, and it's also too brutal:



                                                              tty.setraw(sys.stdin.fileno())


                                                              Asides from that, package tty is not really needed, termios is enough to handle it.



                                                              Below is the improved code that works for me (Ctrl-C will interrupt), with the extra getche function that echo the char as you type:



                                                              if sys.platform == 'win32':
                                                              import msvcrt
                                                              getch = msvcrt.getch
                                                              getche = msvcrt.getche
                                                              else:
                                                              import sys
                                                              import termios
                                                              def __gen_ch_getter(echo):
                                                              def __fun():
                                                              fd = sys.stdin.fileno()
                                                              oldattr = termios.tcgetattr(fd)
                                                              newattr = oldattr[:]
                                                              try:
                                                              if echo:
                                                              # disable ctrl character printing, otherwise, backspace will be printed as "^?"
                                                              lflag = ~(termios.ICANON | termios.ECHOCTL)
                                                              else:
                                                              lflag = ~(termios.ICANON | termios.ECHO)
                                                              newattr[3] &= lflag
                                                              termios.tcsetattr(fd, termios.TCSADRAIN, newattr)
                                                              ch = sys.stdin.read(1)
                                                              if echo and ord(ch) == 127: # backspace
                                                              # emulate backspace erasing
                                                              # https://stackoverflow.com/a/47962872/404271
                                                              sys.stdout.write('b b')
                                                              finally:
                                                              termios.tcsetattr(fd, termios.TCSADRAIN, oldattr)
                                                              return ch
                                                              return __fun
                                                              getch = __gen_ch_getter(False)
                                                              getche = __gen_ch_getter(True)


                                                              References:




                                                              • https://pypi.python.org/pypi/getch






                                                              share|improve this answer




























                                                                1












                                                                1








                                                                1







                                                                The ActiveState's recipe seems to contain a little bug for "posix" systems that prevents Ctrl-C from interrupting (I'm using Mac). If I put the following code in my script:



                                                                while(True):
                                                                print(getch())


                                                                I will never be able to terminate the script with Ctrl-C, and I have to kill my terminal to escape.



                                                                I believe the following line is the cause, and it's also too brutal:



                                                                tty.setraw(sys.stdin.fileno())


                                                                Asides from that, package tty is not really needed, termios is enough to handle it.



                                                                Below is the improved code that works for me (Ctrl-C will interrupt), with the extra getche function that echo the char as you type:



                                                                if sys.platform == 'win32':
                                                                import msvcrt
                                                                getch = msvcrt.getch
                                                                getche = msvcrt.getche
                                                                else:
                                                                import sys
                                                                import termios
                                                                def __gen_ch_getter(echo):
                                                                def __fun():
                                                                fd = sys.stdin.fileno()
                                                                oldattr = termios.tcgetattr(fd)
                                                                newattr = oldattr[:]
                                                                try:
                                                                if echo:
                                                                # disable ctrl character printing, otherwise, backspace will be printed as "^?"
                                                                lflag = ~(termios.ICANON | termios.ECHOCTL)
                                                                else:
                                                                lflag = ~(termios.ICANON | termios.ECHO)
                                                                newattr[3] &= lflag
                                                                termios.tcsetattr(fd, termios.TCSADRAIN, newattr)
                                                                ch = sys.stdin.read(1)
                                                                if echo and ord(ch) == 127: # backspace
                                                                # emulate backspace erasing
                                                                # https://stackoverflow.com/a/47962872/404271
                                                                sys.stdout.write('b b')
                                                                finally:
                                                                termios.tcsetattr(fd, termios.TCSADRAIN, oldattr)
                                                                return ch
                                                                return __fun
                                                                getch = __gen_ch_getter(False)
                                                                getche = __gen_ch_getter(True)


                                                                References:




                                                                • https://pypi.python.org/pypi/getch






                                                                share|improve this answer















                                                                The ActiveState's recipe seems to contain a little bug for "posix" systems that prevents Ctrl-C from interrupting (I'm using Mac). If I put the following code in my script:



                                                                while(True):
                                                                print(getch())


                                                                I will never be able to terminate the script with Ctrl-C, and I have to kill my terminal to escape.



                                                                I believe the following line is the cause, and it's also too brutal:



                                                                tty.setraw(sys.stdin.fileno())


                                                                Asides from that, package tty is not really needed, termios is enough to handle it.



                                                                Below is the improved code that works for me (Ctrl-C will interrupt), with the extra getche function that echo the char as you type:



                                                                if sys.platform == 'win32':
                                                                import msvcrt
                                                                getch = msvcrt.getch
                                                                getche = msvcrt.getche
                                                                else:
                                                                import sys
                                                                import termios
                                                                def __gen_ch_getter(echo):
                                                                def __fun():
                                                                fd = sys.stdin.fileno()
                                                                oldattr = termios.tcgetattr(fd)
                                                                newattr = oldattr[:]
                                                                try:
                                                                if echo:
                                                                # disable ctrl character printing, otherwise, backspace will be printed as "^?"
                                                                lflag = ~(termios.ICANON | termios.ECHOCTL)
                                                                else:
                                                                lflag = ~(termios.ICANON | termios.ECHO)
                                                                newattr[3] &= lflag
                                                                termios.tcsetattr(fd, termios.TCSADRAIN, newattr)
                                                                ch = sys.stdin.read(1)
                                                                if echo and ord(ch) == 127: # backspace
                                                                # emulate backspace erasing
                                                                # https://stackoverflow.com/a/47962872/404271
                                                                sys.stdout.write('b b')
                                                                finally:
                                                                termios.tcsetattr(fd, termios.TCSADRAIN, oldattr)
                                                                return ch
                                                                return __fun
                                                                getch = __gen_ch_getter(False)
                                                                getche = __gen_ch_getter(True)


                                                                References:




                                                                • https://pypi.python.org/pypi/getch







                                                                share|improve this answer














                                                                share|improve this answer



                                                                share|improve this answer








                                                                edited Jan 7 '18 at 12:07

























                                                                answered Jan 7 '18 at 10:09









                                                                ibicibic

                                                                312510




                                                                312510























                                                                    0














                                                                    The build-in raw_input should help.



                                                                    for i in range(3):
                                                                    print ("So much work to do!")
                                                                    k = raw_input("Press any key to continue...")
                                                                    print ("Ok, back to work.")





                                                                    share|improve this answer



















                                                                    • 6





                                                                      raw_input is waiting for enter key

                                                                      – vac
                                                                      Dec 16 '15 at 22:03


















                                                                    0














                                                                    The build-in raw_input should help.



                                                                    for i in range(3):
                                                                    print ("So much work to do!")
                                                                    k = raw_input("Press any key to continue...")
                                                                    print ("Ok, back to work.")





                                                                    share|improve this answer



















                                                                    • 6





                                                                      raw_input is waiting for enter key

                                                                      – vac
                                                                      Dec 16 '15 at 22:03
















                                                                    0












                                                                    0








                                                                    0







                                                                    The build-in raw_input should help.



                                                                    for i in range(3):
                                                                    print ("So much work to do!")
                                                                    k = raw_input("Press any key to continue...")
                                                                    print ("Ok, back to work.")





                                                                    share|improve this answer













                                                                    The build-in raw_input should help.



                                                                    for i in range(3):
                                                                    print ("So much work to do!")
                                                                    k = raw_input("Press any key to continue...")
                                                                    print ("Ok, back to work.")






                                                                    share|improve this answer












                                                                    share|improve this answer



                                                                    share|improve this answer










                                                                    answered Dec 15 '15 at 20:51









                                                                    MabookaMabooka

                                                                    171




                                                                    171








                                                                    • 6





                                                                      raw_input is waiting for enter key

                                                                      – vac
                                                                      Dec 16 '15 at 22:03
















                                                                    • 6





                                                                      raw_input is waiting for enter key

                                                                      – vac
                                                                      Dec 16 '15 at 22:03










                                                                    6




                                                                    6





                                                                    raw_input is waiting for enter key

                                                                    – vac
                                                                    Dec 16 '15 at 22:03







                                                                    raw_input is waiting for enter key

                                                                    – vac
                                                                    Dec 16 '15 at 22:03













                                                                    0














                                                                    My solution for python3, not depending on any pip packages.



                                                                    # precondition: import tty, sys
                                                                    def query_yes_no(question, default=True):
                                                                    """
                                                                    Ask the user a yes/no question.
                                                                    Returns immediately upon reading one-char answer.
                                                                    Accepts multiple language characters for yes/no.
                                                                    """
                                                                    if not sys.stdin.isatty():
                                                                    return default
                                                                    if default:
                                                                    prompt = "[Y/n]?"
                                                                    other_answers = "n"
                                                                    else:
                                                                    prompt = "[y/N]?"
                                                                    other_answers = "yjosiá"

                                                                    print(question,prompt,flush= True,end=" ")
                                                                    oldttysettings = tty.tcgetattr(sys.stdin.fileno())
                                                                    try:
                                                                    tty.setraw(sys.stdin.fileno())
                                                                    return not sys.stdin.read(1).lower() in other_answers
                                                                    except:
                                                                    return default
                                                                    finally:
                                                                    tty.tcsetattr(sys.stdin.fileno(), tty.TCSADRAIN , oldttysettings)
                                                                    sys.stdout.write("rn")
                                                                    tty.tcdrain(sys.stdin.fileno())





                                                                    share|improve this answer




























                                                                      0














                                                                      My solution for python3, not depending on any pip packages.



                                                                      # precondition: import tty, sys
                                                                      def query_yes_no(question, default=True):
                                                                      """
                                                                      Ask the user a yes/no question.
                                                                      Returns immediately upon reading one-char answer.
                                                                      Accepts multiple language characters for yes/no.
                                                                      """
                                                                      if not sys.stdin.isatty():
                                                                      return default
                                                                      if default:
                                                                      prompt = "[Y/n]?"
                                                                      other_answers = "n"
                                                                      else:
                                                                      prompt = "[y/N]?"
                                                                      other_answers = "yjosiá"

                                                                      print(question,prompt,flush= True,end=" ")
                                                                      oldttysettings = tty.tcgetattr(sys.stdin.fileno())
                                                                      try:
                                                                      tty.setraw(sys.stdin.fileno())
                                                                      return not sys.stdin.read(1).lower() in other_answers
                                                                      except:
                                                                      return default
                                                                      finally:
                                                                      tty.tcsetattr(sys.stdin.fileno(), tty.TCSADRAIN , oldttysettings)
                                                                      sys.stdout.write("rn")
                                                                      tty.tcdrain(sys.stdin.fileno())





                                                                      share|improve this answer


























                                                                        0












                                                                        0








                                                                        0







                                                                        My solution for python3, not depending on any pip packages.



                                                                        # precondition: import tty, sys
                                                                        def query_yes_no(question, default=True):
                                                                        """
                                                                        Ask the user a yes/no question.
                                                                        Returns immediately upon reading one-char answer.
                                                                        Accepts multiple language characters for yes/no.
                                                                        """
                                                                        if not sys.stdin.isatty():
                                                                        return default
                                                                        if default:
                                                                        prompt = "[Y/n]?"
                                                                        other_answers = "n"
                                                                        else:
                                                                        prompt = "[y/N]?"
                                                                        other_answers = "yjosiá"

                                                                        print(question,prompt,flush= True,end=" ")
                                                                        oldttysettings = tty.tcgetattr(sys.stdin.fileno())
                                                                        try:
                                                                        tty.setraw(sys.stdin.fileno())
                                                                        return not sys.stdin.read(1).lower() in other_answers
                                                                        except:
                                                                        return default
                                                                        finally:
                                                                        tty.tcsetattr(sys.stdin.fileno(), tty.TCSADRAIN , oldttysettings)
                                                                        sys.stdout.write("rn")
                                                                        tty.tcdrain(sys.stdin.fileno())





                                                                        share|improve this answer













                                                                        My solution for python3, not depending on any pip packages.



                                                                        # precondition: import tty, sys
                                                                        def query_yes_no(question, default=True):
                                                                        """
                                                                        Ask the user a yes/no question.
                                                                        Returns immediately upon reading one-char answer.
                                                                        Accepts multiple language characters for yes/no.
                                                                        """
                                                                        if not sys.stdin.isatty():
                                                                        return default
                                                                        if default:
                                                                        prompt = "[Y/n]?"
                                                                        other_answers = "n"
                                                                        else:
                                                                        prompt = "[y/N]?"
                                                                        other_answers = "yjosiá"

                                                                        print(question,prompt,flush= True,end=" ")
                                                                        oldttysettings = tty.tcgetattr(sys.stdin.fileno())
                                                                        try:
                                                                        tty.setraw(sys.stdin.fileno())
                                                                        return not sys.stdin.read(1).lower() in other_answers
                                                                        except:
                                                                        return default
                                                                        finally:
                                                                        tty.tcsetattr(sys.stdin.fileno(), tty.TCSADRAIN , oldttysettings)
                                                                        sys.stdout.write("rn")
                                                                        tty.tcdrain(sys.stdin.fileno())






                                                                        share|improve this answer












                                                                        share|improve this answer



                                                                        share|improve this answer










                                                                        answered Jan 28 '16 at 1:24









                                                                        xroxro

                                                                        1




                                                                        1























                                                                            0














                                                                            I believe that this is one the most elegant solution.



                                                                            import os

                                                                            if os.name == 'nt':
                                                                            import msvcrt
                                                                            def getch():
                                                                            return msvcrt.getch().decode()
                                                                            else:
                                                                            import sys, tty, termios
                                                                            fd = sys.stdin.fileno()
                                                                            old_settings = termios.tcgetattr(fd)
                                                                            def getch():
                                                                            try:
                                                                            tty.setraw(sys.stdin.fileno())
                                                                            ch = sys.stdin.read(1)
                                                                            finally:
                                                                            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
                                                                            return ch


                                                                            and then use it in the code:



                                                                            if getch() == chr(ESC_ASCII_VALUE):
                                                                            print("ESC!")





                                                                            share|improve this answer




























                                                                              0














                                                                              I believe that this is one the most elegant solution.



                                                                              import os

                                                                              if os.name == 'nt':
                                                                              import msvcrt
                                                                              def getch():
                                                                              return msvcrt.getch().decode()
                                                                              else:
                                                                              import sys, tty, termios
                                                                              fd = sys.stdin.fileno()
                                                                              old_settings = termios.tcgetattr(fd)
                                                                              def getch():
                                                                              try:
                                                                              tty.setraw(sys.stdin.fileno())
                                                                              ch = sys.stdin.read(1)
                                                                              finally:
                                                                              termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
                                                                              return ch


                                                                              and then use it in the code:



                                                                              if getch() == chr(ESC_ASCII_VALUE):
                                                                              print("ESC!")





                                                                              share|improve this answer


























                                                                                0












                                                                                0








                                                                                0







                                                                                I believe that this is one the most elegant solution.



                                                                                import os

                                                                                if os.name == 'nt':
                                                                                import msvcrt
                                                                                def getch():
                                                                                return msvcrt.getch().decode()
                                                                                else:
                                                                                import sys, tty, termios
                                                                                fd = sys.stdin.fileno()
                                                                                old_settings = termios.tcgetattr(fd)
                                                                                def getch():
                                                                                try:
                                                                                tty.setraw(sys.stdin.fileno())
                                                                                ch = sys.stdin.read(1)
                                                                                finally:
                                                                                termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
                                                                                return ch


                                                                                and then use it in the code:



                                                                                if getch() == chr(ESC_ASCII_VALUE):
                                                                                print("ESC!")





                                                                                share|improve this answer













                                                                                I believe that this is one the most elegant solution.



                                                                                import os

                                                                                if os.name == 'nt':
                                                                                import msvcrt
                                                                                def getch():
                                                                                return msvcrt.getch().decode()
                                                                                else:
                                                                                import sys, tty, termios
                                                                                fd = sys.stdin.fileno()
                                                                                old_settings = termios.tcgetattr(fd)
                                                                                def getch():
                                                                                try:
                                                                                tty.setraw(sys.stdin.fileno())
                                                                                ch = sys.stdin.read(1)
                                                                                finally:
                                                                                termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
                                                                                return ch


                                                                                and then use it in the code:



                                                                                if getch() == chr(ESC_ASCII_VALUE):
                                                                                print("ESC!")






                                                                                share|improve this answer












                                                                                share|improve this answer



                                                                                share|improve this answer










                                                                                answered Nov 29 '17 at 9:14









                                                                                theAlsetheAlse

                                                                                2,89054490




                                                                                2,89054490























                                                                                    0














                                                                                    If I'm doing something complicated I'll use curses to read keys. But a lot of times I just want a simple Python 3 script that uses the standard library and can read arrow keys, so I do this:



                                                                                    import sys, termios, tty

                                                                                    key_Enter = 13
                                                                                    key_Esc = 27
                                                                                    key_Up = '33[A'
                                                                                    key_Dn = '33[B'
                                                                                    key_Rt = '33[C'
                                                                                    key_Lt = '33[D'

                                                                                    fdInput = sys.stdin.fileno()
                                                                                    termAttr = termios.tcgetattr(0)

                                                                                    def getch():
                                                                                    tty.setraw(fdInput)
                                                                                    ch = sys.stdin.buffer.raw.read(4).decode(sys.stdin.encoding)
                                                                                    if len(ch) == 1:
                                                                                    if ord(ch) < 32 or ord(ch) > 126:
                                                                                    ch = ord(ch)
                                                                                    elif ord(ch[0]) == 27:
                                                                                    ch = '33' + ch[1:]
                                                                                    termios.tcsetattr(fdInput, termios.TCSADRAIN, termAttr)
                                                                                    return ch





                                                                                    share|improve this answer






























                                                                                      0














                                                                                      If I'm doing something complicated I'll use curses to read keys. But a lot of times I just want a simple Python 3 script that uses the standard library and can read arrow keys, so I do this:



                                                                                      import sys, termios, tty

                                                                                      key_Enter = 13
                                                                                      key_Esc = 27
                                                                                      key_Up = '33[A'
                                                                                      key_Dn = '33[B'
                                                                                      key_Rt = '33[C'
                                                                                      key_Lt = '33[D'

                                                                                      fdInput = sys.stdin.fileno()
                                                                                      termAttr = termios.tcgetattr(0)

                                                                                      def getch():
                                                                                      tty.setraw(fdInput)
                                                                                      ch = sys.stdin.buffer.raw.read(4).decode(sys.stdin.encoding)
                                                                                      if len(ch) == 1:
                                                                                      if ord(ch) < 32 or ord(ch) > 126:
                                                                                      ch = ord(ch)
                                                                                      elif ord(ch[0]) == 27:
                                                                                      ch = '33' + ch[1:]
                                                                                      termios.tcsetattr(fdInput, termios.TCSADRAIN, termAttr)
                                                                                      return ch





                                                                                      share|improve this answer




























                                                                                        0












                                                                                        0








                                                                                        0







                                                                                        If I'm doing something complicated I'll use curses to read keys. But a lot of times I just want a simple Python 3 script that uses the standard library and can read arrow keys, so I do this:



                                                                                        import sys, termios, tty

                                                                                        key_Enter = 13
                                                                                        key_Esc = 27
                                                                                        key_Up = '33[A'
                                                                                        key_Dn = '33[B'
                                                                                        key_Rt = '33[C'
                                                                                        key_Lt = '33[D'

                                                                                        fdInput = sys.stdin.fileno()
                                                                                        termAttr = termios.tcgetattr(0)

                                                                                        def getch():
                                                                                        tty.setraw(fdInput)
                                                                                        ch = sys.stdin.buffer.raw.read(4).decode(sys.stdin.encoding)
                                                                                        if len(ch) == 1:
                                                                                        if ord(ch) < 32 or ord(ch) > 126:
                                                                                        ch = ord(ch)
                                                                                        elif ord(ch[0]) == 27:
                                                                                        ch = '33' + ch[1:]
                                                                                        termios.tcsetattr(fdInput, termios.TCSADRAIN, termAttr)
                                                                                        return ch





                                                                                        share|improve this answer















                                                                                        If I'm doing something complicated I'll use curses to read keys. But a lot of times I just want a simple Python 3 script that uses the standard library and can read arrow keys, so I do this:



                                                                                        import sys, termios, tty

                                                                                        key_Enter = 13
                                                                                        key_Esc = 27
                                                                                        key_Up = '33[A'
                                                                                        key_Dn = '33[B'
                                                                                        key_Rt = '33[C'
                                                                                        key_Lt = '33[D'

                                                                                        fdInput = sys.stdin.fileno()
                                                                                        termAttr = termios.tcgetattr(0)

                                                                                        def getch():
                                                                                        tty.setraw(fdInput)
                                                                                        ch = sys.stdin.buffer.raw.read(4).decode(sys.stdin.encoding)
                                                                                        if len(ch) == 1:
                                                                                        if ord(ch) < 32 or ord(ch) > 126:
                                                                                        ch = ord(ch)
                                                                                        elif ord(ch[0]) == 27:
                                                                                        ch = '33' + ch[1:]
                                                                                        termios.tcsetattr(fdInput, termios.TCSADRAIN, termAttr)
                                                                                        return ch






                                                                                        share|improve this answer














                                                                                        share|improve this answer



                                                                                        share|improve this answer








                                                                                        edited Sep 24 '18 at 5:20

























                                                                                        answered Sep 23 '18 at 0:07









                                                                                        qelqel

                                                                                        47944




                                                                                        47944

















                                                                                            protected by eyllanesc Jun 23 '18 at 22:25



                                                                                            Thank you for your interest in this question.
                                                                                            Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



                                                                                            Would you like to answer one of these unanswered questions instead?



                                                                                            K1cEZTsaBJL2d0qK19UZThuV96qO yxPoXwQRA5a MvtVyeofYckM THwR,hGsqZI0
                                                                                            iliK,DH8dfaByJ,x1Na9SlCJv9xmkrY 8 KtA2r,F6CCeR,7qmQWSTBT13NN,IkMfq

                                                                                            Popular posts from this blog

                                                                                            Monofisismo

                                                                                            Angular Downloading a file using contenturl with Basic Authentication

                                                                                            Olmecas