How to Trap CTRL+C and CTRL+BREAK Keystrokes

Last reviewed: July 17, 1997
Article ID: Q86558
5.10 6.00 6.00a 6.00ax 7.00 | 1.00 1.50
MS-DOS                      | WINDOWS
kbprg

The information in this article applies to:

  • The C Run-time (CRT) included with:

        - Microsoft C for MS-DOS, versions 5.1, 6.0, 6.0a, and 6.0ax
        - Microsoft C/C++ for MS-DOS, version 7.0
        - Microsoft Visual C++ for Windows, versions 1.0 and 1.5
    

SUMMARY

The program below demonstrates how to revector interrupts to your own service routine. Also, it shows how to stop the ^C character from appearing on the screen when CTRL+C is pressed.

MORE INFORMATION

The sample program shows how to trap the CTRL+C and CTRL+BREAK key combinations. The program waits for a keystroke. When a key is pressed, the program checks to see if the keystroke is a CTRL+C or CTRL+BREAK key combination. If the keystroke is CTRL+BREAK, nothing happens. If the keystroke is CTRL+C, a message is displayed and the keyboard buffer is dumped to the screen in hexadecimal values. If the keystroke is neither CTRL+C nor CTRL+BREAK, just the keyboard buffer is dumped to the screen.

Sample Code

/* Compile options needed: None
*/

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

   #define HIBYTE(x) ((unsigned char) (((unsigned) x >> 8) & 0x00FF))
   #define HIWORD(x) \
                 ((unsigned) (((unsigned long) x >> 16) & 0x0000FFFF)
   #define LOBYTE(x) ((unsigned char) ((unsigned) x & 0x00FF))
   #define LOWORD(x) ((unsigned) ((unsigned long) x & 0x0000FFFF))

   #define BITSET(x, n) ( (((unsigned) x >> n) & 0x0001) == 1 ? 1 : 0)

   #define AND(a, b)  ( a &= b )  /* a = a AND b */
   #define OR(a, b)   ( a |= b )  /* a = a OR  b */
   #define XOR(a, b)  ( a ^= b )  /* a = a XOR b */

   #define SEMINIT(s)  ( XOR(s, s) )
   #define SEMSET(s)   ( s ? 1 : 0 )

   #define INT09   0x0009      /* Keyboard interrupt number */
   #define INT1B   0x001B      /* CTRL+C interrupt number */
   #define INT23   0x0023      /* CTRL+BREAK interrupt number */

   #define ESC     0x1B        /* ASCII escape code */
   #define SPACE   0x20        /* ASCII space  code */
   #define cScan   0x2E        /* Scan code for the "C" key */
   #define CtrlOff 0xFB        /* CTRL+C bit mask */
   #define CtrlOn  0x04        /* CTRL+C bit mask */
   #define Value   0x001F      /* Replace ^C with this value */

   #define KBDMEM  0x0000041C  /* Keyboard buffer tail
                                  pointer address */

   #define KBDBUF  0x0000041E  /* Keyboard buffer address */
   #define KBDFLAG 0x00000417  /* Keyboard flag byte address */

   #define KB_DATA 0x0060      /* Keyboard port address  */
   #define ADDRESS unsigned far *

   /*========================================================*/
   /*  Functions pointers */

   void (interrupt far *KbdPtr)(void);  /* Points to keybrd routine */
   void (interrupt far *BrkPtr)(void);  /* Points to break routine  */

   void (interrupt far *OldInt09)(void); /* Save old kbd handler */
   void (interrupt far *OldInt1B)(void); /* Save old ^C  handler */
   void (interrupt far *OldInt23)(void); /* Save old brk handler */

   /*========================================================*/

   ADDRESS KbdBuf;
   ADDRESS KbdCtrl;
   ADDRESS KbdTail;

   void main (void);
   void KbdHexDump( ADDRESS str );

   /*=========================================================*/
   /* Interrupt service routines */

   void interrupt far Int09();
   void interrupt far Int1B();
   void interrupt far Int23();

   /*=========================================================*/

   unsigned sem;  /* ^C was pressed then sem=1, else sem=0 */
   unsigned ch;
   unsigned cell; /* Data from kbd port 60h */

   void
   main (void)
   {
      unsigned i;

      OldInt09 = _dos_getvect( INT09 );
      OldInt1B = _dos_getvect( INT1B );
      OldInt23 = _dos_getvect( INT23 );

      KbdPtr = Int09;
      _dos_setvect( INT09, KbdPtr );

      BrkPtr = Int1B;
      _dos_setvect( INT1B, BrkPtr);

      BrkPtr = Int23;
      _dos_setvect( INT23, BrkPtr );

      KbdTail  = (ADDRESS) KBDMEM;
      KbdBuf   = (ADDRESS) KBDBUF;
      KbdCtrl  = (ADDRESS) KBDFLAG;

      for(i = 0; i < 16; i++)
         KbdBuf[i] = (unsigned) (0x3900 | SPACE);

      SEMINIT(sem);  /* Clear semaphore */
      XOR(ch, ch);   /* ch=0  */

      while( LOBYTE(ch) != ESC )
      {
         ch = getch();
         if ( SEMSET(sem) )
             printf("\nCtrl-C key was pressed!\n");
             KbdHexDump( KbdBuf );
      }

      _dos_setvect( INT09, OldInt09 );
      _dos_setvect( INT1B, OldInt1B );
      _dos_setvect( INT23, OldInt23 );
   }

   void
   KbdHexDump( ADDRESS str )
   {
      unsigned  j;

      printf("\n");
      for( j=0; j < 16; j++ )
      {
         if ( LOBYTE(str[j]) < 15 )
            printf("0");
         if ( str[j] == Value )
            printf("03 ");
         else
            printf("%x ", LOBYTE(str[j]));
      }
      printf("     ");
      for( j=0; j < 16; j++ )
      {
         if ( LOBYTE(str[j]) < SPACE )
            printf("%c", '.');
         else
            printf("%c", LOBYTE(str[j]));
      }
      printf("\n");
   }

   /*========================================================*/
   /* Interrupt service routines */

   void interrupt far
   Int09( void )
   {
      unsigned indx;

      _disable();

      cell = inp( KB_DATA );
      if ( BITSET(*KbdCtrl, 2) && LOBYTE(cell) == cScan )
      {
         sem = 1;
         indx = ( *KbdTail - LOBYTE(LOWORD(KbdBuf)) ) / 2;
         AND( *KbdCtrl, CtrlOff );
      }
      else
         XOR(sem, sem);

      OldInt09();

      if ( SEMSET(sem) )
      {
         OR( *KbdCtrl, CtrlOn );
         KbdBuf[indx] = Value;
      }

   }

   void interrupt far
   Int1B(void)
   {
       /* New home for CTRL+C     */
   }

   void interrupt far
   Int23(void)
   {
       /* New Home for CTRL+BREAK */
   }


Additional reference words: kbinf 5.10 6.00 6.00a 6.00ax 7.00 1.00 1.50
KBCategory: kbprg
KBSubcategory: CRTIss
Keywords : kb16bitonly


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: July 17, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.