Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!seismo!ut-sally!godzilla!hitchens From: hitchens@godzilla.cs.utexas.edu (Ron Hitchens, Sun Wiz) Newsgroups: comp.unix.questions Subject: Re: Keyboard Input (Revised Question) ... Message-ID: <8569@ut-sally.UUCP> Date: Sun, 26-Jul-87 18:25:05 EDT Article-I.D.: ut-sally.8569 Posted: Sun Jul 26 18:25:05 1987 Date-Received: Sun, 26-Jul-87 22:41:37 EDT References: <1043@bucsb.bu.edu.UUCP> Sender: news@ut-sally.UUCP Reply-To: hitchens@godzilla.cs.utexas.edu (Ron Hitchens, Sun Wiz) Organization: Central Texas Aphasic Institute Lines: 107 Keywords: Keyboard Summary: Use select() In article <1043@bucsb.bu.edu.UUCP> eap@bucsb.UUCP (Eric Pearce) writes: >I would like to write a routine that performs a repeated sequence of statements >(i.e. a loop) that would check for input from the keyboard and do something >according to what was typed in. Also, it would be able to continue doing the >loop regardless of whether or not anything was typed in from the keyboard. > >like this: > > Begin Loop > check for keyboard input > if a key was pressed > case > 1) do something > 2) do something else > ... > esac > fi > do some more stuff > End Loop > >Is there a way to do this in C? Or maybe a different approach to the problem? >(this is intended for a program on a mainframe) > ANY ideas welcome! > -Eric >------------------------------------------------------------------------------- >Several people asked what machine I would be running this on: > Encore MULTIMAX 4.3 BSD UNIX > and a VAX 11/750 running the same... >******************************************************************************* >* UUCP : ..!harvard!bu-cs!bucsb!eap |-+-+ +-+-+-+-+-+-+-+\ /-+-+-+-+-+-+-+-+* >* ARPANET: eap@bucsb.bu.edu | > : : : - @ - | g * >* CSNET : eap%bucsb@bu-cs |-+-+-+-+-+-+-+-+-+-+/ \ +-+-+ +-+-+ +-+* >* BITNET : cscc8vc@bostonu | | Blasted by ZAXXON | ; | * >******************************************************************************* This article is almost two weeks old, I resisted answering until I got caught up on comp.unix.questions. A couple of people answered it with solutions using non-blocking reads and ioctl()s, but this is a job for select(). If select() is available, and it is on Eric's BSD systems listed above, it's much better than using ioctl()s. Below is some code which does just what Eric describes, using select(). This code is from a program which displays rwho information on the screen using curses(), and updates its display every 20 seconds. This loop does the "every time" stuff at the top of the loop, and the only keyboard input it looks for is a refresh command, anything else means to quit. For an application like this, select is definitely better, since the process is asleep in a system call until either input is ready or the timer runs out. With non-blocking I/O and ioctl()s, your process must run around in a busy loop polling the keyboard. A select() polling loop can still be done by providing the address of a timer set to zero. See the select() man page for details. Ron Hitchens hitchens@ut-sally.uucp hitchens@godzilla.cs.utexas.edu --------------- loop () { static struct timeval timer = {REFRESH_DEFAULT, 0}; char c; int inmask, nfds; timer.tv_sec = refresh_time; /* settable on cmd line */ while (1) { show_stat (); /* do it */ inmask = 1; /* gotta set the mask always */ if ((nfds = select (32, &inmask, 0, 0, &timer)) < 0) { printf ("Error doing select, I'm gettin' outta here\n"); return; } if (nfds == 0) continue; /* timer expired */ read (0, &c, 1); /* the sucker hit a key */ switch (c) { case 'r': case 'R': case 0x12: /* ^R */ case 'l': case 'L': case 0x0C: /* ^L */ (void) wclear (stdscr); /* clear the physical screen */ (void) wrefresh (stdscr);/* for reassuring feedback */ break; default: return; } } } The above code puts the tty into CBREAK mode before calling loop(). You'll want to do this if you want to get each char as it becomes available. If you leave it in cooked mode, select() will not indicate data is avaliable until an entire line has been entered and a newline typed (or some other "break" character, such as ^C or ESC). The tty driver will also do backspace handling transparently to you, if you use CBREAK, you'll have to do it yourself (if appropriate). There is a gotcha to watch out for if you mix select() and stdio. Select() works on file descriptors, stdio implements a buffering system between your code and the raw file descriptor. This means that the data returned to you by getchar(), gets(), etc, were probably read earlier and are being returned from a buffer. Doing a select() on an fd being used by stdio will only be indicative of new data available on the fd, it won't know about any data previously read and buffered by the stdio routines. In general, it's not a good idea to mix stdio and fd operations. ---------