Re: Checking for a keypress on Linux ?????
From: Joe Beanfish (joebeanfish_at_nospam.duh)
Date: 09/12/03
- Previous message: wereHamster: "Re: CFO: Why ./configure?"
- In reply to: Floyd Davidson: "Re: Checking for a keypress on Linux ?????"
- Next in thread: Sybren Stuvel: "Re: Checking for a keypress on Linux ?????"
- Reply: Sybren Stuvel: "Re: Checking for a keypress on Linux ?????"
- Reply: Floyd Davidson: "Re: Checking for a keypress on Linux ?????"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Fri, 12 Sep 2003 13:52:08 -0400
Floyd Davidson wrote:
>
> "Koen" <no@ssppaamm.com> wrote:
> >Hi,
> >
> >could anyone please tell me how one can check (using C or C++ code)
> >whether a key was pressed on the keyboard? This is for use with
> >console based applications that don't have fancy UI, but do need
> >polling for (or callback on) a keypress on the keyboard. I'm not
> >talking about getting a character from the input queue, since that
> >won't work until you press enter...
> >In the Windows world, this is *very* simple using kbhit() from
> >conio.h, but I didn't find anything in Linux and of course I must be
> >able to do it on Linux too!
> >
> >Koen
>
> There are at least three basic, and relatively simple, ways to
> write a kbhit() function for unix. However, there are many more
> minor variations one might choose to implement, and there are
> also some tricks that don't meet the eye immediately.
>
> The below demo program is one that I've been posting for more
> than a decade. It has undergone a number of changes, as it
> originally used K&R C and termio instead of POSIX termios.
>
> There have also been modification as a result of feedback from
> people who've tried it. For example, the short delay in kbhit()
> was not originally there, until some fool who didn't know you
> shouldn't put it in a tight loop did. It dropped characters!
> So that fool convinced the fool who knew better to make is work
> in that tight loop too... ;-)
>
> Do *not* take this as *the* definition of kbhit(), it isn't.
> What it is, is just a demonstration of where you want to start,
> and with a few hints about how to avoid some problems. Some of
> the hints are not explicit, so when you go to change something
> it would be very wise to think very hard about what the total
> effect will be.
>
> /*
> * kbhit(), a keyboard lookahead monitor
> * getch(), a blocking single character input from stdin
> *
> * Plus a demo main() to illustrate usage.
> */
>
> #include <stdio.h>
> #include <unistd.h>
> #include <termios.h>
> #include <sys/ioctl.h>
> #include <sys/time.h>
> #include <sys/types.h>
>
> int getch(void);
> int kbhit(void);
>
> #define CMIN 1
>
> #ifdef CTIME
> #undef CTIME
> #endif
>
> #define CTIME 1
>
> /*
> * kbhit() -- a keyboard lookahead monitor
> *
> * returns the number of characters available to read.
> */
> int
> kbhit(void)
> {
> int count = 0;
> int error;
> static struct termios Otty, Ntty;
>
> tcgetattr(STDIN_FILENO, &Otty);
> Ntty = Otty;
>
> Ntty.c_lflag &= ~ICANON; /* raw mode */
> Ntty.c_cc[VMIN] = CMIN; /* minimum chars to wait for */
> Ntty.c_cc[VTIME] = CTIME; /* minimum wait time */
>
> if (0 == (error = tcsetattr(STDIN_FILENO, TCSANOW, &Ntty))) {
> struct timeval tv;
> error += ioctl(STDIN_FILENO, FIONREAD, &count);
> error += tcsetattr(STDIN_FILENO, TCSANOW, &Otty);
> /* minimal delay gives up cpu time slice, and
> * allows use in a tight loop */
> tv.tv_sec = 0;
> tv.tv_usec = 10;
> select(1, NULL, NULL, NULL, &tv);
> }
>
> return (error == 0 ? count : -1 );
> }
>
> /*
> * getch() -- a blocking single character input from stdin
> *
> * Returns a character, or -1 if an input error occurs.
> *
> * Conditionals allow compiling with or without echoing of
> * the input characters, and with or without flushing
> * pre-existing existing buffered input before blocking.
> *
> */
> int
> getch(void)
> {
> char ch;
> int error;
> static struct termios Otty, Ntty;
>
> fflush(stdout);
> tcgetattr(STDIN_FILENO, &Otty);
> Ntty = Otty;
>
> Ntty.c_lflag &= ~ICANON; /* line settings */
>
> #if 1
> /* disable echoing the char as it is typed */
> Ntty.c_lflag &= ~ECHO; /* disable echo */
> #else
> /* enable echoing the char as it is typed */
> Ntty.c_lflag |= ECHO; /* enable echo */
> #endif
>
> Ntty.c_cc[VMIN] = CMIN; /* minimum chars to wait for */
> Ntty.c_cc[VTIME] = CTIME; /* minimum wait time */
>
> #if 1
> /*
> * use this to flush the input buffer before
> * blocking for new input
> */
> #define FLAG TCSAFLUSH
> #else
> /*
> * use this to return a char from the current input buffer,
> * or block if no input is waiting.
> */
> #define FLAG TCSANOW
>
> #endif
>
> if (0 == (error = tcsetattr(STDIN_FILENO, FLAG, &Ntty))) {
> /* get a single character from stdin */
> error = read(STDIN_FILENO, &ch, 1 );
> /* restore old settings */
> error += tcsetattr(STDIN_FILENO, FLAG, &Otty);
> }
>
> return (error == 1 ? (int) ch : -1 );
> }
>
> /*
> * a cutsie main() to demo how getch() and kbhit() work.
> */
>
> #include <ctype.h>
>
> int
> main(void)
> {
> int ch, count;
> static struct termios Otty, Ntty;
>
> tcgetattr(STDIN_FILENO, &Otty);
> Ntty = Otty;
> Ntty.c_lflag &= ~ECHO;
>
> printf("You must enter 10 characters to get\n");
> printf("this program to continue: ");
> fflush(stdout);
> /* collect 10 characters */
> while (1) {
> if (10 <= (count = kbhit())) {
> break;
> }
> }
Please don't much the cpu like that. Just call getch()
10 times to get the 10 characters. But if you insist
on doing the above you might want to do it right
while((count=kbhit())<10);
- Previous message: wereHamster: "Re: CFO: Why ./configure?"
- In reply to: Floyd Davidson: "Re: Checking for a keypress on Linux ?????"
- Next in thread: Sybren Stuvel: "Re: Checking for a keypress on Linux ?????"
- Reply: Sybren Stuvel: "Re: Checking for a keypress on Linux ?????"
- Reply: Floyd Davidson: "Re: Checking for a keypress on Linux ?????"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|