Creating your own Interrupt Handle in C
See below for a keyboard interrupt handler to allow more than one keystroke at a time.
To do this, we must pick an Interrupt that is called quite often. The "TIME KEEPER" interrupt (1CH) is called about 18.2 times a second, so let's use it?
C will do all of the dirty work for us if we use the _interrupt keyword.
All we have to do is declare it like a normal function/sub (notice the _interrupt _far keywords).
void _interrupt _far Timer(void) {
}
NOTE: Inside this interrupt call we must be very careful on what we do. We can not call major interrupts or procedures. The simpler the better.
Now that we have our ISR written, we need to install it. We must install it and still allow DOS to run the original interrupt. (If DOS doesn't allow INT 1Ch to run, you will mess up allot of things....)
To install it:
void (_interrupt _far old_isr) ();
old_isr = _dos_getvect(0x1C);
_dos_setvect(0x1C,Timer);
That's it. Once you are done with your program, on exit you must uninstall it.
_dos_setvect(0x1C, old_isr);
I got this info from "Tricks of the Game Programming Gurus". This is not a plug, but you should get this book. It has complete source on how to create a communications link for online gaming using this procedure.
The following code, when ran, will noticeably do nothing. But press the left ALT key and notice a smiley face appear in the top left corner of the screen. Release the key and it will restore the original character. Quite simple, but it gets the point across.
#include "dos.h"
#define ISLEFTALT (*(unsigned char _far *)0x00400018)
#define OURSCRNPOS (*(unsigned char _far *)0xB8000000)
char orgchar;
void (_interrupt _far *old_isr)();
void _interrupt _far Timer() {
if ((ISLEFTALT & 0x02) != 0)
OURSCRNPOS = 0x01;
else
OURSCRNPOS = orgchar;
}
int main(int argc, char *argv[]) {
printf("\nPress the ESC key to exit"
"\nPress the Left ALT key");
orgchar = OURSCRNPOS;
old_isr = _dos_getvect(0x1C);
_dos_setvect(0x1C, Timer);
while (getch() != 0x1B); {}
_dos_setvect(0x1C, old_isr);
return 0;
}
Keyboard ISR demo
This handler example shows how to check for more than one keystroke at a time. For example; Have you ever wanted to check for two arrow keys pressed at the same time and only get the first one pressed? This example will show you how to test and use more than one arrow key at a time.
#include "dos.h"
#include "graph.h"
#define SDAMOUNT 0x2FFFF
#define COLOR 0x05
#define KEYBOARD_INT 0x09
#define KEY_BUFFER 0x60
#define KEY_CONTROL 0x61
#define INT_CONTROL 0x20
#define MAKE_RIGHT 77
#define MAKE_LEFT 75
#define MAKE_UP 72
#define MAKE_DOWN 80
#define BREAK_RIGHT 205
#define BREAK_LEFT 203
#define BREAK_UP 200
#define BREAK_DOWN 208
#define INDEX_UP 0
#define INDEX_DOWN 1
#define INDEX_RIGHT 2
#define INDEX_LEFT 3
void (_interrupt _far *Old_Isr)();
unsigned char far *video_buffer = (char far *)0xA0000000L;
int raw_key;
int key_table[4] = {0,0,0,0};
void _interrupt _far New_Key_Int() {
_asm {
sti ; re-enable interrupts
in al,KEY_BUFFER ; get the key that was pressed
xor ah,ah ; zero out upper 8 bits of AX
mov raw_key,ax ; store the key in global
in al,KEY_CONTROL ; set the control register
or al,82h ; set the proper bits to reset the FF
out KEY_CONTROL,al ; send the new data back to the control register
and al,7Fh
out KEY_CONTROL,al ; complete the reset
mov al,20h
out INT_CONTROL,al ; re-enable interrupts
}
switch(raw_key) {
case MAKE_UP: key_table[INDEX_UP] = 1;
break;
case MAKE_DOWN: key_table[INDEX_DOWN] = 1;
break;
case MAKE_RIGHT: key_table[INDEX_RIGHT] = 1;
break;
case MAKE_LEFT: key_table[INDEX_LEFT] = 1;
break;
case BREAK_UP: key_table[INDEX_UP] = 0;
break;
case BREAK_DOWN: key_table[INDEX_DOWN] = 0;
break;
case BREAK_RIGHT: key_table[INDEX_RIGHT] = 0;
break;
case BREAK_LEFT: key_table[INDEX_LEFT] = 0;
break;
default:
break;
}
}
int main(int argc, char *argv[]) {
int x=160, y=100;
unsigned long slowdown = 0;
_setvideomode(_MRES256COLOR);
Old_Isr = _dos_getvect(KEYBOARD_INT);
_dos_setvect(KEYBOARD_INT, New_Key_Int);
while(raw_key != 1) {
slowdown++;
if (slowdown > SDAMOUNT) {
slowdown = 0;
if (key_table[INDEX_RIGHT]) x++;
if (key_table[INDEX_LEFT]) x--;
if (key_table[INDEX_UP]) y--;
if (key_table[INDEX_DOWN]) y++;
video_buffer[((y<<8) + (y<<6)) + x] = COLOR;
}
}
_dos_setvect(KEYBOARD_INT, Old_Isr);
_setvideomode(_DEFAULTMODE);
}