From: mju@mudos.ann-arbor.mi.us (Marc Unangst)
Subject: Re: Keyboard hit in C programs
Date: Tue, 10 Nov 1992 07:57:22 GMT
Organization: The Programmer's Pit Stop, Ann Arbor MI
Keywords: Keyboard hit, C programs, UNIX

In article <1dms9iINNa6m@agate.berkeley.edu> bernt@valois (Bernt Skottun) writes:
>intervals will not do). In the DOS environment
>I have been able to do this with the "kbhit()" function.
>My question is: what is the equivalent function in the UNIX
>environment? or how does one go about creating such a function?

Your question is answered in Part 4 of the comp.unix.questions FAQ
list.  In the future, please check to see if your question is answered
in one of the FAQ postings before posting it to the net.

4.1)  How do I read characters from a terminal without requiring the user
      to hit RETURN?

      Check out cbreak mode in BSD, ~ICANON mode in SysV.

      If you don't want to tackle setting the terminal parameters
      yourself (using the "ioctl(2)" system call) you can let the stty
      program do the work - but this is slow and inefficient, and you
      should change the code to do it right some time:

      #include <stdio.h>
      main()
      {
	    int c;

	    printf("Hit any character to continue\n");
	    /*
	     * ioctl() would be better here; only lazy
	     * programmers do it this way:
	     */
	    system("/bin/stty cbreak");        /* or "stty raw" */
	    c = getchar();
	    system("/bin/stty -cbreak");
	    printf("Thank you for typing %c.\n", c);

	    exit(0);
      }

      You might like to check out the documentation for the "curses"
      library of portable screen functions.  Often if you're interested
      in single-character I/O like this, you're also interested in
      doing some sort of screen display control, and the curses library
      provides various portable routines for both functions.

4.2)  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.

-- 
Marc Unangst, N8VRH         | "There are two ways to solve this problem:
mju@mudos.ann-arbor.mi.us   | the hard way, and the easy way.  Let's start
                            | with the hard way."
                            |   - W. Scheider, from a Physics lecture
Newsgroups: comp.unix.wizards