From: mueller@rbg.informatik.th-darmstadt.de (Klaus Mueller)
Subject: Re: Keyboard hit in C programs
Date: Fri, 13 Nov 1992 16:18:18 GMT
Organization: TH Darmstadt
Keywords: Keyboard hit, C programs, UNIX


In article <1dms9iINNa6m@agate.berkeley.edu>, you write:
> 
> I am in the process of adapting a C program from the PC for
> the UNIX environment (for SUN 3 running SUNOS 4.1.1).
> In this program it is essential that
> the user be able to stop certain parts of the program
> (e.g. an inner loop) by hitting the keyboard (any key
> is fine) while as long as the keyboard is not touched the execution
> of the program will continue un-interupted (thus a procedure
> which requires, or expects, the user to type in a key stroke at certain
> 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?
> Any suggestions will be very welcome. Thanks a lot.
> Bernt Skottun, bernt@valois.berkeley.edu 
>  

Here is a solution to this problem that not even requires to poll the the
the keyboard. It uses SIGIO to get notified, but the program continues with
the loop after the signalhandler  has returned. So you have to think about 
leaving the loop after execution continues :).

I don't know how portable this is, my system is HP-UX. The relevant man-pages 
are: termio(7) and ioctl(5).


#include <sys/ioctl.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <termio.h>

struct termio term_old;

void resetfiles(void) {		/* resets all terminalstat we have changed */
    int arg;

    arg = 0;
    if (ioctl(STDIN_FILENO, FIOSSAIOSTAT, &arg)==-1) {
        perror("unset async");
        exit(1);
    }
    if (ioctl(STDIN_FILENO, TCSETA, &term_old) == -1) {
        perror("set termios");
        exit(1);
    }
}

void handler(int dummy) {	/* handels the SIGIO */
    printf("got it\n");
    resetfiles();	/* clear what we have done */
    exit(0);
}

int main (void) {
    int arg;
    struct termio term;
    
    arg = getpid();	/* tell the keyboard _we_ want the signal */
    if (ioctl(STDIN_FILENO, FIOSSAIOOWN, &arg)==-1) { 
	perror("set owner");
	resetfiles();
	exit(1);
    }

			/* tell the system we want a _signal_ */

    arg = 1;
    if (ioctl(STDIN_FILENO, FIOSSAIOSTAT, &arg)==-1) {
	perror("set async");
	resetfiles();
	exit(1);
    }

		/* keep the old stats */

    if (ioctl(STDIN_FILENO, TCGETA, &term_old) == -1) {	
	perror("get termio1");
	resetfiles();
	exit(1);
    }

		/* and get some stats we can change */

    if (ioctl(STDIN_FILENO, TCGETA, &term) == -1) {
	perror("get termio2");
	resetfiles();
	exit(1);
    }
    term.c_lflag &= ~ICANON;	  	/* get the charcters immediately */
    term.c_cc[VMIN] = (char) 0;		/* no char buffered */
    term.c_cc[VTIME] = (char) 0;	/* and no timeout */

		/* use our new settings */

    if (ioctl(STDIN_FILENO, TCSETA, &term) == -1) {
        perror("set termios");
        resetfiles();
        exit(1);
    }

    signal(SIGIO, handler); /* where to go with the signal */

    sleep(20);		/* now let's do something (sleep) */

    resetfiles();	/* reset all we changed */
}

-- 
Klaus M"uller  (mueller@rbg.informatik.th-darmstadt.de)
IRC: netmage       MUD: loren

Newsgroups: comp.unix.wizards