From: dfox@quack.sac.ca.us (David Fox)
Subject: 386bsd: how to read characters non-blocking
Followup-To: comp.unix.bsd
Keywords: termios, kbhit(), non-blocking read
Organization: The Duck Pond public unix: +1 408 249 9630, log in as 'guest'.
Date: 30 Dec 1992 20:31:09 UTC

Hi *,
 
I've had some problems recently trying to emulate the MS-DOS function
kbhit() in 386BSD.  I've gotten some good help, but the functions I've
tried don't work the way I think they're supposed to.  In MS-DOS, a
kbhit() simply returns (with a zero result) if no key has been pressed,
enabling the rest of the program (usually, a while loop) to continue 
processing.  That's what I want to do - loop until a key has been 
pressed.  However, the functions that I've tried so far (termios, stty,
read, cbreak, etc.) only emulate the getch() function which sits there until
a key has been pressed, which doesn't allow my program to continue
processing.

Why I've decided to post is because I received some example code that
uses the BSD termio and sets up for a non-blocking read (which is
apparently what I want).  This produces the expected behavior when
run on a Sparc (the site I use for mail/news) - it continues processing
in the loop, returning immediately if no key has been pressed.  After
editing this to make it compile under 386BSD (taking into account that
termio should be termios) it doesn't work the same way.  It simply sits
there in the kbhit() function until I press a key.

---  Begin sample code ---

#include <stdio.h>
#include <sys/types.h>
#include <termio.h>

main()
{
int ch;

	for (;;) {
		if ((ch = kbhit()) != 0)
			printf("a key was hit (%d)\n", ch);
		if (ch == 3)
			break;
		printf(".");
		fflush(stdout);
	}
}

/*
 * return a non-zero value if a key has been pressed (the value returned
 * is the ascii value of the key); note that this function does not do
 * anything special with multibyte sequences (such as those returned by
 * function keys or cursor motion keys)
 */
int
kbhit()
{
struct termio old, new; /* I changed to struct termios */
int retval;
char ch;

	/*
	 * get the line settings for standard input and save them
	 * in ``old''; we also copy them to ``new'' so that we can
	 * change the settings appropriately
	 */
	ioctl(0, TCGETA, &old); /* changed to TIOCGETA */
	memcpy((char *)&new, (char *)&old, sizeof(struct termio));
        /* changed termio to termios */
	/*
	 * set ``raw'' mode, ignore breaks, don't post-process output,
	 * don't echo characters, etc.
	 */
	new.c_iflag |= IGNBRK;
	new.c_oflag &= ~OPOST;
	new.c_lflag &= ~(ISIG|ICANON|ECHO);
	new.c_cc[VMIN] = 0;
	new.c_cc[VTIME] = 1;

	/*
	 * change the terminal line settings, read a character and
	 * then restore the terminal back to it's original state
	 */
	ioctl(0, TCSETA, &new); /* changed to TIOCSETA */
	retval = read(0, &ch, 1);
	ioctl(0, TCSETA, &old); /* changed to TIOCSETA */

	/*
	 * ``retval'' will either contain 1 (which means a key was
	 * pressed), 0 (which means that no key was pressed), or -1
	 * (which means an error occurred, check errno)
	 */
	if (retval > 0)
		retval = (int)ch;

	return retval;
}

---- End of included code ----
 
Forgive my ignorance, I am not yet well-skilled in Unix C programming,
but I'm fairly familiar with DOS C programming.

--
David Fox
dfox@quack.sac.ca.us

Newsgroups: comp.unix.bsd,comp.unix.questions,comp.unix.wizards