Some dialog boxes contain custom navigation that goes beyond what the IsDialogMessage function provides. For example, property sheets use Ctrl+Tab and Ctrl+Shift+Tab to change pages within the property sheet. Remember the core of the dialog loop:

while (<dialog still active> &&
       GetMessage(&msg, NULL, 0, 0, 0)) {
 if (!IsDialogMessage(hdlg, &msg)) {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }
}

(Or the modified version we created in part 7.)

To add custom navigation, just stick it in before calling IsDialogMessage.

while (<dialog still active> &&
       GetMessage(&msg, NULL, 0, 0, 0)) {
 if (msg.message == WM_KEYDOWN &&
     msg.wParam == VK_TAB &&
     GetKeyState(VK_CONTROL) < 0) {
  ... do custom navigation ...
 } else if (!IsDialogMessage(hdlg, &msg)) {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }
}

After retrieving a message, we check whether it was Ctrl+Tab before dispatching it or indeed even before letting IsDialogMessage see it. If so, then treat it as a navigation key.

Note that if you intend to have modeless dialogs controlled by this message loop, then your test needs to be a little more focused, because you don't want to pick off keyboard navigation keys destined for the modeless dialog.

while (<dialog still active> &&
       GetMessage(&msg, NULL, 0, 0, 0)) {
 if ((hdlg == msg.hwnd || IsChild(hdlg, msg.hwnd)) &&
     msg.message == WM_KEYDOWN &&
     msg.wParam == VK_TAB &&
     GetKeyState(VK_CONTROL) < 0) {
  ... do custom navigation ...
 } else if (!IsDialogMessage(hdlg, &msg)) {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }
}

Next time, we'll see another way of accomplishing this same task.