Non-blocking console input?
For Windows, console only, use the msvcrt
module:
import msvcrtnum = 0done = Falsewhile not done: print(num) num += 1 if msvcrt.kbhit(): print "you pressed",msvcrt.getch(),"so now i will quit" done = True
For Linux, this article describes the following solution, it requires the termios
module:
import sysimport selectimport ttyimport termiosdef isData(): return select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], [])old_settings = termios.tcgetattr(sys.stdin)try: tty.setcbreak(sys.stdin.fileno()) i = 0 while 1: print(i) i += 1 if isData(): c = sys.stdin.read(1) if c == '\x1b': # x1b is ESC breakfinally: termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
For cross platform, or in case you want a GUI as well, you can use Pygame:
import pygamefrom pygame.locals import *def display(str): text = font.render(str, True, (255, 255, 255), (159, 182, 205)) textRect = text.get_rect() textRect.centerx = screen.get_rect().centerx textRect.centery = screen.get_rect().centery screen.blit(text, textRect) pygame.display.update()pygame.init()screen = pygame.display.set_mode( (640,480) )pygame.display.set_caption('Python numbers')screen.fill((159, 182, 205))font = pygame.font.Font(None, 17)num = 0done = Falsewhile not done: display( str(num) ) num += 1 pygame.event.pump() keys = pygame.key.get_pressed() if keys[K_ESCAPE]: done = True
This is the most awesome solution1 I've ever seen. Pasted here in case link goes down:
#!/usr/bin/env python'''A Python class implementing KBHIT, the standard keyboard-interrupt poller.Works transparently on Windows and Posix (Linux, Mac OS X). Doesn't workwith IDLE.This program is free software: you can redistribute it and/or modifyit under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.'''import os# Windowsif os.name == 'nt': import msvcrt# Posix (Linux, OS X)else: import sys import termios import atexit from select import selectclass 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 != []# Test if __name__ == "__main__": kb = KBHit() print('Hit any key, or ESC to exit') while True: if kb.kbhit(): c = kb.getch() if ord(c) == 27: # ESC break print(c) kb.set_normal_term()
1Made by Simon D. Levy, part of a compilation of software he has written and released under the Gnu Lesser General Public License.
Here a solution that runs under linux and windows using a seperate thread:
import sysimport threadingimport timeimport Queuedef add_input(input_queue): while True: input_queue.put(sys.stdin.read(1))def foobar(): input_queue = Queue.Queue() input_thread = threading.Thread(target=add_input, args=(input_queue,)) input_thread.daemon = True input_thread.start() last_update = time.time() while True: if time.time()-last_update>0.5: sys.stdout.write(".") last_update = time.time() if not input_queue.empty(): print "\ninput:", input_queue.get()foobar()