This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| _kbhit() for Linux Submitted by

The Windows _kbhit() function returns a nonzero value when a character is waiting in stdin, otherwise it returns zero. It does not consume the character and does not block. A common use of this function is to test when the user has pressed a key in an interactive console application. POSIX (and therefore Linux) lacks a similar function. Although it does not directly support this functionality, the GNU Curses library can be used to implement _kbhit() on Linux. Here I present an alternate solution to Curses that implements _kbhit() using only standard libraries. It should port directly to OS X, AIX, and other Unix-like operating systems as well as Linux. This implementation has two advantages over a Curses based approach. The Curses library must be initialized from main() before it can be used. This implementation is a drop-in replacement for _kbhit() when porting from Windows and does not require any explicit initialization. Also, no external library must be installed and linked.
The ioctl() function is a low level method for controlling I/O drivers. Its arguments depend on the stream and driver being used. The last group of lines in _kbhit() uses this function to determine whether data is waiting on stdin. This implementation was written specifically for Linux and may not port. A more general implementation can replace these lines with a call to the select() function as follows:

        timeval timeout;
        fd_set rdset;

        FD_ZERO(&rdset);
        FD_SET(STDIN, &rdset);
        timeout.tv_sec  = 0;
        timeout.tv_usec = 0;

        return select(STDIN + 1, &rdset, NULL, NULL, &timeout);

Console input is typically line buffered on Linux, particularly when running over Telnet or SSH. This means that a keypress does not appear on stdin until a newline character is sent. The ioctl() or select() calls cannot determine if characters are in the buffer waiting for a newline, and can indicate that there are zero characters waiting when really several keys have been pressed.
To fix this, the first code block in _kbhit() disables line buffering. This uses routines from the termios.h header. Another author offers a longer method that uses only ioctl() and avoids termios.h. Because termios.h is a standard header on most systems I see no reason to avoid it. Both implementations use a static variable to detect the first call and disable buffering then. Output buffering on stdout is still enabled. If you wish to print to stdout and see the result before a newline is sent, use the command flush(stdout) as shown in the simple demo.
The Linux version of _kbhit() now performs to the same specification as the Windows version. The actual value of the non-zero integer returned will be different on the two platforms, however.
Morgan McGuire

Download Associated File: kbhit.txt (922 bytes)

    /**
     Linux (POSIX) implementation of _kbhit().
     Morgan McGuire, morgan@cs.brown.edu
     */
    #include <stdio.h>
    #include <sys/select.h>
    #include <termios.h>
    #include <stropts.h>

    int _kbhit() {
        static const int STDIN = 0;
        static bool initialized = false;

        if (! initialized) {
            // Use termios to turn off line buffering
            termios term;
            tcgetattr(STDIN, &term);
            term.c_lflag &= ~ICANON;
            tcsetattr(STDIN, TCSANOW, &term);
            setbuf(stdin, NULL);
            initialized = true;
        }

        int bytesWaiting;
        ioctl(STDIN, FIONREAD, &bytesWaiting);
        return bytesWaiting;
    }

    //////////////////////////////////////////////
    //    Simple demo of _kbhit()

    #include <unistd.h>

    int main(int argc, char** argv) {
        printf("Press any key");
        while (! _kbhit()) {
            printf(".");
            fflush(stdout);
            usleep(1000);
        }
        printf("\nDone.\n");

        return 0;
    }

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.