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.
[code]/**
Linux (POSIX) implementation of _kbhit().
Morgan McGuire, morgan@cs.brown.edu
*/
#include
#include
#include
#include
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
printf("Press any key");
while (! _kbhit()) {
printf(".");
fflush(stdout);
usleep(1000);
}
printf("\nDone.\n"); return 0;
}[/code]