3

msvcrt has a handy function for this: kbhit(). Unix doesn't :(


I have a function _Getch() like:

def _Getch():
    if sys.stdin.isatty():
        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
    else:
        return sys.stdin.read(1)

It gets exactly one keypress.

The problem comes when someone presses:

  • ESC sends \x1b. That's 1 byte: the actual escape character.

  • Page Up sends \x1b[H. That's 3 bytes.

  • F2 sends \x1b[OQ. That's 4 bytes.

  • F5 sends \x1b[15~. That's 5 bytes.

See where this is going? Once ESC has been read, there is no predicting how long the following sequence will be.

Subsequent _Getch() calls will get these bytes, but the question is of how many _Getch() calls.


I want to define a function like the following, which will read everything waiting in stdin til there's nothing left:

def _Kbhit():
    y = []
    while msvcrt.kbhit():         # while something is waiting
        y.append(msvcrt.getch())  # get it!
    return y

Here's the Unix equivalent that is my aim (from here):

def _Kbhit():
    fd = sys.stdin.fileno()
    fl = fcntl.fcntl(fd, fcntl.F_GETFL)
    fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
    return sys.stdin.read(waiting_buffer_len)  # ?

I just don't know how to define waiting_buffer_len.

I've searched through all the relevant docs (tty, termios, sys.stdin, fcntl, os), but I can't find what I'm looking for.

Community
  • 1
  • 1
cat
  • 3,888
  • 5
  • 32
  • 61

1 Answers1

0

I did some more searching and unintuitively, thanks to this answer:

Upon looking at the help documentation for sys.stdin.read, I noticed this:

read(...)

read([size]) -> read at most size bytes, returned as a string.

If the size argument is negative or omitted, read until EOF is reached. Notice that when in non-blocking mode, less data than what was requested may be returned, even if no size parameter was given.

The answer is waiting_buffer_len can be any length:

def _Kbhit():
    fd = sys.stdin.fileno()
    fl = fcntl.fcntl(fd, fcntl.F_GETFL)
    fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
    try:
        chars = sys.stdin.read(10)
    except TypeError:
        chars = ""
    finally:
        fcntl.fcntl(fd, fcntl.F_SETFL, fl)
        return chars

works perfectly.

Community
  • 1
  • 1
cat
  • 3,888
  • 5
  • 32
  • 61