Link to home
Start Free TrialLog in
Avatar of Cypher19
Cypher19

asked on

Keydown event in DOS?

I was wondering if anyone could help me out  on this.

In a program I'm making for DOS, I want to have keyboard input where the program 'instantly' responds to a specific key. However, the way it's set up, if you remember when you press and hold a key, there's the initial key response, a short delay, then the key continues to be recognized. Is there a method of keyboard input that can avoid that delay, and just have a continuous stream of the inputted character?

Any help would be appreciated, and samples of how to do so would be good as well. Keep in mind this is for a DOS program, not Win16/32.
Avatar of e12voltsdac
e12voltsdac
Flag of United States of America image

I had this axact same question about a week ago. I finally figured it out after searching the internet forever.

For this to work you'll need to include conio.h
If you don't have it just ask me.

kbhit() will check to see if there is any information in the keyboard buffer.

getch() will input for a key.

Here is how to combine them to make something similar to what you want:

#include<conio.h>//for getch() and kbhit()
#include<iostream.h>

int main()
{

    char b=0;
    while(1)//will run forever
    {
        for(int i=0;i<999;++i)//counting loop
        {
        clrscr();//clear the screen, need conio.h
        cout<<i<<endl<<b;
        for(int k=0;k<800000;++k)//delay loop
        {}
        if(kbhit())//keyboard character check
        b=getch();//put keyboard buffer into char b
        }
    }
}
this program will count from 0 to 999 and while its counting you can type a key, and it will display it on the second line.
this program will count from 0 to 999 and while its counting you can type a key, and it will display it on the second line.
Avatar of Maxmike
Maxmike

now the real trick... multiple simultanious keystrokes.
Avatar of Cypher19

ASKER

MaxMike: That's what one of my goals are. I can't use kbhit because I need multiple keys at once. Actually, I used kbhit + getch, but it didn't give me the result i wanted.
I do know of a keyboard interrupt.  Back in the day I made a 2 player q-basic program (Yeah, I'm a bit past that now) and in qb the command was int(32)

Now, I'm not certain, but I am guessing that if you can generate an assembly intterupt 0x032 that'll somehow capture the keyboard.  I have no idea.  I don't program in assembly, nor do I know what I'm talking about.

HOWEVER, it may give you some sort of basis for figuring it out.

Alternatively it just struck me that if you could find a keyboard up command you could create some sort of control array with all the different keys you want to trap.  Now using this array you could initialize the key to '1' when kbhit for that key was found, and set it back to '0' when the key is released.  Using this method you could more accurately capture the keystrokes.  This may be the more sensical of the two ideas I've got, but I'ts late and I don't really feel like looking it up right now because I've been working on my own programming issues recently.

Let me know if this helps.
hmm... you could do it by releasing the keys when the keyboard buffer is empty... But of course, then it would keep the key pressed as long as ANY button was held down.
I would assume that the int(32) in basic is referring to '32' in decimal, so it should be int 0x20.

Hmm...not sure but I thought int 0x21 is the generic DOS interrupt. I thought int 0x20 was the interrupt to terminate the program or something....it's a while ago though so I may be wrong in this.

I am pretty sure that int(32) is not int 0x32 though since the first is decimal and the second is 32 in hex.

Yes, DOS does use the higher INT values for some undocumented features but I don't think reading keyboard codes are among those.

I would believe the best way to get simultaneous keyboard keys and checking for those is to read the keyboard, think it is int 0x15 or in decimal that would be int(21). This is the interrupt to directly talk with the BIOS keyboard code. Checking for simultaneous keys is simply a matter of recognizing that a key had gone down, then second key down before the first key has gone up. Then the two keys are being pressed simultaneously.

If some of those keys are shift or control it's even easier since the MS-DOS keep track of ALT SHIFT and CTRL keys and their status. If it is other keys, simply keep track of that by yourself, you get to know when a key is pressed and you get to know when it is no longer pressed.

Alf
MaxMike: You mean use the array in conjunction with the kbhit/getch method? That would work well, but one problem that lies with that is it can only get one key at a time.

Kind of a seperate question, but I found (with the help of some people on IRC) a windows.h function, GetAsyncKeyState(int (in hex form)), that returns a true or false based on the virtual-key code inputted if that key was pressed or not. It works great! Multiple keys at once, fairly fast, but it won't work in a DOS program/project. Is it possible to get it working in DOS, even though it's a windows function?
If it is a win32 function it won't work on DOS - sorry.

However, asking the keyboard driver through int 0x15 should give you the keycode and a bit saying if the key was pressed down or if it was released. This is all the info you need. You just have to keep track of which keys are down and which are up.

If you get this sequence (one key at a time):

K1 (down), (*1) K1 (up), K2 (down), (*2) K3 (down), (*3) K2 (up), K4 (down), (*4) K3 (up), K4 (up)

Then you know that at time (*1) you have key K1 down and no other. At time (*2) you have K2 down and no other. At time (*3) you have both K2 and K3 pressed down at the same time. At time (*4) you have both K3 and K4 presesd down at the same time.

What more do you need? Check out the BIOS keyboard interface.

Alf
If this doesn't work, in DOS you can always take over the keyboard event. When the user press a key the system generates an interrupt to the CPU. If you place a hook in that interrupt you can catch exactly the same information that the BIOS processes when it reads the keyboard key and places it in the FIFO buffer.

just change the interrupt vector at that place to hold your function, then when you're done processing the key and probably placing it in your own FIFO buffer and keeping track of which keys are down you can pass it on to the system keyboard driver by doing a far jump to the address of the old interrupt vector.

Note that using this method you have to read the keyboard key yourself using IN instruction.

Alf
Salte: And I would accomplish that how in Borland's C++? I found an interrupt property for functions (I think that's what you're talking about in the first paragraph) but I have no clue whatsoever on what to do with it.
ASKER CERTIFIED SOLUTION
Avatar of Salte
Salte

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
@.@ Wow, thanks for the help salte!!
One thing, if you want to jump to the function it is possible that a simple

__asm {
   jmp addr
}

isn't good. It might try to jump to the data location where the address is stored instead of considering that address to be a pointer and jump to the location indicated by it. Try:

__asm {
   jmp [addr]
}

if the first one doesn't work, you want an indirect jump.

possibly also specify that it is a far jump:

__asm {
   jmp far ptr [addr]
}

Alf