diff --git a/include/wx/event.h b/include/wx/event.h index f052255bed..7b4d53c6a2 100644 --- a/include/wx/event.h +++ b/include/wx/event.h @@ -1744,6 +1744,14 @@ public: wxUint32 m_rawFlags; private: + // Set the event to propagate if necessary, i.e. if it's of wxEVT_CHAR_HOOK + // type. This is used by all ctors. + void InitPropagation() + { + if ( m_eventType == wxEVT_CHAR_HOOK ) + m_propagationLevel = wxEVENT_PROPAGATE_MAX; + } + // Copy only the event data present in this class, this is used by // AssignKeyData() and copy ctor. void DoAssignMembers(const wxKeyEvent& evt) diff --git a/interface/wx/event.h b/interface/wx/event.h index db03625d00..afc71acc7d 100644 --- a/interface/wx/event.h +++ b/interface/wx/event.h @@ -1365,17 +1365,21 @@ enum wxKeyCategoryFlags @event{EVT_CHAR(func)} Process a @c wxEVT_CHAR event. @event{EVT_CHAR_HOOK(func)} - Process a @c wxEVT_CHAR_HOOK event which is sent to the active - wxTopLevelWindow (i.e. the one containing the currently focused window) - or wxApp global object if there is no active window before any other - keyboard events are generated giving the parent window the opportunity - to intercept all the keyboard entry. If the event is handled, i.e. the - handler doesn't call wxEvent::Skip(), neither @c wxEVT_KEY_DOWN nor @c - wxEVT_CHAR events will be generated (although @c wxEVT_KEY_UP still - will be). Notice that this event is not generated when the mouse is - captured as it is considered that the window which has the capture - should receive all the keyboard events too without allowing its parent - wxTopLevelWindow to interfere with their processing. + Process a @c wxEVT_CHAR_HOOK event. Unlike all the other key events, + this event is propagated upwards the window hierarchy which allows + intercepting it in the parent window of the focused window to which it + is sent initially (if there is no focused window, this event is sent to + the wxApp global object). It is also generated before any other key + events and so gives the parent window an opportunity to modify the + keyboard handling of its children, e.g. it is used internally by + wxWidgets in some ports to intercept pressing Esc key in any child of a + dialog to close the dialog itself when it's pressed. If the event is + handled, i.e. the handler doesn't call wxEvent::Skip(), neither @c + wxEVT_KEY_DOWN nor @c wxEVT_CHAR events will be generated (although @c + wxEVT_KEY_UP still will be). Notice that this event is not generated + when the mouse is captured as it is considered that the window which + has the capture should receive all the keyboard events too without + allowing its parent wxTopLevelWindow to interfere with their processing. @endEventTable @see wxKeyboardState diff --git a/src/common/event.cpp b/src/common/event.cpp index 088e5fdbfc..ce1e145c79 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -735,6 +735,8 @@ wxKeyEvent::wxKeyEvent(wxEventType type) #if wxUSE_UNICODE m_uniChar = WXK_NONE; #endif + + InitPropagation(); } wxKeyEvent::wxKeyEvent(const wxKeyEvent& evt) @@ -742,6 +744,8 @@ wxKeyEvent::wxKeyEvent(const wxKeyEvent& evt) wxKeyboardState(evt) { DoAssignMembers(evt); + + InitPropagation(); } wxKeyEvent::wxKeyEvent(wxEventType eventType, const wxKeyEvent& evt) @@ -751,6 +755,8 @@ wxKeyEvent::wxKeyEvent(wxEventType eventType, const wxKeyEvent& evt) DoAssignMembers(evt); m_eventType = eventType; + + InitPropagation(); } bool wxKeyEvent::IsKeyInCategory(int category) const diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index 3815c8e7e5..9e62caac35 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -834,22 +834,15 @@ namespace // if it was processed (and not skipped). bool SendCharHookEvent(const wxKeyEvent& event, wxWindow *win) { - // wxEVT_CHAR_HOOK must be sent to the top level parent window to allow it + // wxEVT_CHAR_HOOK must be sent to allow the parent windows (e.g. a dialog + // which typically closes when Esc key is pressed in any of its controls) // to handle key events in all of its children unless the mouse is captured // in which case we consider that the keyboard should be "captured" too. if ( !g_captureWindow ) { - wxWindow * const parent = wxGetTopLevelParent(win); - if ( parent ) - { - // We need to make a copy of the event object because it is - // modified while it's handled, notably its WasProcessed() flag - // is set after it had been processed once. - wxKeyEvent eventCharHook(event); - eventCharHook.SetEventType(wxEVT_CHAR_HOOK); - if ( parent->HandleWindowEvent(eventCharHook) ) - return true; - } + wxKeyEvent eventCharHook(wxEVT_CHAR_HOOK, event); + if ( win->HandleWindowEvent(eventCharHook) ) + return true; } return false; diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 6e8efa691e..506bc5175a 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -6622,7 +6622,14 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) #endif // wxUSE_UNICODE ) { - const wxWindow * const win = wxGetActiveWindow(); + wxWindow const* win = wxWindow::DoFindFocus(); + if ( !win ) + { + // Even if the focus got lost somehow, still send the event + // to the top level parent to allow a wxDialog to always + // close on Escape. + win = wxGetActiveWindow(); + } wxKeyEvent event(wxEVT_CHAR_HOOK); MSWInitAnyKeyEvent(event, wParam, lParam, win); diff --git a/src/osx/carbon/app.cpp b/src/osx/carbon/app.cpp index 171eb0825b..a3ea022933 100644 --- a/src/osx/carbon/app.cpp +++ b/src/osx/carbon/app.cpp @@ -1616,20 +1616,16 @@ bool wxApp::MacSendCharEvent( wxWindow* focus , long keymessage , long modifiers #if wxOSX_USE_CARBON long keyval = event.m_keyCode ; - wxNonOwnedWindow *tlw = focus->MacGetTopLevelWindow() ; - if (tlw) { - event.SetEventType( wxEVT_CHAR_HOOK ); - handled = tlw->HandleWindowEvent( event ); - if ( handled && event.GetSkipped() ) + wxKeyEvent eventCharHook(wxEVT_CHAR_HOOK, event); + handled = focus->HandleWindowEvent( eventCharHook ); + if ( handled && eventCharHook.GetSkipped() ) handled = false ; } if ( !handled ) { - event.SetEventType( wxEVT_CHAR ); - event.Skip( false ) ; handled = focus->HandleWindowEvent( event ) ; } diff --git a/src/osx/cocoa/window.mm b/src/osx/cocoa/window.mm index 0bf1872401..84f694dd02 100644 --- a/src/osx/cocoa/window.mm +++ b/src/osx/cocoa/window.mm @@ -2305,9 +2305,8 @@ bool wxWidgetCocoaImpl::DoHandleKeyEvent(NSEvent *event) // changed by SetupKeyEvent() so it can be wxEVT_KEY_UP too by now). if ( wxevent.GetEventType() == wxEVT_KEY_DOWN ) { - wxKeyEvent eventHook(wxevent); - eventHook.SetEventType(wxEVT_CHAR_HOOK); - if ( wxGetTopLevelParent(GetWXPeer())->OSXHandleKeyEvent(eventHook) ) + wxKeyEvent eventHook(wxEVT_CHAR_HOOK, wxevent); + if ( GetWXPeer()->OSXHandleKeyEvent(eventHook) ) return true; }