Keyboard input is delivered to an application’s window procedure in the form of Windows messages. Whenever a key is pressed or released, Windows posts one or more keyboard messages to the message queue of the window that currently has the keyboard focus. Since most applications contain several windows, only the window with the keyboard focus receives these messages.
Pressing keys on the keyboard will generate both a keystroke and a character. Keystrokes represent the physical keypress and characters represent the display symbol or glyphs generated as a result of the keypress.
When a key is pressed or released, Windows places a WM_KEYDOWN or WM_KEYUP message in the application’s message queue. These keystroke messages identify the key using a virtual-key code. A virtual-key code is a device-independent integer value that uniquely identifies a key on the keyboard. The corresponding MFC message-map macros are ON_WM_KEYDOWN() and ON_WM_KEYUP(). The prototype for the message handler is:
afx_msg void OnMsgName(UINT nChar, UINT nRepCnt, UINT nFlags);
where
nChar – the virtual-key code of the key that was pressed or released.
nRepCnt – the repeat count, indicating the number of times the keystroke has been automatically repeated while the key remains pressed.
nFlags – contains additional information about the keystroke, including the scan code, extended-key flag, context code, previous key state, and transition state.
In addition to producing keystrokes, character messages are also produced as a result of translating keystroke messages into character codes. The most commonly used character message is WM_CHAR. A WM_CHAR message includes a character code that maps directly to a symbol in the current character set. The ON_WM_CHAR macro entry in a class’s message map routes WM_CHAR messages to the member function OnChar(). The prototype is as follows:
afx_msg void OnMsgName(UINT nChar,UINT nRepCnt,UINT nFlags);
where nChar holds the character code and nRepCnt and nFlags have the same meanings as keystroke messages.
Some additional keyboard messages
SYSKEY messages
WM_SYSKEYDOWN and WM_SYSKEYUP are generated when the user presses the Alt key or presses another key while the Alt key is held down. They are also generated when the F10 key is pressed because Windows reserves this key for activating the menu bar.
If other keys are pressed while the Alt key is held down Windows will generate a WM_SYSKEYDOWN and WM_SYSKEYUP messages instead of WM_KEYDOWN and WM_KEYUP messages.
The window that receives the message can distinguish between these two contexts by checking the context code in the lParam parameter.
The corresponding message-map macros are
ON_WM_KEYDOWN()
ON_WM_KEYUP()
ON_WM_SYSKEYDOWN()
ON_WM_SYSKEYUP()
Handling WM_SYSKEYDOWN and WM_SYSKEYUP messages is generally best left to the system since if these messages don’t find their way to ::DefWindowProc and get returned to Windows then system keyboard commands such as Alt-Tab will stop working.
Dead keys
A dead key is a modifier key that does not generate a character but modifies the character generated by the key pressed immediately after it. Dead keys are typically used to attach a specific diacritic to a base letter. Examples of dead keys include the acute (´), grave (`), circumflex (^), and tilde (~) accent keys found on many European keyboard layouts.
To process dead-key messages in an MFC application will need an ON_WM_DEADCHAR or ON_WM_SYSDEADCHAR entry in the message map in addition to supplying handling functions named OnDeadChar() and OnSysDeadChar().
Virtual key codes
Windows defines special constants for each key the user can press. These constants, known as virtual key codes, provide hardware and language-independent methods of identifying keyboard keys. Microsoft provides a complete list of virtual-key codes in the Windows API documentation.
Retrieving a key state
The ::GetKeyState() API function retrieves the status of a specified virtual key. The status specifies whether the key is up, down, or toggled. Since information about the current states of keys such as Shift and Ctrl keys is not included in keyboard messages, the GetKeyState API function allows the developer to determine these key states before deciding on a course of action. The syntax for this function is –
SHORT GetKeyState(int vKey);
The return value is:
High-order bit set → key is currently down.
Low-order bit set → key is toggled (Caps Lock, Num Lock, Scroll Lock).
Retrieving the Asynchronous Key State
The ::GetAsyncKeyState() API function retrieves the current state of a specified virtual key independently of the application’s message queue. Unlike GetKeyState(), which reports the keyboard state associated with the current message being processed, GetAsyncKeyState() returns the real-time physical state of the key at the instant the function is called. This makes it particularly useful in applications such as games, drawing programs, and other real-time software that continuously polls the keyboard rather than relying solely on keyboard messages.
The syntax for the function is:
SHORT GetAsyncKeyState(int vKey);
where vKey specifies one of the Windows virtual-key codes.
The return value is a 16-bit value. If the most significant bit is set, the key is currently pressed. If the least significant bit is set, the key has been pressed since the previous call to GetAsyncKeyState(). Because other applications may also call this function, the least significant bit should not be relied upon in modern versions of Windows. In most applications, only the most significant bit is tested.
For example, the following code determines whether the Shift key is currently being held down:
if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
{
// Shift key is currently pressed.
}
Example
The following code segment illustrates key-down and char-character message handling by displaying the output of the keystroke and character values when a key is pressed.