mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Windows: Fix bug where mouse events would not reach background windows blocked by modal windows
This commit is contained in:
parent
b0a3be2bb4
commit
2d243486c9
1 changed files with 57 additions and 15 deletions
|
|
@ -2813,6 +2813,11 @@ private:
|
||||||
|
|
||||||
doMouseEvent (getPointFromLocalLParam (lParam), MouseInputSource::defaultPressure);
|
doMouseEvent (getPointFromLocalLParam (lParam), MouseInputSource::defaultPressure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is the first event after receiving both a MOUSEACTIVATE and a SETFOCUS, then
|
||||||
|
// process the postponed focus update.
|
||||||
|
if (std::exchange (mouseActivateFlags, (uint8_t) 0) == (gotMouseActivate | gotSetFocus))
|
||||||
|
handleSetFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void doMouseUp (Point<float> position, const WPARAM wParam, bool adjustCapture = true)
|
void doMouseUp (Point<float> position, const WPARAM wParam, bool adjustCapture = true)
|
||||||
|
|
@ -3820,6 +3825,27 @@ private:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handleSetFocus()
|
||||||
|
{
|
||||||
|
/* When the HWND receives Focus from the system it sends a
|
||||||
|
UIA_AutomationFocusChangedEventId notification redirecting the focus to the HWND
|
||||||
|
itself. This is a built-in behaviour of the HWND.
|
||||||
|
|
||||||
|
This means that whichever JUCE managed provider was active before the entire
|
||||||
|
window lost and then regained the focus, loses its focused state, and the
|
||||||
|
window's root element will become focused under which all JUCE managed providers
|
||||||
|
can be found.
|
||||||
|
|
||||||
|
This needs to be reflected on currentlyFocusedHandler so that the JUCE
|
||||||
|
accessibility mechanisms can detect that the root window got the focus, and send
|
||||||
|
another FocusChanged event to the system to redirect focus to a JUCE managed
|
||||||
|
provider if necessary.
|
||||||
|
*/
|
||||||
|
AccessibilityHandler::clearCurrentlyFocusedHandler();
|
||||||
|
updateKeyModifiers();
|
||||||
|
handleFocusGain();
|
||||||
|
}
|
||||||
|
|
||||||
LRESULT peerWindowProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam)
|
LRESULT peerWindowProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
switch (message)
|
switch (message)
|
||||||
|
|
@ -4120,23 +4146,14 @@ private:
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
case WM_SETFOCUS:
|
case WM_SETFOCUS:
|
||||||
/* When the HWND receives Focus from the system it sends a
|
mouseActivateFlags |= gotSetFocus;
|
||||||
UIA_AutomationFocusChangedEventId notification redirecting the focus to the HWND
|
|
||||||
itself. This is a built-in behaviour of the HWND.
|
|
||||||
|
|
||||||
This means that whichever JUCE managed provider was active before the entire
|
// If we've received a MOUSEACTIVATE, wait until we've seen the relevant mouse event
|
||||||
window lost and then regained the focus, loses its focused state, and the
|
// before updating the focus.
|
||||||
window's root element will become focused under which all JUCE managed providers
|
if ((mouseActivateFlags & gotMouseActivate) != 0)
|
||||||
can be found.
|
break;
|
||||||
|
|
||||||
This needs to be reflected on currentlyFocusedHandler so that the JUCE
|
handleSetFocus();
|
||||||
accessibility mechanisms can detect that the root window got the focus, and send
|
|
||||||
another FocusChanged event to the system to redirect focus to a JUCE managed
|
|
||||||
provider if necessary.
|
|
||||||
*/
|
|
||||||
AccessibilityHandler::clearCurrentlyFocusedHandler();
|
|
||||||
updateKeyModifiers();
|
|
||||||
handleFocusGain();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_KILLFOCUS:
|
case WM_KILLFOCUS:
|
||||||
|
|
@ -4186,10 +4203,15 @@ private:
|
||||||
|
|
||||||
case WM_POINTERACTIVATE:
|
case WM_POINTERACTIVATE:
|
||||||
case WM_MOUSEACTIVATE:
|
case WM_MOUSEACTIVATE:
|
||||||
|
{
|
||||||
|
mouseActivateFlags = 0;
|
||||||
|
|
||||||
if (! component.getMouseClickGrabsKeyboardFocus())
|
if (! component.getMouseClickGrabsKeyboardFocus())
|
||||||
return MA_NOACTIVATE;
|
return MA_NOACTIVATE;
|
||||||
|
|
||||||
|
mouseActivateFlags |= gotMouseActivate;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case WM_SHOWWINDOW:
|
case WM_SHOWWINDOW:
|
||||||
if (wParam != 0)
|
if (wParam != 0)
|
||||||
|
|
@ -4731,6 +4753,26 @@ private:
|
||||||
IMEHandler imeHandler;
|
IMEHandler imeHandler;
|
||||||
bool shouldIgnoreModalDismiss = false;
|
bool shouldIgnoreModalDismiss = false;
|
||||||
|
|
||||||
|
/* When the user clicks on a window, the window gets sent WM_MOUSEACTIVATE, WM_ACTIVATE,
|
||||||
|
and WM_SETFOCUS, before sending a WM_LBUTTONDOWN or other pointer event.
|
||||||
|
However, if the WM_SETFOCUS message immediately calls SetFocus to move the focus to a
|
||||||
|
different window (e.g. a foreground modal window), then no mouse event will be sent to the
|
||||||
|
initially-activated window. This differs from the behaviour on other platforms, where the
|
||||||
|
mouse event always reaches the activated window. Failing to emit a mouse event breaks user
|
||||||
|
interaction: in the Toolbars pane of the WidgetsDemo, we create a foreground modal
|
||||||
|
customisation dialog. The window containing the toolbar is not modal, but still expects to
|
||||||
|
receive mouse events so that the toolbar buttons can be dragged around.
|
||||||
|
|
||||||
|
To avoid the system eating the mouse event sent to the initially-activated window, we
|
||||||
|
postpone processing the WM_SETFOCUS until *after* the activation mouse event.
|
||||||
|
*/
|
||||||
|
enum MouseActivateFlags : uint8_t
|
||||||
|
{
|
||||||
|
gotMouseActivate = 1 << 0,
|
||||||
|
gotSetFocus = 1 << 1,
|
||||||
|
};
|
||||||
|
uint8_t mouseActivateFlags = 0;
|
||||||
|
|
||||||
ScopedSuspendResumeNotificationRegistration suspendResumeRegistration;
|
ScopedSuspendResumeNotificationRegistration suspendResumeRegistration;
|
||||||
std::optional<TimedCallback> monitorUpdateTimer;
|
std::optional<TimedCallback> monitorUpdateTimer;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue