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
Between these two functions is TranslateMessage , which takes on the responsibility of translating keystroke messages to character messages. If the keystroke message is WM_KEYDOWN or WM_SYSKEYDOWN, and if the keystroke in combination with the shift state produces a character, 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.
|
|
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. (I'll discuss what a dead character is shortly.)
Here's the good news: In most cases, your Windows program can process the WM_CHAR message while ignoring the other three character messages. The
lParam
parameter that
These character messages are the first messages we've
Unless you're explicitly doing mixed coding of ANSI and Unicode functions and window procedures, the character code delivered with the WM_CHAR message (and the three other character messages) is
(TCHAR) wParam
The same window procedure might be used with two window classes, one registered with
RegisterClassA
and the other registered with
RegisterClassW
. This means that the window procedure might get some messages with ANSI character codes and some messages with Unicode character codes. If your window procedure needs help to
fUnicode = IsWindowUnicode (hwnd) ;
The fUnicode variable will be TRUE if the window procedure for hwnd gets Unicode messages, which means the window is based on a window class that was registered with RegisterClassW .
Because the character messages are generated by the TranslateMessage function from WM_KEYDOWN and WM_SYSKEYDOWN messages, 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 code for `A' (0x41) |
| WM_CHAR | Character code for `a' (0x61) |
| WM_KEYUP | Virtual key code for `A' (0x41) |
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 code VK_SHIFT (0x10) |
| WM_KEYDOWN | Virtual key code for `A' (0x41) |
| WM_CHAR | Character code for `A' (0x41) |
| WM_KEYUP | Virtual key code for `A' (0x41) |
| WM_KEYUP | Virtual key code VK_SHIFT (0x10) |
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 code for `A' (0x41) |
| WM_CHAR | Character code for `a' (0x61) |
| WM_KEYDOWN | Virtual key code for `A' (0x41) |
| WM_CHAR | Character code for `a' (0x61) |
| WM_KEYDOWN | Virtual key code for `A' (0x41) |
| WM_CHAR | Character code for `a' (0x61) |
| WM_KEYDOWN | Virtual key code for `A' (0x41) |
| WM_CHAR | Character code for `a' (0x61) |
| WM_KEYUP | Virtual key code for `A' (0x41) |
If some of the WM_KEYDOWN messages have a Repeat Count greater than 1, the corresponding WM_CHAR message will have the same Repeat Count.
The Ctrl Key in combination with a letter key generates ASCII control characters from 0x01 (Ctrl-A) through 0x1A (Ctrl-Z). Several of these control codes are also generated by the keys shown in the following table:
| Key | Character Code | Duplicated by | ANSI C Escape |
|
|
0x08 | Ctrl-H | \b |
| Tab | 0x09 | Ctrl-I | \t |
| Ctrl-Enter | 0x0A | Ctrl-J | \n |
| Enter | 0x0D | Ctrl-M | \r |
| Esc | 0x1B | Ctrl-[ |
The rightmost column shows the escape code defined in ANSI C to represent the character codes for these keys.
Windows programs sometimes use the Ctrl key in combination with letter keys for menu accelerators (which I'll discuss in Chapter 10). In this case, the letter keys are not translated into character messages.
The basic rule for processing keystroke and character messages is this: If you need to read keyboard character input in your window, you process the WM_CHAR message. If you need to read the cursor keys, function keys, Delete, Insert, Shift, Ctrl, and Alt, you process the WM_KEYDOWN message.
But what about the Tab key? Or Enter or Backspace or Escape? Traditionally, these keys generate ASCII control characters, as shown in the
After a
case WM_CHAR:
[other program lines]
switch (wParam)
{
case `\b': // backspace
[other program line
break ;
case `\t': // tab
[other program lines]
break ;
case `\n': // linefeed
[other program lines]
break ;
case `\r': // carriage return
[other program lines]
break ;
default: // character codes
[other program lines]
break ;
}
return 0 ;
Windows programs can usually ignore WM_DEADCHAR and WM_SYSDEADCHAR messages, but you should definitely know what dead characters are and how they work.
On some non-U.S. English keyboards, certain keys are defined to add a
When a
Thus, your program does not have to process the WM_DEADCHAR message because the WM_CHAR message gives the program all the information it needs. The Windows logic even has built-in error handling: If the dead key is followed by a letter that can't take a diacritic (such as `s'), the window procedure receives two WM_CHAR messages in a row—the first with wParam equal to the ASCII code for the diacritic by itself (the same wParam value delivered with the WM_DEADCHAR message) and the second with wParam equal to the ASCII code for the letter `s'.
Of course, the best way to get a feel for this is to see it in action. You need to load a foreign keyboard that uses dead keys, such as the German keyboard that I described earlier. You do this in the Control Panel by selecting Keyboard and then the Language tab. Then you need an application that shows you the details of every keyboard message a program can receive. That's the KEYVIEW1 program coming up next.