[python] Polling the keyboard (detect a keypress) in python

How can I poll the keyboard from a console python app? Specifically, I would like to do something akin to this in the midst of a lot of other I/O activities (socket selects, serial port access, etc.):

   while 1:
      # doing amazing pythonic embedded stuff
      # ...

      # periodically do a non-blocking check to see if
      # we are being told to do something else
      x = keyboard.read(1000, timeout = 0)

      if len(x):
          # ok, some key got pressed
          # do something

What is the correct pythonic way to do this on Windows? Also, portability to Linux wouldn't be bad, though it's not required.

This question is related to python console keyboard blocking nonblocking

The answer is


The standard approach is to use the select module.

However, this doesn't work on Windows. For that, you can use the msvcrt module's keyboard polling.

Often, this is done with multiple threads -- one per device being "watched" plus the background processes that might need to be interrupted by the device.


From the comments:

import msvcrt # built-in module

def kbfunc():
    return ord(msvcrt.getch()) if msvcrt.kbhit() else 0

Thanks for the help. I ended up writing a C DLL called PyKeyboardAccess.dll and accessing the crt conio functions, exporting this routine:

#include <conio.h>

int kb_inkey () {
   int rc;
   int key;

   key = _kbhit();

   if (key == 0) {
      rc = 0;
   } else {
      rc = _getch();
   }

   return rc;
}

And I access it in python using the ctypes module (built into python 2.5):

import ctypes
import time

#
# first, load the DLL
#


try:
    kblib = ctypes.CDLL("PyKeyboardAccess.dll")
except:
    raise ("Error Loading PyKeyboardAccess.dll")


#
# now, find our function
#

try:
    kbfunc = kblib.kb_inkey
except:
    raise ("Could not find the kb_inkey function in the dll!")


#
# Ok, now let's demo the capability
#

while 1:
    x = kbfunc()

    if x != 0:
        print "Got key: %d" % x
    else:
        time.sleep(.01)

I am using this for checking for key presses, can't get much simpler:

#!/usr/bin/python3
# -*- coding: UTF-8 -*-

import curses, time

def main(stdscr):
    """checking for keypress"""
    stdscr.nodelay(True)  # do not wait for input when calling getch
    return stdscr.getch()

while True:
    print("key:", curses.wrapper(main)) # prints: 'key: 97' for 'a' pressed
                                        # '-1' on no presses
    time.sleep(1)

While curses is not working on windows, there is a 'unicurses' version, supposedly working on Linux, Windows, Mac but I could not get this to work


Ok, since my attempt to post my solution in a comment failed, here's what I was trying to say. I could do exactly what I wanted from native Python (on Windows, not anywhere else though) with the following code:

import msvcrt 

def kbfunc(): 
   x = msvcrt.kbhit()
   if x: 
      ret = ord(msvcrt.getch()) 
   else: 
      ret = 0 
   return ret

I've come across a cross-platform implementation of kbhit at http://home.wlu.edu/~levys/software/kbhit.py (made edits to remove irrelevant code):

import os
if os.name == 'nt':
    import msvcrt
else:
    import sys, select

def kbhit():
    ''' Returns True if a keypress is waiting to be read in stdin, False otherwise.
    '''
    if os.name == 'nt':
        return msvcrt.kbhit()
    else:
        dr,dw,de = select.select([sys.stdin], [], [], 0)
        return dr != []

Make sure to read() the waiting character(s) -- the function will keep returning True until you do!


None of these answers worked well for me. This package, pynput, does exactly what I need.

https://pypi.python.org/pypi/pynput

from pynput.keyboard import Key, Listener

def on_press(key):
    print('{0} pressed'.format(
        key))

def on_release(key):
    print('{0} release'.format(
        key))
    if key == Key.esc:
        # Stop listener
        return False

# Collect events until released
with Listener(
        on_press=on_press,
        on_release=on_release) as listener:
    listener.join()

You might look at how pygame handles this to steal some ideas.


I've come across a cross-platform implementation of kbhit at http://home.wlu.edu/~levys/software/kbhit.py (made edits to remove irrelevant code):

import os
if os.name == 'nt':
    import msvcrt
else:
    import sys, select

def kbhit():
    ''' Returns True if a keypress is waiting to be read in stdin, False otherwise.
    '''
    if os.name == 'nt':
        return msvcrt.kbhit()
    else:
        dr,dw,de = select.select([sys.stdin], [], [], 0)
        return dr != []

Make sure to read() the waiting character(s) -- the function will keep returning True until you do!


Ok, since my attempt to post my solution in a comment failed, here's what I was trying to say. I could do exactly what I wanted from native Python (on Windows, not anywhere else though) with the following code:

import msvcrt 

def kbfunc(): 
   x = msvcrt.kbhit()
   if x: 
      ret = ord(msvcrt.getch()) 
   else: 
      ret = 0 
   return ret

From the comments:

import msvcrt # built-in module

def kbfunc():
    return ord(msvcrt.getch()) if msvcrt.kbhit() else 0

Thanks for the help. I ended up writing a C DLL called PyKeyboardAccess.dll and accessing the crt conio functions, exporting this routine:

#include <conio.h>

int kb_inkey () {
   int rc;
   int key;

   key = _kbhit();

   if (key == 0) {
      rc = 0;
   } else {
      rc = _getch();
   }

   return rc;
}

And I access it in python using the ctypes module (built into python 2.5):

import ctypes
import time

#
# first, load the DLL
#


try:
    kblib = ctypes.CDLL("PyKeyboardAccess.dll")
except:
    raise ("Error Loading PyKeyboardAccess.dll")


#
# now, find our function
#

try:
    kbfunc = kblib.kb_inkey
except:
    raise ("Could not find the kb_inkey function in the dll!")


#
# Ok, now let's demo the capability
#

while 1:
    x = kbfunc()

    if x != 0:
        print "Got key: %d" % x
    else:
        time.sleep(.01)

None of these answers worked well for me. This package, pynput, does exactly what I need.

https://pypi.python.org/pypi/pynput

from pynput.keyboard import Key, Listener

def on_press(key):
    print('{0} pressed'.format(
        key))

def on_release(key):
    print('{0} release'.format(
        key))
    if key == Key.esc:
        # Stop listener
        return False

# Collect events until released
with Listener(
        on_press=on_press,
        on_release=on_release) as listener:
    listener.join()

If you combine time.sleep, threading.Thread, and sys.stdin.read you can easily wait for a specified amount of time for input and then continue, also this should be cross-platform compatible.

t = threading.Thread(target=sys.stdin.read(1) args=(1,))
t.start()
time.sleep(5)
t.join()

You could also place this into a function like so

def timed_getch(self, bytes=1, timeout=1):
    t = threading.Thread(target=sys.stdin.read, args=(bytes,))
    t.start()
    time.sleep(timeout)
    t.join()
    del t

Although this will not return anything so instead you should use the multiprocessing pool module you can find that here: how to get the return value from a thread in python?


From the comments:

import msvcrt # built-in module

def kbfunc():
    return ord(msvcrt.getch()) if msvcrt.kbhit() else 0

Thanks for the help. I ended up writing a C DLL called PyKeyboardAccess.dll and accessing the crt conio functions, exporting this routine:

#include <conio.h>

int kb_inkey () {
   int rc;
   int key;

   key = _kbhit();

   if (key == 0) {
      rc = 0;
   } else {
      rc = _getch();
   }

   return rc;
}

And I access it in python using the ctypes module (built into python 2.5):

import ctypes
import time

#
# first, load the DLL
#


try:
    kblib = ctypes.CDLL("PyKeyboardAccess.dll")
except:
    raise ("Error Loading PyKeyboardAccess.dll")


#
# now, find our function
#

try:
    kbfunc = kblib.kb_inkey
except:
    raise ("Could not find the kb_inkey function in the dll!")


#
# Ok, now let's demo the capability
#

while 1:
    x = kbfunc()

    if x != 0:
        print "Got key: %d" % x
    else:
        time.sleep(.01)

A solution using the curses module. Printing a numeric value corresponding to each key pressed:

import curses

def main(stdscr):
    # do not wait for input when calling getch
    stdscr.nodelay(1)
    while True:
        # get keyboard input, returns -1 if none available
        c = stdscr.getch()
        if c != -1:
            # print numeric value
            stdscr.addstr(str(c) + ' ')
            stdscr.refresh()
            # return curser to start position
            stdscr.move(0, 0)

if __name__ == '__main__':
    curses.wrapper(main)

You might look at how pygame handles this to steal some ideas.


Ok, since my attempt to post my solution in a comment failed, here's what I was trying to say. I could do exactly what I wanted from native Python (on Windows, not anywhere else though) with the following code:

import msvcrt 

def kbfunc(): 
   x = msvcrt.kbhit()
   if x: 
      ret = ord(msvcrt.getch()) 
   else: 
      ret = 0 
   return ret

A solution using the curses module. Printing a numeric value corresponding to each key pressed:

import curses

def main(stdscr):
    # do not wait for input when calling getch
    stdscr.nodelay(1)
    while True:
        # get keyboard input, returns -1 if none available
        c = stdscr.getch()
        if c != -1:
            # print numeric value
            stdscr.addstr(str(c) + ' ')
            stdscr.refresh()
            # return curser to start position
            stdscr.move(0, 0)

if __name__ == '__main__':
    curses.wrapper(main)


import sys
import select

def heardEnter():
    i,o,e = select.select([sys.stdin],[],[],0.0001)
    for s in i:
        if s == sys.stdin:
            input = sys.stdin.readline()
            return True
    return False

If you combine time.sleep, threading.Thread, and sys.stdin.read you can easily wait for a specified amount of time for input and then continue, also this should be cross-platform compatible.

t = threading.Thread(target=sys.stdin.read(1) args=(1,))
t.start()
time.sleep(5)
t.join()

You could also place this into a function like so

def timed_getch(self, bytes=1, timeout=1):
    t = threading.Thread(target=sys.stdin.read, args=(bytes,))
    t.start()
    time.sleep(timeout)
    t.join()
    del t

Although this will not return anything so instead you should use the multiprocessing pool module you can find that here: how to get the return value from a thread in python?


Ok, since my attempt to post my solution in a comment failed, here's what I was trying to say. I could do exactly what I wanted from native Python (on Windows, not anywhere else though) with the following code:

import msvcrt 

def kbfunc(): 
   x = msvcrt.kbhit()
   if x: 
      ret = ord(msvcrt.getch()) 
   else: 
      ret = 0 
   return ret


import sys
import select

def heardEnter():
    i,o,e = select.select([sys.stdin],[],[],0.0001)
    for s in i:
        if s == sys.stdin:
            input = sys.stdin.readline()
            return True
    return False

You might look at how pygame handles this to steal some ideas.


I am using this for checking for key presses, can't get much simpler:

#!/usr/bin/python3
# -*- coding: UTF-8 -*-

import curses, time

def main(stdscr):
    """checking for keypress"""
    stdscr.nodelay(True)  # do not wait for input when calling getch
    return stdscr.getch()

while True:
    print("key:", curses.wrapper(main)) # prints: 'key: 97' for 'a' pressed
                                        # '-1' on no presses
    time.sleep(1)

While curses is not working on windows, there is a 'unicurses' version, supposedly working on Linux, Windows, Mac but I could not get this to work


You might look at how pygame handles this to steal some ideas.


Examples related to python

programming a servo thru a barometer Is there a way to view two blocks of code from the same file simultaneously in Sublime Text? python variable NameError Why my regexp for hyphenated words doesn't work? Comparing a variable with a string python not working when redirecting from bash script is it possible to add colors to python output? Get Public URL for File - Google Cloud Storage - App Engine (Python) Real time face detection OpenCV, Python xlrd.biffh.XLRDError: Excel xlsx file; not supported Could not load dynamic library 'cudart64_101.dll' on tensorflow CPU-only installation

Examples related to console

Error in MySQL when setting default value for DATE or DATETIME Where can I read the Console output in Visual Studio 2015 Chrome - ERR_CACHE_MISS Swift: print() vs println() vs NSLog() Datatables: Cannot read property 'mData' of undefined How do I write to the console from a Laravel Controller? Cannot read property 'push' of undefined when combining arrays Very simple log4j2 XML configuration file using Console and File appender Console.log not working at all Chrome: console.log, console.debug are not working

Examples related to keyboard

How do I check if a Key is pressed on C++ Move a view up only when the keyboard covers an input field Move textfield when keyboard appears swift Xcode iOS 8 Keyboard types not supported Xcode 6: Keyboard does not show up in simulator How to dismiss keyboard iOS programmatically when pressing return Detect key input in Python Getting Keyboard Input Press Keyboard keys using a batch file Keylistener in Javascript

Examples related to blocking

How to create a sleep/delay in nodejs that is Blocking? Is there a way to get all IP addresses of youtube to block it with Windows Firewall? asynchronous vs non-blocking How to prevent downloading images and video files from my website? Polling the keyboard (detect a keypress) in python

Examples related to nonblocking

What does Python's socket.recv() return for non-blocking sockets if no data is received until a timeout occurs? C non-blocking keyboard input A non-blocking read on a subprocess.PIPE in Python Polling the keyboard (detect a keypress) in python