: I'm porting a DOS program to Linux, and I'm wondering how to port the
: kbhit() call? I tried out using select() on STDIN, but it only returns
: when I hit a RETURN key. I'd like to just poll the keyboard and see if
: a key has been hit while focused on my application. Any ideas?
Thanks to all of you who replied. Many suggested using the cbreak()
function of ncurses. Since I'm not using ncurses, that didn't help
much, but I'll save it for a time when I *do* use ncurses.
Anyways, here is the final code I came up with. I thought maybe
someone else might be able to use it. So, here you go. A little heavy
on the documentation, but I'm making up for other parts of Linux :)
Pete Kruckenberg
----------------------------------------------------------------------
/* kbhit(void) : returns 1 if a key has been struck, 0 otherwise
Port of the kbhit() MS-DOS function to Linux (and maybe other OS's).
Checks to see if there are any keystrokes available, without blocking.
If any keystrokes are available, they should be retrieved with
getchar() or a similar function (this function won't retrieve them).
This is released into the public domain by the author, Pete Kruckenberg.
There is no guarantee or warranty, implied or otherwise, as to its
proper functionality. The author shall not be liable in any manner for
this code.
*/
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <termios.h>
int kbhit(void) {
/* return 0 for no key pressed, 1 for key pressed */
int return_value = 0;
/* variables to store the current tty state, create a new one */
struct termios origtty, tty;
/* time struct for the select() function, to only wait a little while */
struct timeval select_time;
/* file descriptor variable for the select() call */
fd_set readset;
/* we're only interested in STDIN */
FD_ZERO(&readset);
FD_SET(STDIN_FILENO, &readset);
/* store the current tty settings */
tcgetattr(0, &origtty);
/* flush the tty */
tcflush(0, TCIOFLUSH);
/* start with the current settings */
tty = origtty;
/* make modifications to put it in raw mode, turn off echo */
tty.c_iflag &= ~(IGNCR|IUCLC|ICRNL|INLCR);
tty.c_oflag &= ~(ONLCR|OPOST|ONLCR|OCRNL|ONLRET|OLCUC);
tty.c_lflag &= ~(ISIG|ICANON|XCASE|ECHO|ECHOE|ECHOK|ECHONL|ECHOPRT| \
ECHOCTL|ECHOKE);
tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 0;
/* put the settings into effect */
tcsetattr(0, TCSADRAIN, &tty);
/* how long to block for - this must be > 0.0, but could be changed
to some other setting. 10-18msec seems to work well and only
minimally load the system (0% CPU loading) */
select_time.tv_sec = 0;
select_time.tv_usec = 10;
/* is there a keystroke there? */
if (select(1, &readset, NULL, NULL, &select_time))
/* yes, remember it */
return_value = 1;
/* reset the tty to its original settings */
tcsetattr(0, TCSADRAIN, &origtty);
/* return with what we found out */
return return_value;
Quote:}