[comp.os.msdos.programmer] Disabling CTRL-C, in Turbo-C - not via TSR.

waynet@kit.tek.com (Wayne Turner) (04/11/91)

In article <mazz.671291088@jupiter.newcastle.edu.au> mazz@jupiter.newcastle.edu.au (Richard Mazzaferri) writes:
>I'm developing an application which runs in EGA graphics mode, and also
>requires that CTRL-BREAK be used by the user to interrupt ( via my INT 0x24
>handler ) when required.  This works well, except that CTRL-C also causes
>the handler to be invoked, _BUT_ prints the characters "^C" to something
>like stdout or stderr before doing so.
>
>    Now, I don't care whether or not CTRL-C invokes INT 0x24 as long as my 
>screen _doesn't get corrupted_ !  To this end I have ANSI.SYS redefine
> ...

You must mean INT 0x23 not 0x24 as 0x24 is for the critical error interrupt.
If you really are hooking 0x24 and not 0x23 you should make this change
first.

However this still won't solve your problem :-(.  I've tried three
methods to prevent corruption of graphics mode screens when ctrl-C is hit
(note I always hook interrupts 0x1B and 0x23 with handlers that do
nothing but an IRET). Method 1 was to put stdin and stdout into
raw (intead of cooked) mode (using a DOS IOCTL call, INT 0x21 Function 0x44 
Subfunction 01) and hoping that DOS wouldn't echo the ctrl-C.  This *almost* 
worked. 
Somehow stdin got returned to cooked mode as a side effect of some other
DOS or BIOS call which I made after the IOCTL call -- I never did have
the patience (or the time) to track this down.

Method 2 was to actually install my own handler for the keyboard interrupt
but my lack of knowledge about programming the keyboard controller caused
me some problems in this area. (BTW, can anyone recommend a good source
of information for writing keyboard handlers under DOS?).

Method 3 worked. I used the standard library routine dup2 to redirect
stdout and stderr to a file when my application is in graphics mode,
thus preventing screen corruption when control-C is hit (or when
some run-time library routine takes an error and decides to do a
printf). When I exit graphics mode I delete the temp file.
The following sample program demonstrates the idea for stdout (written
using Zortech C++ but I expect it would work with Turbo C as well). In
fact it was suggested to me by someone on the net...

#include <string.h>
#include <stdio.h>
#include <dos.h>

char *temp_file_string1 = "This goes to temp.file (stdout redirected)\n";
char *stdout_string = "This goes to stdout\r\n";

void main()
    {
    int newout, oldout;
    char *tempfile;
    oldout = dup(1); 
    if ( (tempfile = tmpnam(NULL)) == NULL )
        { perror("can't open temp file"); exit(1); }
    else
        printf("Opening temp file %s for redirection\n", tempfile);
    newout = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0777);
    dup2(newout, 1);
    write(1, temp_file_string1, strlen(temp_file_string1));
    dup2(oldout, 1);
    write(1, stdout_string, strlen(stdout_string));
    }

I guess this whole thing with handling ctrl-C/break under DOS is final
verification that we spend 95% of our time working on 5% of the software
(or however the saying goes :-).  

Hope this helps.

--
Wayne Turner
Tektronix, Inc.
Redmond, Oregon
waynet@kit.CNA.TEK.COM

mazz@jupiter.newcastle.edu.au (Richard Mazzaferri) (04/12/91)

waynet@kit.tek.com (Wayne Turner) writes:

>In article <mazz.671291088@jupiter.newcastle.edu.au> mazz@jupiter.newcastle.edu.au (Richard Mazzaferri) writes:
[ trying to prevent "^C" from reaching screen, while still allowing CTRL-BREAK
  to generate it's interrupt - I said INT0x24 when I should have 0x23. ]

>You must mean INT 0x23 not 0x24 as 0x24 is for the critical error interrupt.
>If you really are hooking 0x24 and not 0x23 you should make this change
>first.

Yes, sorry - I've also written my critical event handler for INT 0x24, and I'm
starting to get memory glitches from all those interrupt handlers - forgetting
which one does what.  


[ Suggestion 1 : Use IOCTL to put stdin into raw mode.  ( I'd already tried 
  this. )  Some other DOS/BIOS call apparently puts stdin back into cooked 
  mode.  ( I've never tried to track down how/why either. ) ]

[ Suggestion 2 : install own handler for keyboard interrupt.  Wayne had
  problems.  ( I was hoping not to do this. )  Anyone ever done it? ]

[ Suggestion 3 : redirect stderr/stdout to a tempfile using dup2.
  ( I thought of doing this and thought - No, there must be a better way. ) ]

Thanks for the ideas and shared experience.  If no-one comes up with a better
idea I guess this will have to be implemented.  Does anyone actually know how
ANSI.SYS redefines keys?

    Mazz. 
-- 
-----------------------------------------------------------------
Richard Mazzaferri,   Comp.Sc. Ph.D. student,  Uni. of Newcastle,
  Ph (049) 602574    mazz@nucs.newcastle.edu.au     Australia.
-----------------------------------------------------------------

iisakkil@vipunen.hut.fi (Mika R Iisakkila) (04/12/91)

One easy method is to simply close stdout. If you still need it
somewhere, you might dup() it into some other descriptor before
closing the original stdout.

teittinen@cc.helsinki.fi (04/14/91)

In article <mazz.671428317@jupiter.newcastle.edu.au>,
mazz@jupiter.newcastle.edu.au (Richard Mazzaferri) writes:
> 
> [ Suggestion 2 : install own handler for keyboard interrupt.  Wayne had
>   problems.  ( I was hoping not to do this. )  Anyone ever done it? ]

I can't believe it.  Nobody has yet posted code to do this.  Ok, I guess
it is my turn to give source to net.  The following is a group of
functions for TurboC to disable ctrl-c totally, nothing will come up on
the screen.  Or actually, you can change the ctrl-c to any scan code you
want.  But see the listing, it is quite well commented.  Hereby I
declare the following source file public domain :-).  You can use it,
but don't claim it to be yours.  Keep the comments in it. 

-------8<-------clip here-------8<-------
/***************************************************************************/
/*                                                                         */
/*  Module CtrlC                                                           */
/*                                                                         */
/*  Filename: CTRLC.C                                                      */
/*  Date:     18.09.1989                                                   */
/*  Version:  1.0                                                          */
/*  Author:   Marko Teittinen                                              */
/*                                                                         */
/*  This module contains functions to disable ctrl-c checking              */
/*                                                                         */
/*  This file is public domain, you may copy, use and modify it, but       */
/*  don't claim it to be yours. Don't remove comments, and comment your    */
/*  modifications.                                                         */
/*                                                                         */
/***************************************************************************/
/* Include files */

#include <dos.h>

/***************************************************************************/
/* Type definitions */

typedef unsigned int	word;
typedef unsigned char	byte;

/***************************************************************************/
/* Constant definitions */

#define cScan   0x2E	/* Scan code for the "C" key    */
#define CtrlOff 0xFB	/* Ctrl-C bit mask              */
#define CtrlOn  0x04	/* Ctrl-C bit mask              */

/***************************************************************************/
/* Macro definitions */

/* Get lower byte or word of a variable */
#define LOBYTE(x)	((byte)((word) x & 0x00FF))
#define LOWORD(x)	((word)((unsigned long) x & 0x0000FFFF))

/* Test if specified bit is set */
#define BITSET(x,n)	((word)x & (0x0001 << n))

/***************************************************************************/
/* Function prototypes and short documentation */

void DisableCtrlC(word ScanCode);
/* Disables Ctrl-C interrupts */
/* Given ScanCode will replace every Ctrl-C pressed */

void EnableCtrlC(void);
/* Restores original keyboard, Ctrl-C and Ctrl-Break interrupts */

/***************************************************************************/
/* Static variables */

/* Ptr to original kbd handler */
static void (interrupt far *OrigInt09)(void);
/* Ptr to original ^C  handler */
static void (interrupt far *OrigInt1B)(void);
/* Ptr to original brk handler */
static void (interrupt far *OrigInt23)(void);

/* Pointer to keyboard buffer */
static word far *KbdBuf = (word far *)0x0040001EL;
/* Pointer to keyboard control flag byte */
static word far *KbdCtrl = (word far *)0x00400017L;
/* Pointer to keyboard buffer tail pointer */
static word far *KbdTail = (word far *)0x0040001CL;

/* Value to replace Ctrl-C in keyboard buffer */
static word Value;

/***************************************************************************/
/* New keyboard interrupt */

static void interrupt far Keyboard(void)
{
	word Data,	/* Data from Kbd port 60h */
	     CtrlC,	/* CtrlC = 1, if ^C was pressed else CtrlC = 0 */
	     Indx;

	disable();

	/* Read the data from kbd port 0x60 */
	Data = inp(0x60);

	/* Test if Ctrl is pressed and C is pressed */
	if (BITSET(*KbdCtrl,2) && LOBYTE(Data) == cScan)
	{
		/* Ctrl-C was pressed */
		CtrlC = 1;
		/* Get the current position of the keyboard buffer */
		Indx = (*KbdTail - LOBYTE(LOWORD(KbdBuf))) / 2;
		/* Lie to original interrupt that Ctrl was not pressed */
		*KbdCtrl &= CtrlOff;
	}
	else
		CtrlC = 0;

	/* Call the original keyboard interrupt */
	OrigInt09();

	if (CtrlC)
	{
		/* Restore the Ctrl-flag in keyboard control flag */
		*KbdCtrl |= CtrlOn;
		/* Replace Ctrl-C with the value defined */
		KbdBuf[Indx] = Value;
	}
}

/***************************************************************************/
/* New interrupt for Ctrl-Break and Ctrl-C */

static void interrupt far DoNothing(void)
{
	/* Do nothing */
}

/***************************************************************************/
/* Disable Ctrl-C interrupts */

void DisableCtrlC(word ScanCode)
{
	OrigInt09 = getvect(0x09);  /* Save original keyboard interrupt   */
	OrigInt1B = getvect(0x1B);  /* Save original Ctrl-C interrupt     */
	OrigInt23 = getvect(0x23);  /* Save original Ctrl-Break interrupt */

	setvect(0x09, Keyboard);   /* Install our own keyboard interrupt   */
	setvect(0x1B, DoNothing);  /* Install our own Ctrl-C interrupt     */
	setvect(0x23, DoNothing);  /* Install our own Ctrl-Break interrupt */

	Value = ScanCode;
}

/***************************************************************************/
/* Enable Ctrl-C interrupts */

void EnableCtrlC(void)
{
	setvect(0x09, OrigInt09);  /* Restore original keyboard interrupt   */
	setvect(0x1B, OrigInt1B);  /* Restore original Ctrl-C interrupt     */
	setvect(0x23, OrigInt23);  /* Restore original Ctrl-Break interrupt */
}

/***************************************************************************/
/* End of file */
-------8<-------clip here-------8<-------
-- 
E-Mail: teittinen@finuh.bitnet               ! "Studying is the only way
        teittinen@cc.helsinki.fi             !  to do nothing without
Marko Teittinen, student of computer science !  anyone blaming you" -me