Allow using ESC as accelerator in wxMSW again.

This ended up being broken due to an interplay between different unrelated
changes (at least r15120 and r41134) which were both correct, but didn't work
well together and resulted in not only preventing IsDialogMessage() from
handling ESC, but also our own accelerator tables.

Fix this by doing the check for IsDialogMessage() brokenness in
MSWProcessMessage() itself, just before calling it, instead of doing it in
MSWShouldPreProcessMessage() which is (and must be) called before
MSWTranslateMessage() which checks for accelerators using ESC.

Closes #3813.

[This is the backport of r77071 from trunk.]

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_3_0_BRANCH@77948 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2014-10-03 01:52:15 +00:00
parent 7d94e9fafd
commit cbc1dbab9a
3 changed files with 54 additions and 45 deletions

View File

@@ -619,6 +619,7 @@ wxMSW:
- Fix wxFileName::MakeRelativeTo() for shortcut files (gafatoa).
- Fix height of initially empty wxBitmapComboBox (Artur Wieczorek).
- Fix setting label of submenu items (Artur Wieczorek).
- Fix using Esc as accelerator in the menus.
3.0.1: (released 2014-06-15)

View File

@@ -682,6 +682,13 @@ private:
bool HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags);
bool HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result);
#ifndef __WXUNIVERSAL__
// Call ::IsDialogMessage() if it is safe to do it (i.e. if it's not going
// to hang or do something else stupid) with the given message, return true
// if the message was handled by it.
bool MSWSafeIsDialogMessage(WXMSG* msg);
#endif // __WXUNIVERSAL__
#if wxUSE_DEFERRED_SIZING
protected:
// this function is called after the window was resized to its new size

View File

@@ -2491,7 +2491,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
}
}
if ( ::IsDialogMessage(GetHwnd(), msg) )
if ( MSWSafeIsDialogMessage(msg) )
{
// IsDialogMessage() did something...
return true;
@@ -2522,12 +2522,16 @@ bool wxWindowMSW::MSWTranslateMessage(WXMSG* pMsg)
#endif // wxUSE_ACCEL
}
bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* msg)
bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* WXUNUSED(msg))
{
// all tests below have to deal with various bugs/misfeatures of
// IsDialogMessage(): we have to prevent it from being called from our
// MSWProcessMessage() in some situations
// We don't have any reason to not preprocess messages at this level.
return true;
}
#ifndef __WXUNIVERSAL__
bool wxWindowMSW::MSWSafeIsDialogMessage(WXMSG* msg)
{
// don't let IsDialogMessage() get VK_ESCAPE 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
@@ -2541,48 +2545,45 @@ bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* msg)
// going into an infinite loop when it tries to find the control to give
// focus to when Alt-<key> is pressed, so we try to detect [some of] the
// situations when this may happen and not call it then
if ( msg->message != WM_SYSCHAR )
return true;
// assume we can call it by default
bool canSafelyCallIsDlgMsg = true;
HWND hwndFocus = ::GetFocus();
// if the currently focused window itself has WS_EX_CONTROLPARENT style,
// ::IsDialogMessage() will also enter an infinite loop, because it will
// recursively check the child windows but not the window itself and so if
// none of the children accepts focus it loops forever (as it only stops
// when it gets back to the window it started from)
//
// while it is very unusual that a window with WS_EX_CONTROLPARENT
// style has the focus, it can happen. One such possibility is if
// all windows are either toplevel, wxDialog, wxPanel or static
// controls and no window can actually accept keyboard input.
#if !defined(__WXWINCE__)
if ( ::GetWindowLong(hwndFocus, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
if ( msg->message == WM_SYSCHAR )
{
// pessimistic by default
canSafelyCallIsDlgMsg = false;
for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
node;
node = node->GetNext() )
{
wxWindow * const win = node->GetData();
if ( win->CanAcceptFocus() &&
!wxHasWindowExStyle(win, WS_EX_CONTROLPARENT) )
{
// it shouldn't hang...
canSafelyCallIsDlgMsg = true;
HWND hwndFocus = ::GetFocus();
break;
// if the currently focused window itself has WS_EX_CONTROLPARENT style,
// ::IsDialogMessage() will also enter an infinite loop, because it will
// recursively check the child windows but not the window itself and so if
// none of the children accepts focus it loops forever (as it only stops
// when it gets back to the window it started from)
//
// while it is very unusual that a window with WS_EX_CONTROLPARENT
// style has the focus, it can happen. One such possibility is if
// all windows are either toplevel, wxDialog, wxPanel or static
// controls and no window can actually accept keyboard input.
#if !defined(__WXWINCE__)
if ( ::GetWindowLong(hwndFocus, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
{
// pessimistic by default
bool canSafelyCallIsDlgMsg = false;
for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
node;
node = node->GetNext() )
{
wxWindow * const win = node->GetData();
if ( win->CanAcceptFocus() &&
!wxHasWindowExStyle(win, WS_EX_CONTROLPARENT) )
{
// it shouldn't hang...
canSafelyCallIsDlgMsg = true;
break;
}
}
if ( !canSafelyCallIsDlgMsg )
return false;
}
}
#endif // !__WXWINCE__
if ( canSafelyCallIsDlgMsg )
{
// ::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
@@ -2593,9 +2594,7 @@ bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* msg)
!::IsWindowVisible(hwndFocus) )
{
// it would enter an infinite loop if we do this!
canSafelyCallIsDlgMsg = false;
break;
return false;
}
if ( !(::GetWindowLong(hwndFocus, GWL_STYLE) & WS_CHILD) )
@@ -2610,9 +2609,11 @@ bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* msg)
}
}
return canSafelyCallIsDlgMsg;
return ::IsDialogMessage(GetHwnd(), msg) != 0;
}
#endif // __WXUNIVERSAL__
// ---------------------------------------------------------------------------
// message params unpackers
// ---------------------------------------------------------------------------