Using the regular keyboard input, like getch() in C or readkey in Pascal notifies us when a key was hit, but it doesn't let us know that it was released.
Therefore, we cannot tell which keys are being held at a specific moment, which is, as you sure have noticed, a very important thing to know, especially in action games (moving and shooting simultaneously).
So, we have to take care of the keyboard input by ourselves:
What we'll do is install an interrupt that will get messages from the Keyboard IO and will update a buffer (array) of keys that tells 'key is currently DOWN' or 'key is currently UP' for each of the keys.
The interrupt (0x9) is generated by the system every time a key is pressed or released.
The value retrieved by port 0x60 tells us what had happened (which key and [Pressed/Released]).
When a key is pressed a "make" code is sent, when a key is released a "break" code is sent.
The value range of the make code is 0-127, the value of the corresponding break code is 128 + the make code (or in other words - MSB on).
For example: When a key ESC is pressed the code is 1, when it is released the code is 129(=1+128).
Ok, so we have an array of 128 booleans (true = key down), the interrupt updates it and in the game loop we check if our keys are pressed in this array.
Now, to the code:
void interrupt key_interrupt(...)
{
unsigned char ch, dummy;
asm cli //Disable interrupts
ch = inp(0x60); //Read the value from the KB IO
dummy = inp(0x61); //Read the value from the KB Status Controller
dummy |= 0x80; //Clear Keyboard, by setting 8th bit, and leave the other untouched
dummy = outp(0x61, dummy);
dummy &= 0x7f; //Enable Keyboard, by clearing the 8th bit, and leave the other untouched
outp(0x61, dummy);
// We disable and then reenable immediately the interrupt to acknowledge the KB controller of the scan code receival.
if (ch < 128) keypress[ch] = 1; //Is it up?
else keypress[ch - 128] = 0; //Is it down?
outportb(0x20, 0x20); //Let the PIC know we are finished
asm sti //Enable interrupts
}
|
looks confusing huh? don't worry, it'll be clearer.
Now instead of doing the 'if else' statement we can use just one line:
keypress[(ch & 127)] = (ch >> 7);
(ch >> 7) ---> returns 0 if ch < 128, returns 1 otherwise.
It's like what we said ...remember? up to 128 is down(true) and more than 128 is up(false)..
Now you wonder what (ch & 127) does?
Well if you don't have a clue about bits read this first!
According to what we said..we get 128 plus the "make" code, it means we want just the first 7 bits of the value
and 2^7=128 which is the maximum of the array. So any number AND (logic) 01111111B will make it at least 127
OK think we get the number 64 from the KB IO so 64 & 127 is 64(again you must know BITWISE AND!)
But when you do 255 & 127 you'll get 127...
ahhhhh I hope you still get what I try to explain it's pretty easy
So we get the same result from the if else statement and the AND logic trick...
That's it for now I hope you got it all......
Take a look at the source to see how to install the interrupt
and how to use it correctly.
Source Code:
Turbo C - skeys.cpp