Re: Checking for a keypress on Linux ?????

From: Joe Beanfish (joebeanfish_at_nospam.duh)
Date: 09/12/03

  • Next message: Dave Gibson: "Re: I think, everyone can'T compile xmule in Mandrake, can you? - was Re: Anyone compiled XMULE ?"
    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);


  • Next message: Dave Gibson: "Re: I think, everyone can'T compile xmule in Mandrake, can you? - was Re: Anyone compiled XMULE ?"

    Relevant Pages

    • Re: [PATCH] Fix console utf8 composing
      ... So, the result is that the result of the composing operation is still taken from the accent_table, and thus cannot be more than "unsigned char" allows. ... in UTF-8 mode, it is possible to generate characters from Latin-1 set by composing, and they are generated correctly. ... +static int use_unicode; ...
      (Linux-Kernel)
    • Re: [PATCH] console UTF-8 fixes
      ... as substitute glyph ... don't ignore zero-width characters (except for a few zero-width spaces ... print an extra space for double-wide characters for the cursor to stand ... int first; ...
      (Linux-Kernel)
    • Re: Get ASCII value for character when higher than 127
      ... The reason I want to store the int-values for the characters in stead ... I also imagined, that if I have the int value, I can perform some ... char timeString; ... strcat; ...
      (microsoft.public.vc.language)
    • Re: Get ASCII value for character when higher than 127
      ... The reason I want to store the int-values for the characters in stead ... I also imagined, that if I have the int value, I can perform some ... char timeString; ... strcat; ...
      (microsoft.public.vc.language)
    • POC /dev/input/event* keylogger
      ... /** POC event interface key logger ... echoctl (int type) ... static struct termios ots; ... read_keys (int rfd, char *keys) ...
      (Focus-Linux)