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.EDU
ray@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