From - Thu Apr 25 16:18:51 2002 Path: news.net.uni-c.dk!logbridge.uoregon.edu!pln-e!spln!dex!extra.newsguy.com!newsp.newsguy.com!enews1 From: Floyd Davidson Newsgroups: linux.dev.c-programming,linux.dev.gcc,comp.os.linux.development.apps Subject: Re: Immediate Detection of Character Input Date: 24 Apr 2002 14:12:51 -0800 Organization: __________ Lines: 217 Sender: floyd@barrow.com Message-ID: <87pu0obva4.fld@barrow.com> References: <3CC7167A.8080405@csulb.edu> NNTP-Posting-Host: p-491.newsdawg.com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii User-Agent: gnus 5.8.3/XEmacs 21.1.9/Linux Xref: news.net.uni-c.dk comp.os.linux.development.apps:130803 X-Mozilla-Status: 8010 X-Mozilla-Status2: 00000000 Alex Sramek wrote: >I'm writing a game in C, on a linux box (working on recent RedHat and >Mandrake systems). > >I want to get input from the keyboard immediately into the program, >without having to wait for an end of line to empty the buffer. Just >whenever a key is pressed, I'd like to hear about it and be able to tell >what key(s) was (were) pressed, preferably in a non-blocking manner (the >code can go on if nothing is received). > >I would prefer not to use curses.h if possible, but if I must, I must. > >I think ioctl might be able to do it, but I'm unfamiliar with the >syntax, and the manpage for it isn't at all helpful. > >Any suggestions/comments are appreciated. > >Thanks! > >-Alex Here is a program that demonstrates the functionality you seek. /* * kbhit(), a keyboard lookahead monitor * getch(), a blocking single character input from stdin * * Plus a demo main() to illustrate usage. */ #include #include #include #include #include #include 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 cnt = 0; int error; static struct termios Otty, Ntty; tcgetattr(0, &Otty); Ntty = Otty; Ntty.c_iflag = 0; /* input mode */ Ntty.c_oflag = 0; /* output mode */ 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(0, TCSANOW, &Ntty))) { struct timeval tv; error += ioctl(0, FIONREAD, &cnt); error += tcsetattr(0, TCSANOW, &Otty); tv.tv_sec = 0; tv.tv_usec = 100; /* insert a minimal delay */ select(1, NULL, NULL, NULL, &tv); } return (error == 0 ? cnt : -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(0, &Otty); Ntty = Otty; Ntty.c_iflag = 0; /* input mode */ Ntty.c_oflag = 0; /* output mode */ 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(0, FLAG, &Ntty))) { error = read(0, &ch, 1 ); /* get char from stdin */ error += tcsetattr(0, FLAG, &Otty); /* restore old settings */ } return (error == 1 ? (int) ch : -1 ); } /* * a cutsie main() to demo how getch() and kbhit() work. */ #include int main(void) { int ch, cnt; static struct termios Otty, Ntty; tcgetattr(0, &Otty); Ntty = Otty; Ntty.c_lflag &= ~ECHO; printf("You must enter 10 characters to get\nthis program to continue: "); fflush(stdout); /* collect 10 characters */ while (1) { if (10 <= (cnt = kbhit())) { break; } } tcsetattr(0, TCSANOW, &Ntty); /* disable echoing of further input */ printf("\nSTOP!"); fflush(stdout); printf("\nNow type to continue!"); fflush(stdout); ch = getchar(); tcsetattr(0, TCSANOW, &Otty); /* enable echoing of further input */ printf("\n\nThe first five characters are: \""); /* * print a few chars, note that calling getch() will flush * remaining buffered input. */ cnt = 4; do { printf("%c", ch); ch = getchar(); } while (--cnt); printf("%c\"\n\n", ch); printf("\n\n *** Demo Menu ***\n\n"); printf(" Option Action\n"); printf(" A Exit and print an A word\n"); printf(" B Exit and print a B word\n"); printf(" C Exit and print a C word\n"); printf("\n Enter your choice: ?\b"); fflush(stdout); while(1) { switch (ch = getch()) { case 'a': case 'A': printf("%c\n\nThat is an *awesome* function!\n", toupper(ch)); break; case 'b': case 'B': printf("%c\n\nThat is a *beneficial* function!\n", toupper(ch)); break; case 'c': case 'C': printf("%c\n\nThat is a *critical* function!\n", toupper(ch)); break; default: continue; } break; } return 0; } -- Floyd L. Davidson Ukpeagvik (Barrow, Alaska) floyd@barrow.com