Xref: utzoo comp.unix.programmer:172 comp.unix.questions:25943 Path: utzoo!attcan!uunet!snorkelwacker!bloom-beacon!athena.mit.edu!jik From: jik@athena.mit.edu (Jonathan I. Kamens) Newsgroups: comp.unix.programmer,comp.unix.questions Subject: Re: can i test for keyboard input? Message-ID: <1990Oct3.164026.17052@athena.mit.edu> Date: 3 Oct 90 16:40:26 GMT References: <1990Oct3.041737.2280@watmath.waterloo.edu> Sender: daemon@athena.mit.edu (Mr Background) Reply-To: jik@athena.mit.edu (Jonathan I. Kamens) Organization: Massachusetts Institute of Technology Lines: 129 As I believe has been discussed recently in this newsgroup (comp.unix.programmer), you can use the FASYNC fcntl() operation on BSD-like systems to turn on asynchronous input mode on standard input, and that should cause you to get a SIGIO every time a character is typed. Furthermore, question 7 on the monthly comp.unix.questions Frequently Asked Questions posting (most recently posted on October 1) is, "How do I check to see if there are characters to be read without actually reading?" It's usually a good idea to read the FAQ posting before posting a question to a comp.unix.* newsgroup in general, or to comp.unix.questions in particular. I have included the text of the FAQ posting's answer at the end of this message. Finally, I have included below the FAQ text the source code for a function called keypressed() which should illustrate to you the general method you can use, at least under BSD-like systems. -- Jonathan Kamens USnail: MIT Project Athena 11 Ashford Terrace jik@Athena.MIT.EDU Allston, MA 02134 Office: 617-253-8495 Home: 617-782-0710 ------------------------------------------------------------------ 7) How do I check to see if there are characters to be read without actually reading? Certain versions of UNIX provide ways to check whether characters are currently available to be read from a file descriptor. In BSD, you can use select(2). You can also use the FIONREAD ioctl (see tty(4)), which returns the number of characters waiting to be read, but only works on terminals, pipes and sockets. In System V Release 3, you can use poll(2), but that only works on streams. In Xenix - and therefore Unix SysV r3.2 and later - the rdchk() system call reports whether a read() call on a given file descriptor will block. There is no way to check whether characters are available to be read from a FILE pointer. (You could poke around inside stdio data structures to see if the input buffer is nonempty, but that wouldn't work since you'd have no way of knowing what will happen the next time you try to fill the buffer.) Sometimes people ask this question with the intention of writing if (characters available from fd) read(fd, buf, sizeof buf); in order to get the effect of a nonblocking read. This is not the best way to do this, because it is possible that characters will be available when you test for availability, but will no longer be available when you call read. Instead, set the O_NDELAY flag (which is also called FNDELAY under BSD) using the F_SETFL option of fcntl(2). Older systems (Version 7, 4.1 BSD) don't have O_NDELAY; on these systems the closest you can get to a nonblocking read is to use alarm(2) to time out the read. ------------------------------------------------------------------ /* Procedure to check for waiting input on the tty. Does not */ /* actually read the input. */ #include #include #include #include #ifdef TEST main() { char buf[64]; while (1) { if (keypressed()) break; else { printf("Waiting...\n"); sleep(1); } } (void) printf("Enter string: "); (void) gets(buf); exit(0); } #endif int keypressed() { /* These are for ioctl */ struct sgttyb tty, ntty; int ttyset, stat, arg; ttyset = 0; stat = ioctl(0, TIOCGETP, &tty); if (stat == -1) { perror("ioctl"); return(-1); } if (! (tty.sg_flags & CBREAK)) { ntty = tty; ttyset = (! ttyset); ntty.sg_flags |= CBREAK; stat = ioctl(0, TIOCSETN, &ntty); if (stat == -1) { perror("ioctl"); return(-1); } } stat = ioctl(0, FIONREAD, &arg); if (stat == -1) { perror("ioctl"); return(-1); } if (ttyset) { stat = ioctl(0, TIOCSETN, &tty); if (stat == -1) { perror("ioctl"); return(-1); } } return(arg); }