nather@ut-sally.UUCP (Ed Nather) (02/01/88)
There are several ways to trap a "Ctrl-C" or "Ctrl-Break" keystroke
if you have cleanup to do before your program exits. I include one
way in the attached sample program, but I have tried the interrupt
intercept as described in Norton's "Programmers' Guide to the IBM
PC" as well. Both fail with the code below. Ctrl-C is NOT trapped
by either method. (Both Microsoft C v4.0 and Turbo C v1.0 behave
the same way; I'm sure MS-DOS is the culprit, since the "kbhit()"
routine just accesses the MS-DOS interrupt 06h).
It appears that the "Direct Console Interrupt 06 hex" has a wired-in
trap for "Ctrl-C." If that code arrives and then 06h is used to
ask if a keystroke is waiting, the program is immediately aborted.
I cannot find this behavior documented anywhere. It is a nifty
MS-DOS "feature" that will blow your program out of the water without
warning. Beware.
(I had to write an assembly-code keyboard intercept program just to
stop Ctrl-C, so if I sound irritable, that's why.)
--------------------------------------------------------------------
#include <stdio.h>
#include <dos.h>
main()
{
set_raw(); /* set MS-DOS to raw mode */
printf("Hit Ctrl-C twice.\n");
if(!kbhit()) /* if no keystroke waiting */
; /* do nothing */
bdos(7,0,0); /* wait for a keystroke */
if(!kbhit()) /* do it again ... */
;
bdos(7,0,0);
printf("ok so far, now once more ...\n");
while(!kbhit())
; /* watch until a keystroke appears */
bdos(7,0,0); /* try to get it */
printf("Never gets here.\n");
restore_raw();
exit(0);
}
/* Following code is by Dan Kegel, author of "nansi.sys" */
/* Use the IOCTL DOS function call to change stdin and stdout to raw mode.
* For stdin, this prevents MSDOS from trapping ^P, ^S, ^C, thus freeing us
* of ^P toggling 'echo to printer'.
* For stdout, this radically speeds up the output because there is no
* checking for these special characters in the input buffer whenever
* screen output is occurring.
* Note that only the stdin OR stdout ioctl need be changed since
* apparently they are handled as the same device.
* Thanks to Mark Zbikowski (markz@microsoft.UUCP) for helping me with
* this.
* --- This stolen from sources to the mighty game HACK ---
*/
#define DEVICE 0x80
#define RAW 0x20
#define IOCTL 0x44
#define STDIN fileno(stdin)
#define STDOUT fileno(stdout)
#define GETBITS 0
#define SETBITS 1
static unsigned old_stdin, old_stdout, ioctl();
/*--- set_raw() ----------
Call this to set raw mode; call restore_raw() later to restore
console to old rawness state.
--------------------------*/
set_raw()
{
old_stdin = ioctl(STDIN, GETBITS, 0);
old_stdout = ioctl(STDOUT, GETBITS, 0);
if (old_stdin & DEVICE)
ioctl(STDIN, SETBITS, old_stdin | RAW);
if (old_stdout & DEVICE)
ioctl(STDOUT, SETBITS, old_stdout | RAW);
}
restore_raw()
{
if (old_stdin)
(void) ioctl(STDIN, SETBITS, old_stdin);
if (old_stdout)
(void) ioctl(STDOUT, SETBITS, old_stdout);
}
static unsigned
ioctl(handle, mode, setvalue)
unsigned setvalue;
{
union REGS regs;
regs.h.ah = IOCTL;
regs.h.al = mode;
regs.x.bx = handle;
regs.h.dl = setvalue;
regs.h.dh = 0; /* Zero out dh */
intdos(®s, ®s);
return (regs.x.dx);
}
/*-- end of setraw.msc --*/
--
Ed Nather
Astronomy Dept, U of Texas @ Austin
{allegra,ihnp4}!{noao,ut-sally}!utastro!nather
nather@astro.AS.UTEXAS.EDUray@micomvax.UUCP (Ray Dunn) (02/26/88)
In article <10277@ut-sally.UUCP> nather@ut-sally.UUCP (Ed Nather) writes: >There are several ways to trap a "Ctrl-C" or "Ctrl-Break" keystroke >if you have cleanup to do before your program exits. I include one >way in the attached sample program, but I have tried the interrupt >intercept as described in Norton's "Programmers' Guide to the IBM >PC" as well. Both fail with the code below. Ctrl-C is NOT trapped >by either method. (Both Microsoft C v4.0 and Turbo C v1.0 behave >the same way; I'm sure MS-DOS is the culprit..... Using Microsoft C v3.0 and 4.0 I have *NEVER* had any problems trapping ^C using the "int (*signal(sig,func))()" feature with the manifest constant SIGINT, eg: previous_ctrl_c_handler = signal(SIGINT, my_ctrl_c_handler); This works perfectly, whether I want my_ctrl_c_handler to exit the program, to continue after some processing (including reading input), or even to redefine the ctrl C handler then continue. RTFM. This seems significantly simpler than the stuff Ed published & CERTAINLY does not require assembler! Ray Dunn. ..philabs!micomvax!ray