Translating the Keystrokes

We will now tamper with three lines of code that are common to all the Windows programs that we've created so far in this book. The code is the standard message loop:

while (GetMessage (&msg, NULL, 0, 0))

{

TranslateMessage (&msg) ;

DispatchMessage (&msg) ;

}

Here's how we change it to use the keyboard accelerator table:

while (GetMessage (&msg, NULL, 0, 0))

{

if (!TranslateAccelerator (hwnd, hAccel, &msg))

{

TranslateMessage (&msg) ;

DispatchMessage (&msg) ;

}

}

The TranslateAccelerator function determines if the message stored in the msg message structure is a keyboard message. If it is, the function searches for a match in the accelerator table whose handle is hAccel. If it finds a match, it calls the window procedure for the window whose handle is hwnd. If the keyboard accelerator ID corresponds to a menu item in the system menu, then the message is WM_SYSCOMMAND. Otherwise, the message is WM_COMMAND.

When TranslateAccelerator returns, the return value is nonzero if the message has been translated (and already sent to the window procedure) and 0 if not. If TranslateAccelerator returns a nonzero value, you should not call TranslateMessage and DispatchMessage but rather loop back to the GetMessage call.

The hwnd parameter in TranslateMessage looks a little out of place because it's not required in the other three functions in the message loop. Moreover, the message structure itself (the structure variable msg) has a member named hwnd, which is also a handle to a window.

The fields of the msg structure are filled in by the GetMessage call. When the second parameter of GetMessage is NULL, the function retrieves messages for all windows belonging to the application. When GetMessage returns, the hwnd member of the msg structure is the window handle of the window that will get the message. However, when TranslateAccelerator translates a keyboard message into a WM_COMMAND or WM_SYSCOMMAND message, it replaces the msg.hwnd window handle with the window handle hwnd specified as the first parameter to the function. That is how Windows sends all keyboard accelerator messages to the same window procedure even if another window in the application currently has the input focus. TranslateAccelerator does not translate keyboard messages when a modal dialog box or message box has the input focus, because messages for these windows do not come through the program's message loop.

In some cases in which another window in your program (such as a modeless dialog box) has the input focus, you may not want keyboard accelerators to be translated. You'll see how to handle this in Chapter 10.