Using windows.h to substitute conio.h and dos.h, specially getch()

Hi everyone.

My objective is to make standard C/C++ programs that operate on a text user interface (TUI). After LONG search on the internet, I learned a lot of interesting stuff about C/C++.

First, I know that fully standard is not possible across all platforms, but I'm satisfied with Windows only. From that, I found code that substitute almost all of the important functions from conio.h and dos.h (which I used on Borland Turbo C++ 3 to great effect), using functions from windows.h, which seems to be standard across Windows compilers.

I created my own library to make it easier to use those functions, but the function that substitutes getch() (and in my case kbhit() as well) lacks some functionality that I'd like your help to implement.

I remember that when I learned to use getch() I was told that the keyboard generates one character in it's buffer for keys that simply represent characters and two characters for special keys like Fn and the arrow keys, where the first character is always '0'. But the function that I have only works for simple keys. How do I change that?

This is the function that I use (tested and working):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
bool tui_getkey (char * tui_key) {
    HANDLE tui_handle = GetStdHandle(STD_INPUT_HANDLE);
    DWORD tui_evtc;
    GetNumberOfConsoleInputEvents(tui_handle,&tui_evtc);
    INPUT_RECORD tui_inrec;
    DWORD tui_numread;
    bool tui_havehappened = false;
    while (tui_evtc > 0) {
        ReadConsoleInput(tui_handle,&tui_inrec,1,&tui_numread);
        if (tui_inrec.EventType == KEY_EVENT) {
            if (tui_inrec.Event.KeyEvent.bKeyDown) {
                *tui_key = tui_inrec.Event.KeyEvent.uChar.AsciiChar;
                tui_havehappened = true;
            }
        }
        GetNumberOfConsoleInputEvents(tui_handle,&tui_evtc);
    }
    return tui_havehappened;
}

This function is to be used inside a while() loop, where it will return whether there was a key press or not. In the case of having a key press, it will return the char via reference. I don't care how this gets modified to work, even if it get modified to work like getch(), where it's executed either once or twice, depending on the value returned on the first time.
First, I know that fully standard is not possible across all platforms, but I'm satisfied with Windows only


Have you considered an external lib like ncurses?

http://en.wikipedia.org/wiki/Ncurses
Disch wrote:
Have you considered an external lib like ncurses?

I'd prefer to stay close to standard and don't install anything, except if the install means pasting a file on the same directory of the program I'll write. Specially because I'll be using machines where I don't have permissions to install stuff.
Without having experience in this area, I have to say I would not have done it like that. GetNumberOfConsoleInputEvents() return the number of events waiting. I would use this number to dynamically allocate an array of that many INPUT_RECORD structures, and then I would examine if the first one is a null char (that should account for special keys).

Furthermore, the function should start with WaitForSingleObject() to wait for the console input buffer to have something in it, making it unnecessary to return a boolean value because the call would be blocking and it would unlock only after reading input.
Just out of curiousity...

Why aren't you using getch() on Windows?

If you're interested in reimplementing getch as an exercise, fine. But you don't have to.
webJose wrote:
Furthermore, the function should start with WaitForSingleObject() to wait for the console input buffer to have something in it, making it unnecessary to return a boolean value because the call would be blocking and it would unlock only after reading input.

If you don't know how getch() and kbhit() work together you should ask, and forgive me for not telling:
1
2
3
4
5
6
7
8
9
10
while (/*whatever*/) {
    if (kbhit()) { // instantly returns if there's a key being pressed or not
        ch1 = getch(); // returns the code for the first/last key in the keyboard buffer *
        if (ch1 == 0) { // * blocks if buffer is empty
            ch2 = getch();
        }
    }
    // update a clock display, for example
    // do stuff with certain keys
}

I need to be able to do stuff and wait for input at the same time. I can do that now, I just can't differentiate simple keys from complex keys;

But I'll try to see if your suggestion works.

andywestken wrote:
Why aren't you using getch() on Windows?

If you're interested in reimplementing getch as an exercise, fine. But you don't have to.

Read first post. I want standardization. conio.h and dos.h is specific to Borland compilers and hopefully other compilers, but not all of them. windows.h, on the other hand, seems to be standard for all compilers, according to what I read.

EDIT: Sorry webJose, but your suggestion didn't worked. But it led me straight in the solution! With your suggestion I started wondering whether the INPUT_RECORD structure records stuff related to the keys or the keyboard buffer, so I went to MSDN to find out. It's the former, but more than that, I realized something: I was reading ASCII chars from keys, which would not return to me ASCII representations of special keys. But there's another member of INPUT_RECORD called wVirtualKeyCode that records the code for most keys on the keyboard plus some more stuff, devide-independent!

So now all I have to do is work with the defined constants instead of chars and I'll be good to go.

I guess I'll make my library available when I finish it so people can free themselves from conio.h and dos.h, although I just remembered that dos.h also contains functions to handle the buzzer which would be interesting to implement...

Thanks everyone and specially webJose for the help! Great forum this one.
Last edited on
Sorry!

I guess I am rather VC + MinGW centric. But conio.h and dos.h aren't Borland specific; they're both provided with Visual C++ and the MinGW version of gcc. If anything, I would assume they first appeared back in the DOS SDK, pre IDE. As all the open source IDEs tend to use gcc, so that's Code::Block, CodeLite, Eclipse, ... covered.

Also, I note that gcc does not provide its own implementation. They are linking to the standard Micrsoft msvcrt.dll. The gcc compiler just provides a .lib file for static linking. Other compiler venders are very likely do do the same thing. Even if they don't, it's easy to link to a DLL which exposes a C API.

The net effect is that you're duplicating functionality that is guaranteed to be on any Microsoft system.

Andy

P.S. If you still want to write a general function to replace the exisiting implementation, you do have a bit of a way to go. I've just had a quick look at the MSVCRT implementation and it's rather longer than your own code.
Last edited on
Topic archived. No new replies allowed.