[comp.lang.c] How to test if a key has been hit w/o waiting for a key ?

chris@mimsy.umd.edu (Chris Torek) (05/02/90)

>In article <1990Apr24.000717.7882@cunixf.cc.columbia.edu>
>gm@cunixd.cc.columbia.edu (Gary Mathews) writes:
>>I want to do some computation and be able to stop by a key pressed by the
>>user.

(As I said already, this cannot be done *portably*.  Given a definition
for `key pressed' and `user', it can usually be done; and it can usually
be done without resorting to writing assembly code, as I once did on VMS
so as to bypass the Pascal runtime library....)

In article <8281@cognos.UUCP> jimp@cognos.UUCP (Jim Patterson) writes:
>        ioctl( stdin->_file, FIONREAD, &count );
>        count += stdin->_cnt;

Be *very* careful with this:
  a. FIONREAD does not exist on all Unix systems, and on some of those
     on which it does exist, it does not quite work right;
  b. stdin probably does not have a _file and/or _cnt structure member
     on some machines.  (If you disagree, try porting to 4.4BSD when
     it comes out.  You may be unpleasantly surprised.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

martin@mwtech.UUCP (Martin Weitzel) (05/02/90)

In article <1990Apr30.182959.18254@cti-software.nl> pim@cti-software.nl (Pim Zandbergen) writes:
[original q&a deleted]
>
>There is also way to find out if a key has been pressed in System V,
>but it is an *ugly* way.

If all keyboard input flows thru a central function of your program,
it's rather clean - just read a character with timeout set to 0
seconds and store that character in a static variable. Use some
impossible value in the static, if no "look ahead" character is
available. It's not extremly hard to extend the look ahead to a
buffer and count of the available characters or have an additional
function to purge them.

BTW: If someone request the above information from me, my first reaction
is to ask back: "Why do want to do this"? If the one who asks comes from
DOS-world, there's a good probability that it's rather a 'timed out
read' what he or she wants, and if you let them you can bet they will
write an idle loop until some input is available.

A: Ohhh, how *incredibly slow* is this UNIX system compared to good old
   DOS I used before ...
B: Let's see ... hmm <typing ps ... etc.>; Ehhm, what does this
   program called "humpfelgrumpf" that is running on the other virtual
   screen?
A: Oh, not much really, gathers some statistical information, not much
   work at all, some few tenths of a second every thirty seconds.
B: And in the meantime.
A: Just looks if a key has been pressed.
-- 
Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83

hsiegel@cvbnet.UUCP (Howard Siegel 4-2390 x4064) (05/09/90)

 gm@cunixd.cc.columbia.edu (Gary Mathews) writes:
 
>I want to do some computation and be able to stop by a key pressed by the
>user.  Turbo C has a function kbhit() and Turbo Pascal has keypressed(),
>but what can be done with UNIX?  I've looked into the stdin structure:

I don't know about other flavors of UNIX, but SunOS has a function
named "select" [horribly non-intuitive, in my opinion] that ought to
do what you want.  The "man" page follows.


SELECT(2)                 SYSTEM CALLS                  SELECT(2)

NAME
     select - synchronous I/O multiplexing

SYNOPSIS
     #include <sys/types.h>
     #include <sys/time.h>

     int select (width, readfds, writefds, exceptfds, timeout)
     int width;
     fd_set *readfds, *writefds, *exceptfds;
     struct timeval *timeout;

     FD_SET (fd, &fdset)
     FD_CLR (fd, &fdset)
     FD_ISSET (fd, &fdset)
     FD_ZERO (&fdset)
     int fd;
     fd_set fdset;

DESCRIPTION
     select() examines the I/O descriptor  sets  whose  addresses
     are  passed  in  readfds,  writefds, and exceptfds to see if
     some of their descriptors are ready for reading,  ready  for
     writing, or have an exceptional condition pending.  width is
     the number of bits to be  checked  in  each  bit  mask  that
     represent  a file descriptor; the descriptors from 0 through
     width-1 in the  descriptor  sets  are  examined.   Typically
     width  has  the  value  returned by getdtablesize(2) for the
     maximum number of file  descriptors.   On  return,  select()
     replaces  the  given descriptor sets with subsets consisting
     of those descriptors that are ready for the requested opera-
     tion.  The total number of ready descriptors in all the sets
     is returned.

     The descriptor sets are stored as bit fields  in  arrays  of
     integers.   The following macros are provided for manipulat-
     ing such descriptor sets:  FD_ZERO  (&fdset)  initializes  a
     descriptor  set  fdset to the null set.  FD_SET(fd, &fdset )
     includes a particular descriptor fd  in  fdset.   FD_CLR(fd,
     &fdset)  removes  fd  from  fdset.   FD_ISSET(fd, &fdset) is
     nonzero if fd is a member of  fdset,  zero  otherwise.   The
     behavior  of these macros is undefined if a descriptor value
     is less than zero or greater than or  equal  to  FD_SETSIZE,
     which  is  normally  at least equal to the maximum number of
     descriptors supported by the system.

     If timeout is not a NULL pointer,  it  specifies  a  maximum
     interval  to wait for the selection to complete.  If timeout
     is a NULL  pointer,  the  select  blocks  indefinitely.   To
     effect  a  poll,  the  timeout argument should be a non-NULL
     pointer, pointing to a zero-valued timeval structure.

     Any of readfds, writefds, and exceptfds may be given as NULL
     pointers if no descriptors are of interest.

     Selecting true for reading on a socket descriptor upon which
     a listen (2) call has been performed indicates that a subse-
     quent accept(2) call on that descriptor will not block.

RETURN VALUE
     select() returns the number of ready  descriptors  that  are
     contained  in  the  descriptor  sets,  or  -1  if  an  error
     occurred.  If the time limit expires then  select()  returns
     0.   If select() returns with an error, including one due to
     an interrupted call, the descriptor sets will be unmodified.

ERRORS
     An error return from select() indicates:

     EBADF          One  of  the  descriptor  sets  specified  an
                    invalid descriptor.

     EINTR          A signal was  delivered  before  any  of  the
                    selected  events occurred, or before the time
                    limit expired.

     EINVAL         A component of the pointed-to time  limit  is
                    outside  the  acceptable range: t_sec must be
                    between 0 and 10^8, inclusive. t_usec must be
                    greater-than  or  equal  to  0, and less than
                    10^6.

     EFAULT         One  of  the  pointers  given  in  the   call
                    referred  to  a  non-existent  portion of the
                    process' address space.

SEE ALSO
     accept(2),  connect(2),  getdtablesize(2),  gettimeofday(2),
     listen(2), read(2V), recv(2), send(2), write(2V)

BUGS
     Although the provision of getdtablesize(2) was  intended  to
     allow  user programs to be written independent of the kernel
     limit on the number of open files, the dimension of a suffi-
     ciently  large  bit field for select remains a problem.  The
     default size FD_SETSIZE (currently 256) is  somewhat  larger
     than  the  current kernel limit to the number of open files.
     However, in order to accommodate programs which might poten-
     tially  use a larger number of open files with select, it is
     possible to increase this size within a program by providing
     a  larger  definition  of FD_SETSIZE before the inclusion of
     /usr/include/sys/types.h.

     select() should probably return the time remaining from  the
     original  timeout,  if  any,  by modifying the time value in
     place.  This may be implemented in future  versions  of  the
     system.   Thus,  it  is  unwise  to  assume that the timeout
     pointer will be unmodified by the select() call.


Sun Release 4.0.3     Last change: 25 March 1989                3