Handling Events

We've done a lot of work with the wHnd we found for writing to the console — how can we read from it, using our rHnd handle? The answer is that it is in fact very easy! We need to use two function calls, GetNumberOfConsoleInputEvents(...) to find out how many console input events have happened — and then ReadConsoleInput(...) to read them into a buffer so we can finally cycle through each event and decide what to do with it.

GetNumberOfConsoleInputEvents(...) requires two arguments — a HANDLE to the console input handle, and a pointer to a DWORD that will store the number of events that really happened. Once we have done that, and if the number of events that happened was not zero, we create an array of INPUT_RECORDs big enough to hold all the events, then use ReadConsoleInput(...) to copy the events into the buffer. ReadConsoleInput(...) takes four arguments:

Here is some code that illustrates the ideas above in motion. Note that for this sort of thing, an IDE capabale of intellisense (I am using Visual Studio) is very useful for working out what all the event types are...

#include <stdlib.h>
#include <stdio.h>
#include <Windows.h>
#include <Tchar.h>

HANDLE wHnd;    // Handle to write to the console.
HANDLE rHnd;    // Handle to read from the console.

int _tmain(int argc, _TCHAR* argv[]) {

    // ... code removed ...

    // Write the characters:
    WriteConsoleOutputA(wHnd, consoleBuffer, charBufSize, characterPos, &writeArea);

    // How many events have happened?
    DWORD numEvents = 0;

    // How many events have we read from the console?
    DWORD numEventsRead = 0;
    
    // Boolean flag to state whether app is running or not.
    bool appIsRunning = true;

    // If we set appIsRunning to false, the program will end!
    while (appIsRunning) {

        // Find out how many console events have happened:
        GetNumberOfConsoleInputEvents(rHnd, &numEvents);

        // If it's not zero (something happened...)
        if (numEvents != 0) {

            // Create a buffer of that size to store the events
            INPUT_RECORD *eventBuffer = new INPUT_RECORD[numEvents];

            // Read the console events into that buffer, and save how
            // many events have been read into numEventsRead.
            ReadConsoleInput(rHnd, eventBuffer, numEvents, &numEventsRead);

            // Now, cycle through all the events that have happened:
            for (DWORD i = 0; i < numEventsRead; ++i) {

                // Check the event type: was it a key?
                if (eventBuffer[i].EventType == KEY_EVENT) {

                    // Yes! Was the key code the escape key?
                    if (eventBuffer[i].Event.KeyEvent.wVirtualKeyCode==VK_ESCAPE) {

                        // Yes, it was, so set the appIsRunning to false.
                        appIsRunning = false;
                    }
                }
            }

            // Clean up our event buffer:
            delete[] eventBuffer;
        }
    }
}

All this does is find out how many events happened, allocates a buffer for them, reads them into it, then cycles through all the ones that was read, checking for a keypress, then checking for the escape key. Once it has done this, it deletes the event buffer and loops, providing appIsRunning is still true.

The available .EventTypes are:

The two event types we'll be concentrating on are KEY_EVENT and MOUSE_EVENT. The following information is lifted almost directly from MSDN.

Keyboard Events

The .Event structure contains the following members:

Mouse Events

The .Event structure contains the following members: