⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 keyint.c

📁 一个多输入的键盘中断处理程序
💻 C
字号:
/*====================================================================*/
/*                                                                    */
/*  NOTE: Ensure this program is compiled for LARGE model.            */
/*        Non-ANSI stuff is pertinent to Microsoft QuickC v2.5.       */
/*        Porting to another compiler should not be too hard!         */
/*                                                                    */
/*====================================================================*/

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

#define FALSE         0
#define TRUE          1

typedef unsigned char BOOL;
typedef unsigned char BYTE;

/* The following typedef represents the SCAN CODE values of all of the keys.  */
/* These values are independant of Shift, Alt and Ctrl key combinations. As   */
/* you can see, these special keys have a value of their own which allows for */
/* their detection...                                                         */

typedef enum
{
        GK_NULL                =0x00,
        GK_ESC                 =0x01,
        GK_1                   =0x02,
        GK_2                   =0x03,
        GK_3                   =0x04,
        GK_4                   =0x05,
        GK_5                   =0x06,
        GK_6                   =0x07,
        GK_7                   =0x08,
        GK_8                   =0x09,
        GK_9                   =0x0a,
        GK_0                   =0x0b,
        GK_MINUS               =0x0c,
        GK_EQUALS              =0x0d,
        GK_BS                  =0x0e,
        GK_TAB                 =0x0f,
        GK_Q                   =0x10,
        GK_W                   =0x11,
        GK_E                   =0x12,
        GK_R                   =0x13,
        GK_T                   =0x14,
        GK_Y                   =0x15,
        GK_U                   =0x16,
        GK_I                   =0x17,
        GK_O                   =0x18,
        GK_P                   =0x19,
        GK_OSBRACKET           =0x1a,
        GK_CSBRACKET           =0x1b,
        GK_ENTER               =0x1c,
        GK_CTRL                =0x1d,
        GK_A                   =0x1e,
        GK_S                   =0x1f,
        GK_D                   =0x20,
        GK_F                   =0x21,
        GK_G                   =0x22,
        GK_H                   =0x23,
        GK_J                   =0x24,
        GK_K                   =0x25,
        GK_L                   =0x26,
        GK_SEMICOLON           =0x27,
        GK_SCQUOTE             =0x28,
        GK_SOQUOTE             =0x29,
        GK_LSHIFT              =0x2a,
        GK_BACKSLASH           =0x2b,
        GK_Z                   =0x2c,
        GK_X                   =0x2d,
        GK_C                   =0x2e,
        GK_V                   =0x2f,
        GK_B                   =0x30,
        GK_N                   =0x31,
        GK_M                   =0x32,
        GK_COMMA               =0x33,
        GK_FULLSTOP            =0x34,
        GK_SLASH               =0x35,
        GK_RSHIFT              =0x36,
        GK_PRTSCRN             =0x37,
        GK_ALT                 =0x38,
        GK_SPACEBAR            =0x39,
        GK_CAPSLOCK            =0x3a,
        GK_F1                  =0x3b,
        GK_F2                  =0x3c,
        GK_F3                  =0x3d,
        GK_F4                  =0x3e,
        GK_F5                  =0x3f,
        GK_F6                  =0x40,
        GK_F7                  =0x41,
        GK_F8                  =0x42,
        GK_F9                  =0x43,
        GK_F10                 =0x44,
        GK_NUMLOCK             =0x45,
        GK_SCRLOCK             =0x46,
        GK_HOME                =0x47,
        GK_UP                  =0x48,
        GK_PAGEUP              =0x49,
        GK_GREYMINUS           =0x4a,
        GK_LEFT                =0x4b,
        GK_NUM5                =0x4c,
        GK_RIGHT               =0x4d,
        GK_GREYPLUS            =0x4e,
        GK_END                 =0x4f,
        GK_DOWN                =0x50,
        GK_PAGEDN              =0x51,
        GK_INSERT              =0x52,
        GK_DELETE              =0x53,
        GK_F11                 =0x57,
        GK_F12                 =0x58,
        GK_PRINTSCRN           =0x70,
        GK_PAUSEBREAK          =0x71
} GAME_KEY;

/*  Define any necessary globals. We should always declare variables that are */
/*  used within interrupt service routines as either global or static. It is  */
/*  NOT a good idea to allocate them dynamically off of the stack since we    */
/*  will not necessarily know the state of the stack at interrupt time...     */

BYTE        cbKeyTable[128];        /*  This will hold our key states:  */
                                    /*  0 = nothing, 1 = DOWN, 2 = up   */
                                    /*  The index into this array is    */
                                    /*  the scan code of the key...     */

BOOL        bChainOldISR=FALSE;     /*  Do we still use the original    */
                                    /*  keyboard interrupt routine?     */

void (interrupt *OldKeyISR)( void );
                                    /*  Function pointer to old ISR     */

/*  The interrupt service routine itself!  */

void interrupt KeyISR( void )
{
    /* NB: The following may look like overkill. In theory, a key is pressed  */
    /* and the scan code for said key should be retrieved from the keyboard   */
    /* controller. However, things aren't that simple! Certain keys, e.g.     */
    /* PrintScreen and Pause/Break, cause the keyboard controller to send a   */
    /* sequence of bytes back rather than a single scan code. These need to   */
    /* be filtered and interpreted - otherwise it could cause the wrong key   */
    /* pressed to be recorded...   End of lecture <g>                         */

    static BYTE     scan,           /*  Used to read the scan code from the keyboard  */
                    updflag,        /*  Used to indicate if we have a 'real' key      */
                    lctrl=0;        /*  Used to record the last 'special' key scan    */

    scan    = inp(0x60);            /*  Ask keyboard controller for scan code  */
    updflag = TRUE;
    switch( scan )
    {
        case 224:
        case 225:
          lctrl   = scan;
          updflag = FALSE;          /*  Special, don't update this time!  */
          break;
        default:
          if ( lctrl==224 )
          {
              if ( (scan&0x7f)==42 ) updflag=FALSE; else
              {
                  if ( (scan&0x7f)==55 ) scan=GK_PRINTSCRN^(scan&0x80);
              }
          }
          else if ( lctrl==225 )
          {
              if ( (scan&0x7f)==29 ) updflag=FALSE; else
              {
                  if ( (scan&0x7f)==69 ) scan=GK_PAUSEBREAK^(scan&0x80);
              }
          }
    }
    if ( updflag )
    {
        /*  Yippee! Update our table. High bit of scan code says its released!  */

        cbKeyTable[scan&0x7f]   = (scan&0x80)?2:1;
        lctrl                   = 0;
    }

    /*  Do we call original?  */

    if ( !bChainOldISR )
    {
        /*  If we don't call the original ISR, we must service this interrupt  */
        /*  ourselves. The following tells the keyboard controller and the     */
        /*  Programmable Interrupt Controller (PIC) that we are done...        */

        _asm
        {
            in   al, 61H
            mov  ah, al
            or   al, 80H
            out  61H, al
            mov  al, ah
            out  61H, al
            mov  al, 20H
            out  20H, al
        }
    }
    else _chain_intr( OldKeyISR );
}

/*========================= main program ====================================*/

void main( void )
{
    int         i, j;

    /*  Start off by getting the address of the old interrupt handler and  */
    /*  setting up our own                                                 */

    OldKeyISR = _dos_getvect( 0x09 );
    _dos_setvect( 0x09,KeyISR );

    /*  The global variable bChainOldISR is subsequently used to control  */
    /*  whether the original keyboard handler is called after our own.    */
    /*  The reason for this might not be immediately apparent but within  */
    /*  normal game play the original routine is not required. However,   */
    /*  once the player's lives have run out and the game is over he'll   */
    /*  no doubt want to be added to some hall of fame (high score table) */
    /*  type thing. It is within this phase of the game that the original */
    /*  handler is desirable since it handles upper/lower case and all of */
    /*  the other shifted stuff. Furthermore, we can resort to using the  */
    /*  simple getch() or whatever to use within our own edited input     */
    /*  routine...                                                        */

    bChainOldISR = FALSE;

    printf( "\n\nMultiple key press handler demo\n===============================\n\nPress ESCape to quit\n\n" );

    /*  Initialise our key state table  */

    _asm    cli                     /*  Disable interrupts for this bit!!  */
    memset( cbKeyTable,0x00,128 );
    _asm    sti                     /*  Re-enable interrupts again!        */

    /*  Display keys pressed/released  */

    while ( cbKeyTable[GK_ESC]!=0x01 )
    {
        /*  Quick linear scan of table, it's only a demo... <g>  */

        for ( i=0; i<128; i++ )
        {
            switch( cbKeyTable[i] )
            {
                case 0x01:
                    printf( "Key %02X is down\n",i );
                    cbKeyTable[i] = 0x00;               /*  Prevent print at next interation  */
                    break;
                case 0x02:
                    printf( "Key %02X is up\n",i );
                    cbKeyTable[i] = 0x00;
            }
        }
    }

    /*  ESCape has been pressed, we MUST re-install the original keyboard  */
    /*  handler BEFORE we terminate the program. If we don't we are sure   */
    /*  to hang the machine once we get back to DOS...                     */

    _dos_setvect( 0x09,OldKeyISR );

    printf( "\n\nCoded by CyberFrog 8:)\n" );
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -