|
-
Mar 18th, 2002, 06:48 PM
#1
Thread Starter
Lively Member
Keyboard interrupt handler help
Well most people who have ever tried to make a game or anything related to that know that the standard functions for keyboard input (getch(), bioskey(0), maybe more...) just s**k. I've looked at many tutorials about replacing the keyboard interrupt handler with one of your own, but could never fully understand it. If anyone could explain the whole process in detail or point me to a good tutorial about it (something that's easy to understand and is in c++ cause most that I found were in asm), I'd appreciate it.
-
Mar 19th, 2002, 11:36 AM
#2
I can tell you all that I know. That is not much, but a start.
DJGPP provides some helper functions, here is code that set's a keyboard interrupt (written for the game Jump'n'Bump, commented by me).
Code:
struct { // information for the keyboard handler
char enabled; // hook enabled
} keyb_handler_info;
volatile char keyb[256]; // stores if a key is pressed (by ASCII code)
// array to map scancodes to ascii codes, can be indexed by one byte
unsigned char scancode2ascii[256] = {
0, 0, 49, 50, 51, 52, 53, 54, 55, 56,//0-9
57, 48, 45, 0, 0, 0, 113, 119, 101, 114,//10-19
116, 121, 117, 105, 111, 112, 0, 0, 0, 0,//20-29
97, 115, 100, 102, 103, 104, 106, 107, 108, 0,//30-39
0, 0, 0, 0, 122, 120, 99, 118, 98, 110,//40-49
109, 44, 46, 47, 0, 0, 0, 32, 0, 0,//50-59
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0};
// this stores some cpu state info before and while the interrupt handler is set
_go32_dpmi_seginfo old_keyb_handler_seginfo, new_keyb_handler_seginfo;
void keyb_handler() { // called by the system if a key is pressed, stores the key in the last_keys array and the keyb array
unsigned char key; // temporarily stores the key
static char extended; // saves if the last character used the 8th bit
int c1; // iteration variable
key = inportb(0x60); // 0x60 seems to be the keyboard port
if (key == 0xe0) // if it is a character that uses the 8th bit
extended = 1; // this will skip this and the nxt call
else {
if (extended == 0) {
if ( (key & 0x80) == 0) {
keyb[key & 0x7f] = 1;
for (c1 = 48; c1 > 0; c1--) // each character in the last_keys array
last_keys[c1] = last_keys[c1 - 1]; // has to go one step back to
last_keys[0] = scancode2ascii[key & 0x7f]; // make place for the new character
}
else
keyb[key & 0x7f] = 0;
}
else { // key is extended
if ( (key & 0x80) == 0) {
keyb[(key & 0x7f) + 0x80] = 1;
for (c1 = 48; c1 > 0; c1--)
last_keys[c1] = last_keys[c1 - 1];
last_keys[0] = scancode2ascii[(key & 0x7f) + 0x80];
}
else
keyb[(key & 0x7f) + 0x80] = 0;
}
if (extended == 1)
extended = 0;
}
outportb(0x20, 0x20); // handled
}
void keyb_handler_end() {} // marks the end of the code of keyb_handler()
char hook_keyb_handler(void) { // enables the keyboard hook
if (keyb_handler_info.enabled == 0) { // only if not already enabled
_go32_dpmi_lock_data( (char *)&keyb, sizeof(keyb) ); // locks the memory region of the keyb array
_go32_dpmi_lock_code(keyb_handler, (unsigned long)keyb_handler_end - (unsigned long)keyb_handler); // locks the code region of keyb_handler
_go32_dpmi_get_protected_mode_interrupt_vector(9, &old_keyb_handler_seginfo); // get the old interrupt handler
new_keyb_handler_seginfo.pm_offset = (int)keyb_handler; // function to call if a key is pressed is keyb_handler
if (_go32_dpmi_allocate_iret_wrapper(&new_keyb_handler_seginfo) != 0) // create a small function that just calls keyb_handler and then does iret
return 1;
if (_go32_dpmi_set_protected_mode_interrupt_vector(9, &new_keyb_handler_seginfo) != 0) { // and set this function as the handler
_go32_dpmi_free_iret_wrapper(&new_keyb_handler_seginfo);
return 1;
}
keyb_handler_info.enabled = 1; // keyboard hook is now enabled
memset(last_keys, 0, sizeof(last_keys) ); // clear the last_keys array
}
return 0;
}
void remove_keyb_handler(void) {
if (keyb_handler_info.enabled == 1) {
_go32_dpmi_set_protected_mode_interrupt_vector(9, &old_keyb_handler_seginfo);
_go32_dpmi_free_iret_wrapper(&new_keyb_handler_seginfo);
keyb_handler_info.enabled = 0;
}
}
char key_pressed(unsigned char key) { // returns if a key is pressed
return keyb[key];
}
I don't know exactly what this all does, but basically you need to store all information about the old handler, then set your new handler. This handler can't simply be a C function because all interrupt handlers need to return with a iret instruction (not the normal ret). Borland had a keyword that made a function return with iret. DJGPP gives you the function ..._allocate_iret_wrapper that is a small assembly function probably written like this:
Code:
mov ebx, [global variable that holds the address of your handler]
call [ebx]
iret
Then you need to set the interrupt handler to your function, don't know exactly how to do this, must probably be in assembler too.
When you're done, restore the old handler with the saved info.
There are some restrictions on an interrupt handler:
You may not use the longjmp functions.
You may not use functions that result in system calls (like printf).
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|