]> git.saurik.com Git - wxWidgets.git/commitdiff
Make wxEVT_CHAR_HOOK propagate upwards and send it to the window itself.
authorVadim Zeitlin <vadim@wxwidgets.org>
Fri, 2 Dec 2011 00:50:25 +0000 (00:50 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Fri, 2 Dec 2011 00:50:25 +0000 (00:50 +0000)
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
interface/wx/event.h
src/common/event.cpp
src/gtk/window.cpp
src/msw/window.cpp
src/osx/carbon/app.cpp
src/osx/cocoa/window.mm

index f052255bedafd7a4293b377e71a9090ac183b8ba..7b4d53c6a29d9b058da9711718f04b1506214d72 100644 (file)
@@ -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)
index db03625d00ebbe54cbeefdefc502104ae7620d15..afc71acc7d9475c05df70a656d93e3c7595c2f5d 100644 (file)
@@ -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
index 088e5fdbfcc9c605a824484f283404ef0a68820c..ce1e145c79fe1fa53133b4a975af7d5a60083a13 100644 (file)
@@ -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
index 3815c8e7e5c5ed74b1037a968e6e658b1459f4b8..9e62caac35d661e00311424f4ffb8b73758e2c19 100644 (file)
@@ -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;
index 6e8efa691e3bc5b060887eae9888b0fc189580fd..506bc5175a65433f0174b05444d17fe9621e5b6e 100644 (file)
@@ -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);
index 171eb0825b9d29afea65ce9e0a1ddfe49d951874..a3ea0229337d9227f0122097dd11aff6ed2328ec 100644 (file)
@@ -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 ) ;
     }
 
index 0bf187240188e2410ee8a873c8b3a9666ad63359..84f694dd02d076e608a1e1db6f75e6c2816fbb9e 100644 (file)
@@ -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;
     }