📄 keyint.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 + -