+ // here we try to do all the job which ::IsDialogMessage() usually does
+ // internally
+#if 1
+ if ( msg->message == WM_KEYDOWN )
+ {
+ bool bCtrlDown = wxIsCtrlDown();
+ bool bShiftDown = wxIsShiftDown();
+
+ // WM_GETDLGCODE: ask the control if it wants the key for itself,
+ // don't process it if it's the case (except for Ctrl-Tab/Enter
+ // combinations which are always processed)
+ LONG lDlgCode = 0;
+ if ( !bCtrlDown )
+ {
+ lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
+
+ // surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the
+ // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
+ // it, of course, implies them
+ if ( lDlgCode & DLGC_WANTALLKEYS )
+ {
+ lDlgCode |= DLGC_WANTTAB | DLGC_WANTARROWS;
+ }
+ }
+
+ bool bForward = TRUE,
+ bWindowChange = FALSE;
+
+ // should we process this message specially?
+ bool bProcess = TRUE;
+ switch ( msg->wParam )
+ {
+ case VK_TAB:
+ // assume that nobody wants Shift-TAB for himself - if we
+ // don't do it there is no easy way for a control to grab
+ // TABs but still let Shift-TAB work as navugation key
+ if ( (lDlgCode & DLGC_WANTTAB) && !bShiftDown ) {
+ bProcess = FALSE;
+ }
+ else {
+ // Ctrl-Tab cycles thru notebook pages
+ bWindowChange = bCtrlDown;
+ bForward = !bShiftDown;
+ }
+ break;
+
+ case VK_UP:
+ case VK_LEFT:
+ if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown )
+ bProcess = FALSE;
+ else
+ bForward = FALSE;
+ break;
+
+ case VK_DOWN:
+ case VK_RIGHT:
+ if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown )
+ bProcess = FALSE;
+ break;
+
+ case VK_RETURN:
+ {
+ if ( (lDlgCode & DLGC_WANTMESSAGE) && !bCtrlDown )
+ {
+ // control wants to process Enter itself, don't
+ // call IsDialogMessage() which would interpret
+ // it
+ return FALSE;
+ }
+ else if ( lDlgCode & DLGC_BUTTON )
+ {
+ // let IsDialogMessage() handle this for all
+ // buttons except the owner-drawn ones which it
+ // just seems to ignore
+ long style = ::GetWindowLong(msg->hwnd, GWL_STYLE);
+ if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW )
+ {
+ // emulate the button click
+ wxWindow *btn = wxFindWinFromHandle((WXHWND)msg->hwnd);
+ if ( btn )
+ btn->MSWCommand(BN_CLICKED, 0 /* unused */);
+ }
+
+ bProcess = FALSE;
+ }
+ // FIXME: this should be handled by
+ // wxNavigationKeyEvent handler and not here!!
+ else
+ {
+#if wxUSE_BUTTON
+ wxButton *btn = wxDynamicCast(GetDefaultItem(),
+ wxButton);
+ if ( btn && btn->IsEnabled() )
+ {
+ // if we do have a default button, do press it
+ btn->MSWCommand(BN_CLICKED, 0 /* unused */);
+
+ return TRUE;
+ }
+ else // no default button
+ {
+#endif // wxUSE_BUTTON
+ // this is a quick and dirty test for a text
+ // control
+ if ( !(lDlgCode & DLGC_HASSETSEL) )
+ {
+ // don't process Enter, the control might
+ // need it for itself and don't let
+ // ::IsDialogMessage() have it as it can
+ // eat the Enter events sometimes
+ return FALSE;
+ }
+ else if (!IsTopLevel())
+ {
+ // if not a top level window, let parent
+ // handle it
+ return FALSE;
+ }
+ //else: treat Enter as TAB: pass to the next
+ // control as this is the best thing to do
+ // if the text doesn't handle Enter itself
+ }
+ }
+ }
+ break;
+
+ default:
+ bProcess = FALSE;
+ }
+
+ if ( bProcess )
+ {
+ wxNavigationKeyEvent event;
+ event.SetDirection(bForward);
+ event.SetWindowChange(bWindowChange);
+ event.SetEventObject(this);
+
+ if ( GetEventHandler()->ProcessEvent(event) )
+ {
+ return TRUE;
+ }
+ }
+ }
+#else // 0
+ // let ::IsDialogMessage() do almost everything and handle just the
+ // things it doesn't here: Ctrl-TAB for switching notebook pages
+ if ( msg->message == WM_KEYDOWN )
+ {
+ // don't process system keys here
+ if ( !(HIWORD(msg->lParam) & KF_ALTDOWN) )
+ {
+ if ( (msg->wParam == VK_TAB) && wxIsCtrlDown() )
+ {
+ // find the first notebook parent and change its page
+ wxWindow *win = this;
+ wxNotebook *nbook = NULL;
+ while ( win && !nbook )
+ {
+ nbook = wxDynamicCast(win, wxNotebook);
+ win = win->GetParent();
+ }
+
+ if ( nbook )
+ {
+ bool forward = !wxIsShiftDown();
+
+ nbook->AdvanceSelection(forward);
+ }
+ }
+ }
+ }
+#endif // 1/0
+
+ // we handle VK_ESCAPE ourselves in wxDialog::OnCharHook() and we
+ // shouldn't let IsDialogMessage() get it as it _always_ eats the
+ // message even when there is no cancel button and when the message is
+ // needed by the control itself: in particular, it prevents the tree in
+ // place edit control from being closed with Escape in a dialog
+ if ( msg->message != WM_KEYDOWN || msg->wParam != VK_ESCAPE )
+ {
+ // ::IsDialogMessage() can enter in an infinite loop when the
+ // currently focused window is disabled or hidden and its parent
+ // has WS_EX_CONTROLPARENT style, so don't call it in this case
+ bool canSafelyCallIsDlgMsg = TRUE;
+
+ HWND hwndFocus = ::GetFocus();
+ while ( hwndFocus )
+ {
+ if ( !::IsWindowEnabled(hwndFocus) ||
+ !::IsWindowVisible(hwndFocus) )
+ {
+ // it would enter an infinite loop if we do this!
+ canSafelyCallIsDlgMsg = FALSE;
+
+ break;
+ }
+
+ if ( !(::GetWindowLong(hwndFocus, GWL_STYLE) & WS_CHILD) )
+ {
+ // it's a top level window, don't go further -- e.g. even
+ // if the parent of a dialog is disabled, this doesn't
+ // break navigation inside the dialog
+ break;
+ }
+
+ hwndFocus = ::GetParent(hwndFocus);
+ }
+
+ if ( canSafelyCallIsDlgMsg && ::IsDialogMessage(GetHwnd(), msg) )
+ {
+ // IsDialogMessage() did something...
+ return TRUE;
+ }
+ }