code: def _getch_unix(_getall=False):
      
      import sys, termios
  
      fd = sys.stdin.fileno()
      # save old terminal settings
      old_settings = termios.tcgetattr(fd)
  
      chars = []
      try:
          # change terminal settings - turn off canonical mode and echo.
          # in canonical mode read from stdin returns one line at a time
          # and we need one char at a time (see DESIGN.rst for more info)
          newattr = list(old_settings)
          newattr[3] &= ~termios.ICANON
          newattr[3] &= ~termios.ECHO
          newattr[6][termios.VMIN] = 1   # block until one char received
          newattr[6][termios.VTIME] = 0
          # TCSANOW below means apply settings immediately
          termios.tcsetattr(fd, termios.TCSANOW, newattr)
  
          # [ ] this fails when stdin is redirected, like
          #       ls -la | pager.py
          #   [ ] also check on Windows
          ch = sys.stdin.read(1)
          chars = [ch]
  
          if _getall:
              # move rest of chars (if any) from input buffer
              # change terminal settings - enable non-blocking read
              newattr = termios.tcgetattr(fd)
              newattr[6][termios.VMIN] = 0      # CC structure
              newattr[6][termios.VTIME] = 0
              termios.tcsetattr(fd, termios.TCSANOW, newattr)
  
              while True:
                  ch = sys.stdin.read(1)
                  if ch != '':
                      chars.append(ch)
                  else:
                      break
      finally:
          # restore terminal settings. Do this when all output is
          # finished - TCSADRAIN flag
          termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
  
      if _getall:
          return chars
      else:
          return chars[0]
docs: # --- current algorithm ---
      # 1. switch to char-by-char input mode
      # 2. turn off echo
      # 3. wait for at least one char to appear
      # 4. read the rest of the character buffer (_getall=True)
      # 5. return list of characters (_getall on)
      #        or a single char (_getall off)