Return to BSD News archive
Received: by minnie.vk1xwt.ampr.org with NNTP id AA6423 ; Sat, 09 Jan 93 11:02:33 EST Xref: sserve comp.unix.bsd:9804 comp.lang.c:37807 Newsgroups: comp.unix.bsd,comp.lang.c Path: sserve!manuel.anu.edu.au!munnari.oz.au!sgiblab!sgigate!odin!sgihub!zola!delhi!dps From: dps@delhi.esd.sgi.com (D.P. Suresh) Subject: Re: a unix terminal question Message-ID: <uonuhjc@zola.esd.sgi.com> Sender: news@zola.esd.sgi.com (Net News) Organization: Silicon Graphics, Inc. Mountain View, CA References: <1iql6kINNisk@ub.d.umn.edu> <1993Jan11.215312.2080@fcom.cc.utah.edu> Date: Mon, 11 Jan 93 22:48:02 GMT Lines: 103 In article <1993Jan11.215312.2080@fcom.cc.utah.edu>, terry@cs.weber.edu writes: > In article <1iql6kINNisk@ub.d.umn.edu> cbusch@ub.d.umn.edu (Chris) writes: > > > > How does one read in a character from standard input without having > >the program wait for the key. Basically, I want to do something like: > > if(kbhit()) c=getch(); > >Except that is not standard, and I want it to work on all platforms. > > This is a bad thing to do, unless you have processing to do when characters > aren't present, and you do your checks relatively infrequently compared to > the procesing itself; otherwise, you will be in a buzz-loop and suck your > CPU through the floor. This is common practice under DOS where there is > nothing else running, but is a generally bad thing to do. > > The CORRECT way to do this: use the select() or poll() system call to > wait for an interval or a character to be present. Resoloution is > generally 1/1000th of a second; you can effect a poll by having a > zero-valued timeval struct (as opposed to passing (struct timeval *)NULL). > This will cause the behaviour you have asked for. When the select() > returns that there are characters available, do a read() on the descriptor > (otherwise, return as if the read() has returned 0 characters). It > should be noted that some systems are sensitive to select/read pairing, > and if you do this, you should have a select() call prior to every read() > call, regardless of whther or not you use the select information aro simply > read anyway. select() or poll() in itself will not get you the desired result. If my memory of DOS does not fail me, kbhit() is a non-blocking call. It just tells you *at once* whether zero or more keys are waiting for his/her highness to be read. To get this effect on UNIX, one should combine select()/poll() with putting the terminal in raw mode. If you dont put the terminal in raw mode and try select()/poll() then even if you press a key, select()/poll() will not detect them until CR is given. Here is a code sample: /* Test code for kbhit function */ #include <stdio.h> #include <termio.h> #include <unistd.h> #include <sys/types.h> #include <sys/time.h> #include <sys/file.h> kbhit() { fd_set readfds, writefds, exceptfds; struct timeval timeout; static struct termio otty, ntty; int ret; /* Create proper environment for select() */ FD_ZERO( &readfds ); FD_ZERO( &writefds ); FD_ZERO( &exceptfds ); FD_SET( fileno(stdin), &readfds ); /* We shall specify 0.5 sec as the waiting time */ timeout.tv_sec = 0; /* 0 seconds */ timeout.tv_usec = 500; /* 500 microseconds */ /* Put tty in raw mode */ ioctl(fileno(stdout), TCGETA, &otty); ntty = otty; ntty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL); ntty.c_lflag &= ~ICANON; ntty.c_lflag |= ISIG; ntty.c_cflag &= ~(CSIZE|PARENB); ntty.c_cflag |= CS8; ntty.c_iflag &= (ICRNL|ISTRIP); ntty.c_cc[VMIN] = ntty.c_cc[VTIME] = 1; ioctl(fileno(stderr), TCSETAW, &ntty); /* Do a select */ ret = select( 1, &readfds, &writefds, &exceptfds, &timeout ); /* Reset the tty back to its original mode */ ioctl(fileno(stderr), TCSETAW, &otty); return( ret ); } main() { while( !kbhit() ) { /* No key was hit. Do your own processing. */ } printf("Hey. you hit a key.\n"); } /* End of listing */ WARNING: This feature should be used wisely. One could incur quite a lot of performance penalties as expressed by terry. -- D.P.Suresh dps@esd.sgi.com