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
This commit is contained in:
Vadim Zeitlin
2011-12-02 00:50:25 +00:00
parent f47a359113
commit 3a95f73c00
7 changed files with 47 additions and 34 deletions

View 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)

View 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

View 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

View File

@@ -834,23 +834,16 @@ 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) )
wxKeyEvent eventCharHook(wxEVT_CHAR_HOOK, event);
if ( win->HandleWindowEvent(eventCharHook) )
return true;
}
}
return false;
}

View 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);

View 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 ) ;
}

View 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;
}