How to Trap CTRL+C and CTRL+BREAK Keystrokes

ID: Q86558


The information in this article applies to:


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 query words: kbinf 5.10 6.00 6.00a 6.00ax 7.00 1.00 1.50


Keywords          : kb16bitonly 
Version           : 
Platform          : 
Issue type        : 

Last Reviewed: July 30, 1999