From 3a95f73c001e70cd195ea1d46df3040dea7532e8 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 2 Dec 2011 00:50:25 +0000 Subject: [PATCH] Make wxEVT_CHAR_HOOK propagate upwards and send it to the window itself. Send wxEVT_CHAR_HOOK events to the focused window itself but make them propagatable to ensure that the parent windows (including the top level parent) still get it. This still allows the TLW parent to intercept keyboard handling in its child but allows the child (or an intermediate parent window) to have some say in the matter. See #9102. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@69893 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/event.h | 8 ++++++++ interface/wx/event.h | 26 +++++++++++++++----------- src/common/event.cpp | 6 ++++++ src/gtk/window.cpp | 17 +++++------------ src/msw/window.cpp | 9 ++++++++- src/osx/carbon/app.cpp | 10 +++------- src/osx/cocoa/window.mm | 5 ++--- 7 files changed, 47 insertions(+), 34 deletions(-) diff --git a/include/wx/event.h b/include/wx/event.h index f052255..7b4d53c 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 db03625..afc71ac 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 088e5fd..ce1e145 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 3815c8e..9e62caa 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 6e8efa6..506bc51 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 171eb08..a3ea022 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 0bf1872..84f694d 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; } -- 2.7.4