Search code examples
c++cdos

Checking if a key is down in MS-DOS (C/C++)


Yes, I mean real MS-DOS, not Windows' cmd.exe shell console.

Is there a way to check if a key is down in MS-DOS, analogically to the GetAsyncKeyState() function in WinAPI?

Currently I'm using kbhit() and getch(), but it's really slow, has a delay after the first character, doesn't allow multiple keys at the same time etc.

I'm using Turbo C++ 3.1. Can anyone help?

(by the way, don't ask why I'm coding my game on such an ancient system)


Solution

  • Why are you coding your game on su…just kidding!

    In MS-DOS, the "API" functions are implemented as interrupt servicers. In x86 assembly language, you use the INT instruction and specify the number of the interrupt that you want to execute. Most of the interrupts require that their "parameters" be set in certain registers before executing the INT. After the INT instruction returns control to your code, its result(s) will have been placed in certain registers and/or flags, as defined by the interrupt call's documentation.

    I have no idea how Turbo C++ implements interrupts, since that pre-dates my involvement with programming, but I do know that it allows you to execute them. Google around for the syntax, or check your Turbo C++ documentation.

    Knowing that these are interrupts will get you 90% of the way to a solution when you're searching. Ralf Brown compiled and published a famous list of DOS and BIOS interrupt codes. They should also be available in any book on DOS programming—if you're serious about retro-programming, you should definitely consider getting your hands on one. A used copy on Amazon should only set you back a few bucks. Most people consider these worthless nowadays.

    Here is a site that lists the sub-functions available for DOS interrupt 21h. The ones that would be relevant to your use are 01, 06, 07, and 08. These are basically what the C standard library functions like getch are going to be doing under the hood. I find it difficult to imagine, but I have heard reports that programmers back in the day found it faster to call the DOS interrupts directly. The reason I question that is that I can't imagine the runtime library implementers would have been so stupid as to provide unnecessarily slow implementations. But maybe they were.

    If the DOS interrupts are still too slow for you, your last recourse would be to use BIOS interrupts directly. This might make an appreciable difference in speed because you're bypassing every abstraction layer possible. But it does make your program significantly less portable, which is the reason operating systems like DOS provided these higher level function calls to begin with. Again, check Ralf Brown's list for the interrupt that is relevant to your use. For example, INT 16 with the 01h sub-function.