[comp.os.msdos.programmer] Need help:Ctrl-C and Ctrl-Break

dennisw@tekigm2.MEN.TEK.COM (Dennis G Ward) (07/31/90)

I've got a truly great program underway, but I can't stand to let the
user break out of it with Ctrl-C or Ctrl-Break, and I need keyboard
input.  What's the trick(s)?
-- 
Dennis Ward    dennisw@tekigm2.MEN.TEK.COM    C1-820    (206)253-5428

nmouawad@water.waterloo.edu (Naji Mouawad) (07/31/90)

In article <9627@tekigm2.MEN.TEK.COM> dennisw@tekigm2.MEN.TEK.COM (Dennis G
Ward) writes:

>I've got a truly great program underway, but I can't stand to let the
>user break out of it with Ctrl-C or Ctrl-Break, and I need keyboard
>input.  What's the trick(s)?
>-- 
>Dennis Ward    dennisw@tekigm2.MEN.TEK.COM    C1-820    (206)253-5428

The best method I know of, is to trap interrupt 09h. Write a little routine
that does the following:
   -checks if the scan code of a key corresponds to the break key or 
    the key with letter 'C'. The scan code, in case you don't know is
    the number that the keyboard processor sends, each time a key is pressed.
    These are listed in several books.
   -If that's not the case, jump to the adress of the interrupt 9h.
   -if it is, check the state of the Ctrl key (bit number 4 I think of byte
    0:40H, again you can find this info in Peter Norton's book or the
    Programmer's Solver etc.) If Ctrl is down, ignore the key and exist, if
    it's up pass it onto the old interrupt 09h.

Prefix interrupt 09 with this routine. That is set the address of interrupt 09h to the Segment:offset of
your routine. 

In C and Pascal there are various ways of replacing an interrupt.
You can also take a look at any resident utility in PC Mag. They do it all
the time.

Maybe C or Pascal has a simple function to do so, I don't remember.

Good Luck.

-- 
         ---------------+-------------------------------------------
        | Naji Mouawad  |       nmouawad@water.uwaterloo.edu        |
        |  University   |-------------------------------------------|
        | Of Waterloo   | "Thanks God, we cannot prove He Exists."  |

fs-info@sbsvax.cs.uni-sb.de (c/o Peter Gaal) (07/31/90)

In article <1990Jul31.023745.1116@water.waterloo.edu>, nmouawad@water.waterloo.edu (Naji Mouawad) writes:
> In article <9627@tekigm2.MEN.TEK.COM> dennisw@tekigm2.MEN.TEK.COM (Dennis G
> Ward) writes:
> 
> >input.  What's the trick(s)?
> >-- 
> >Dennis Ward    dennisw@tekigm2.MEN.TEK.COM    C1-820    (206)253-5428
> 
> The best method I know of, is to trap interrupt 09h. Write a little routine
> that does the following:
> ["little" deleted]

Hmm, with your suggestion, you have to do scancode processing yourself,
but why shouldn't MSDOS do the work for you ?

The following should work:
  Choose a global flag variable, say c_break
  Replace INT09h with the following (meta)code:
    call original int09h
    look if c_break is true
      if yes,
        get the next "keystroke" (getch() in C is ok here!), this overreads
        the break scancode
        reset the c_break flag
        if you want, set some other flag to signal c_break was hit
      else
        do nothing
    and complete
  When the original int09h runs and detects ctrl-break or ctrl-C was pressed,
  it calls one of the DOS ctrl-break handlers (int19h or int24h, but please
  do not beat me if that's wrong, I have no doc handy...) which normally
  set a DOS internal flag which causes DOS to terminate your program on
  thenext int21h.
  So the only thing which remains to do is to replace these two ctrl-break
  interrupts with your own handler, simply setting the c_break flag inspected
  by your own keyboard handler.
  It is important NOT to call the original ctrl-break handlers from your
  own, because otherwise DOS would show up with a nasty "^C" string later.

I hope I go it half right...

Bye
  Patrick

feit@cs.odu.edu (Mark A. Feit) (08/01/90)

In article <5717@sbsvax.cs.uni-sb.de> fs-info@sbsvax.cs.uni-sb.de (c/o Peter Gaal) writes:


   In article <1990Jul31.023745.1116@water.waterloo.edu>, nmouawad@water.waterloo.edu (Naji Mouawad) writes:
   > In article <9627@tekigm2.MEN.TEK.COM> dennisw@tekigm2.MEN.TEK.COM (Dennis G
   > Ward) writes:
   > 
   > >input.  What's the trick(s)?
   > >-- 
   > >Dennis Ward    dennisw@tekigm2.MEN.TEK.COM    C1-820    (206)253-5428
   > 
   > The best method I know of, is to trap interrupt 09h. Write a little routine
   > that does the following:
   > ["little" deleted]

   Hmm, with your suggestion, you have to do scancode processing yourself,
   but why shouldn't MSDOS do the work for you ?
   [Pseudocode Obliterated...  MS-DOS doesn't work for me.  Ptui!]

A quick solution in C that lets the runtime library do the dirty work:

-------------8<-----Trim Here------------------

	BOOL	break_flag = FALSE;

void ctrl_break( void )
{
	break_flag = TRUE;

	/* Do as little as possible in here...  DOS gets in a strange state
	   during interrupts and doesn't take kindly to I/O being done.*/

	signal( SIGINT, ctrl_break );
}

void ctrl_break_handler( void )	/* Or whatever you need... */
{
	signal( SIGINT, SIG_IGN );	/* Shut ^Break off completely...
					   Don't want recursive calls. */

	printf( "\n\nWHAM!  Ctrl-Break!\n\n" );
	break_flag = FALSE;

	/* Do your own thing in here */

	signal( SIGINT, ctrl_break );	/* Reset things */
}

main( int argc, char **argv )
{
	signal( SIGINT, ctrl_break );

	for ( ; ; ) {	/* forever */

		/* Your code here */

		if ( break_flag )
			handle_ctrl_break();

	}
}

-------------8<-----Trim Here------------------

A couple of suggestions:

1.  Implement the code to check on break_flag inside of something that
gets run very often.  For example, I have a routine that gets called
over and over while the system is waiting for a key.  This also means
that you can finish up critical operations and _then_ check for a
break.

2.  If you want to get rid of that nasty ^C on the screen, the only
way I can find is to freopen() stdout to NUL.  There's no other way as
far as I can see without horking the keyboard interrupt (messy) or
modifying your BIOS (out of the question).  If you're using some
screen I/O package, odds are it uses its own direct reads and writes
and stdout just sits idle anyway.


						- Mark

................................... ................................... 
: Mark A. Feit                     : feit@cs.odu.edu                  :
: Old Dominion University CS Dept. : feit@xanth.UUCP                  :
: Norfolk, Virginia, U.S.A., Earth : "So where's my lunch, anyway?"   :
................................... ................................... 
  Y
:)8 G-G-G-D-E-C

--

						- Mark

................................... ................................... 
: Mark A. Feit                     : feit@cs.odu.edu                  :
: Old Dominion University CS Dept. : feit@xanth.UUCP                  :
: Norfolk, Virginia, U.S.A., Earth : "So where's my lunch, anyway?"   :
................................... ................................... 
  Y
:)8 G-G-G-D-E-C

alex@bilver.UUCP (Alex Matulich) (08/04/90)

In article <9627@tekigm2.MEN.TEK.COM> dennisw@tekigm2.MEN.TEK.COM (Dennis G Ward) writes:
>I've got a truly great program underway, but I can't stand to let the
>user break out of it with Ctrl-C or Ctrl-Break, and I need keyboard
>input.  What's the trick(s)?

The most PORTABLE way to do it (and it works well too) is to use the
signal() function in the standard library, like so:

---------------------------------------
#include <signal.h>

void ctrlctrap(i)
int i;
{
signal(SIGINT, ctrlctrap);  /* make sure next ctrl-break comes back here */
}


void main()
{
signal(SIGINT, ctrlctrap);  /* activate ctrl-c/ctrl-break trap handler */

etc....
--------------------------------------

Every time ctrl-c or ctrl break is pressed, the funtion ctrlctrap() will
be invoked, and will reset the pointer for the next ctrl-c to call
ctrlctrap() again.

This has worked on every ANSI compiler I have tried it on (Lattice,
Microsoft, unix compilers, etc.)


-- 
     ///  Alex Matulich
    ///  Unicorn Research Corp, 4621 N Landmark Dr, Orlando, FL 32817
\\\///  alex@bilver.UUCP    ...uunet!tarpit!bilver!alex
 \XX/  From BitNet try: IN%"bilver!alex@uunet.uu.net"