Key pressed (Windows/Linux) in Python (last update: 2017-03-15, created: 2017-03-15) back to the list ↑
Works both with Python 2.7 and Python 3.X on Linux and Windows. Technically it's a snippet from my ReRe CTF challenge (RE 500) published (with sources) on my blog.


import time
import math
import ctypes
import os
import hashlib
import sys
import colorsys

WINNT = os.name == 'nt'

def InitStuff():
  # Linux-only stuff.
  if not WINNT:

    # TermIOs library.
    global termios
    import termios

    # Select library.
    global select
    import select

    # fcntl and ioctl stuff.
    global fcntl
    import fcntl

    # Your favorite structure module.
    global struct
    import struct
 
  # And now for some Windows-only stuff.
  if WINNT:
    # kernel32.dll handle.
    global K32, CRT
    K32 = ctypes.windll.kernel32
    CRT = ctypes.cdll.msvcrt

    # Active Console Screen Buffer and Active Console Input Buffer
    global ACSB, ACIB, STD_OUTPUT_HANDLE, STD_INPUT_HANDLE
    STD_OUTPUT_HANDLE = -11
    STD_INPUT_HANDLE = -10
    ACSB = K32.GetStdHandle(STD_OUTPUT_HANDLE)
    ACIB = K32.GetStdHandle(STD_INPUT_HANDLE)

    # CONSOLE_CURSOR_INFO used to hide the cursor.
    global CONSOLE_CURSOR_INFO
    class CONSOLE_CURSOR_INFO(ctypes.Structure):
      _fields_ = [
        ("dwSize", ctypes.c_uint),
        ("bVisible", ctypes.c_int)  # Uhm, yes, BOOL == int.
      ]

def ChangeConsoleMode_Windows(add, chmode):
  mode = ctypes.c_uint()
  K32.GetConsoleMode(ACIB, ctypes.byref(mode))

  if add:
    mode.value |= chmode
  else:
    mode.value &= (~chmode) & 0xffffffff

  K32.SetConsoleMode(ACIB, mode)  

def ChangeConsoleMode_Linux(add, idx, chmode):
  mode = termios.tcgetattr(0)  # STDIN

  if add:
    mode[idx] |= chmode
  else:
    mode[idx] &= (~chmode) & 0xffffffff

  termios.tcsetattr(0, termios.TCSADRAIN, mode)

def ChangeBuffering(on):
  if not WINNT:
    ChangeConsoleMode_Linux(on, 3, termios.ICANON)
    return

  # ENABLE_LINE_INPUT 0x0002
  ChangeConsoleMode_Windows(on, 2)

def ChangeEcho(show):
  if not WINNT:
    ChangeConsoleMode_Linux(show, 3, termios.ECHO)
    return

  # ENABLE_ECHO_INPUT 0x0004
  ChangeConsoleMode_Windows(show, 4)

def ChangeCursor(show):
  if not WINNT:
    sys.stdout.write([
      "\x1b[?25l",
      "\x1b[?25h"
      ][show])
    sys.stdout.flush()
    return

  if not show:
    ChangeCursor.arch = CONSOLE_CURSOR_INFO()
    K32.GetConsoleCursorInfo(ACSB, ctypes.byref(ChangeCursor.arch))

    new_info = CONSOLE_CURSOR_INFO(0, 0)
    K32.SetConsoleCursorPosition(ACSB, ctypes.byref(new_info))
    return

  # Show.
  K32.SetConsoleCursorPosition(ACSB, ctypes.byref(ChangeCursor.arch))

def MaybeGetChar():
  if not WINNT:
    dr, dw, de = select.select([sys.stdin], [], [], 0)
    if not dr:
      return None
    return sys.stdin.read(1)

  if CRT._kbhit():
    return chr(CRT._getch())
  return None


InitStuff()
try:
  ChangeCursor(show=False)
  ChangeBuffering(on=False)
  ChangeEcho(show=False)

  input = ""
  while True:
    ch = MaybeGetChar()
    if ch is None:
      time.sleep(0.01)
    else:
      print ("YOU PRESSED: " + repr(ch) + " " + str(ord(ch)))

except KeyboardInterrupt:
    ChangeEcho(show=True)
    ChangeBuffering(on=True)
    ChangeCursor(show=True)  
【 design & art by Xa / Gynvael Coldwind 】 【 logo font (birdman regular) by utopiafonts / Dale Harris 】