Earlier I discussed the idea of translating keystroke messages into character messages by taking into account shift-state information, and I warned that shift-state information is not enough: You also need to know about country-dependent keyboard configurations. For this reason, you should not attempt to translate keystroke messages into character codes yourself.
Windows does it for you. You've seen this code before:
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
This is a typical message loop that appears in WinMain. The GetMessage function fills in the msg structure fields with the next message from the queue. DispatchMessage calls the appropriate window procedure with this message.
Between these two functions is TranslateMessage, which translates keystroke messages into character messages. If the message is WM_KEYDOWN or WM_SYSKEYDOWN, and if the keystroke in combination with the shift states produces a character, then TranslateMessage places a character message in the message queue. This character message will be the next message that GetMessage retrieves from the queue after the keystroke message.
There are four character messages:
Characters | Dead Characters |
Nonsystem Characters: | WM_CHAR | WM_DEADCHAR |
System Characters: | WM_SYSCHAR | WM_SYSDEADCHAR |
The WM_CHAR and WM_DEADCHAR messages are derived from WM_KEYDOWN messages. The WM_SYSCHAR and WM_SYSDEADCHAR messages are derived from WM_SYSKEYDOWN messages. In most cases, your Windows program can ignore everything except WM_CHAR messages. The lParam parameter passed to the window procedure with the character code message is the same as the lParam parameter for the keystroke message that generated the character code message. The wParam parameter is the ASCII code for the character (yes, good old familiar ASCII).
The character messages are delivered to your window procedure sandwiched between keystroke messages. For instance, if Caps Lock is not toggled on and you press and release the A key, the window procedure receives the following three messages:
Message | Key or Code |
WM_KEYDOWN | Virtual key A |
WM_CHAR | ASCII code a |
WM_KEYUP | Virtual key A |
If you type an uppercase A by pressing the Shift key, pressing the A key, releasing the A key, and then releasing the Shift key, the window procedure receives five messages:
Message | Key or Code |
WM_KEYDOWN | Virtual key VK_SHIFT |
WM_KEYDOWN | Virtual key A |
WM_CHAR | ASCII code A |
WM_KEYUP | Virtual key A |
WM_KEYUP | Virtual key VK_SHIFT |
The Shift key by itself does not generate a character message.
If you hold down the A key so that the typematic action generates keystrokes, you'll get a character message for each WM_KEYDOWN message:
Message | Key or Code |
WM_KEYDOWN | Virtual key A |
WM_CHAR | ASCII code a |
WM_KEYDOWN | Virtual key A |
WM_CHAR | ASCII code a |
WM_KEYDOWN | Virtual key A |
WM_CHAR | ASCII code a |
WM_KEYDOWN | Virtual key A |
WM_CHAR | ASCII code a |
WM_KEYUP | Virtual key A |
If some of the WM_KEYDOWN messages have a Repeat Count greater than 1, the corresponding WM_CHAR messages will have the same Repeat Count.
The Ctrl key in combination with a letter key generates ASCII control codes from 01H (Ctrl-A) through 1AH (Ctrl-Z). You can also use other keys to generate these control codes. The following table shows the value of wParam in a WM_CHAR message for keys that generate control codes:
Key | ASCII Code | Duplicated by |
Backspace | 08H | Ctrl-H |
Tab | 09H | Ctrl-I |
Ctrl-Enter | 0Ah | Ctrl-J |
Enter | 0Dh | Ctrl-M |
Esc | 1BH | Ctrl-[ |
Windows programs sometimes use the Ctrl key in combination with letter keys for menu accelerators, in which case the letter keys are not translated into character messages.