Fix Windows mouse enter/leave event generation
QWidget::underMouse() did not report correct widget in cases where mouse was grabbed by popup, which was especially disruptive in case of QCompleter popup, as that wouldn't close anymore with off-popup clicks. Root problem was that mouse capture in Windows caused enter/leave events for QWindows to be generated incorrectly. QPlatformWindow documentation specifies that enter/leave events should be sent independent of explicit mouse grabs and only automatic mouse grabbing done when button is pressed should suppress enter/leave events. Updated Windows mouse handling to conform to this. Task-number: QTBUG-27283 Change-Id: Iecf786a702f7d29e6026c42ff8ec4c9cbf1b6ac3 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
This commit is contained in:
parent
dcc2e84fd0
commit
c119767790
@ -44,6 +44,7 @@
|
|||||||
#include "qwindowscontext.h"
|
#include "qwindowscontext.h"
|
||||||
#include "qwindowswindow.h"
|
#include "qwindowswindow.h"
|
||||||
#include "qwindowsintegration.h"
|
#include "qwindowsintegration.h"
|
||||||
|
#include "qwindowsscreen.h"
|
||||||
|
|
||||||
#include <qpa/qwindowsysteminterface.h>
|
#include <qpa/qwindowsysteminterface.h>
|
||||||
#include <QtGui/QGuiApplication>
|
#include <QtGui/QGuiApplication>
|
||||||
@ -127,6 +128,7 @@ static inline void compressMouseMove(MSG *msg)
|
|||||||
|
|
||||||
QWindowsMouseHandler::QWindowsMouseHandler() :
|
QWindowsMouseHandler::QWindowsMouseHandler() :
|
||||||
m_windowUnderMouse(0),
|
m_windowUnderMouse(0),
|
||||||
|
m_trackedWindow(0),
|
||||||
m_touchDevice(0)
|
m_touchDevice(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -162,20 +164,32 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
|
|||||||
return false; // Allow further event processing (dragging of windows).
|
return false; // Allow further event processing (dragging of windows).
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
*result = 0;
|
*result = 0;
|
||||||
if (msg.message == WM_MOUSELEAVE) {
|
if (msg.message == WM_MOUSELEAVE) {
|
||||||
// When moving out of a child, MouseMove within parent is received first
|
|
||||||
// (see below)
|
|
||||||
if (QWindowsContext::verboseEvents)
|
if (QWindowsContext::verboseEvents)
|
||||||
qDebug() << "WM_MOUSELEAVE for " << window << " current= " << m_windowUnderMouse;
|
qDebug() << "WM_MOUSELEAVE for " << window << " previous window under mouse = " << m_windowUnderMouse << " tracked window =" << m_trackedWindow;
|
||||||
if (window == m_windowUnderMouse) {
|
|
||||||
QWindowSystemInterface::handleLeaveEvent(window);
|
// When moving out of a window, WM_MOUSEMOVE within the moved-to window is received first,
|
||||||
|
// so if m_trackedWindow is not the window here, it means the cursor has left the
|
||||||
|
// application.
|
||||||
|
if (window == m_trackedWindow) {
|
||||||
|
QWindow *leaveTarget = m_windowUnderMouse ? m_windowUnderMouse : m_trackedWindow;
|
||||||
|
if (QWindowsContext::verboseEvents)
|
||||||
|
qDebug() << "Generating leave event for " << leaveTarget;
|
||||||
|
QWindowSystemInterface::handleLeaveEvent(leaveTarget);
|
||||||
|
m_trackedWindow = 0;
|
||||||
m_windowUnderMouse = 0;
|
m_windowUnderMouse = 0;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
compressMouseMove(&msg);
|
|
||||||
QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle());
|
QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle());
|
||||||
|
const QPoint globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition);
|
||||||
|
QWindow *currentWindowUnderMouse = platformWindow->hasMouseCapture() ?
|
||||||
|
QWindowsScreen::windowAt(globalPosition) : window;
|
||||||
|
|
||||||
|
compressMouseMove(&msg);
|
||||||
// Qt expects the platform plugin to capture the mouse on
|
// Qt expects the platform plugin to capture the mouse on
|
||||||
// any button press until release.
|
// any button press until release.
|
||||||
if (!platformWindow->hasMouseCapture()
|
if (!platformWindow->hasMouseCapture()
|
||||||
@ -202,22 +216,13 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Enter new window: track to generate leave event.
|
|
||||||
if (m_windowUnderMouse != window) {
|
|
||||||
// The tracking on m_windowUnderMouse might still be active and
|
|
||||||
// trigger later on.
|
|
||||||
if (m_windowUnderMouse) {
|
|
||||||
if (QWindowsContext::verboseEvents)
|
|
||||||
qDebug() << "Synthetic leave for " << m_windowUnderMouse;
|
|
||||||
QWindowSystemInterface::handleLeaveEvent(m_windowUnderMouse);
|
|
||||||
}
|
|
||||||
m_windowUnderMouse = window;
|
|
||||||
if (QWindowsContext::verboseEvents)
|
|
||||||
qDebug() << "Entering " << window;
|
|
||||||
QWindowsWindow::baseWindowOf(window)->applyCursor();
|
|
||||||
//#ifndef Q_OS_WINCE
|
|
||||||
QWindowSystemInterface::handleEnterEvent(window);
|
|
||||||
#ifndef Q_OS_WINCE
|
#ifndef Q_OS_WINCE
|
||||||
|
// Enter new window: track to generate leave event.
|
||||||
|
// If there is an active capture, we must track the actual capture window instead of window
|
||||||
|
// under cursor or leaves will trigger constantly, so always track the window we got
|
||||||
|
// native mouse event for.
|
||||||
|
if (window != m_trackedWindow) {
|
||||||
TRACKMOUSEEVENT tme;
|
TRACKMOUSEEVENT tme;
|
||||||
tme.cbSize = sizeof(TRACKMOUSEEVENT);
|
tme.cbSize = sizeof(TRACKMOUSEEVENT);
|
||||||
tme.dwFlags = TME_LEAVE;
|
tme.dwFlags = TME_LEAVE;
|
||||||
@ -225,11 +230,40 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
|
|||||||
tme.dwHoverTime = HOVER_DEFAULT; //
|
tme.dwHoverTime = HOVER_DEFAULT; //
|
||||||
if (!TrackMouseEvent(&tme))
|
if (!TrackMouseEvent(&tme))
|
||||||
qWarning("TrackMouseEvent failed.");
|
qWarning("TrackMouseEvent failed.");
|
||||||
#endif // !Q_OS_WINCE
|
m_trackedWindow = window;
|
||||||
}
|
}
|
||||||
const QPoint clientPosition = winEventPosition;
|
#endif // !Q_OS_WINCE
|
||||||
QWindowSystemInterface::handleMouseEvent(window, clientPosition,
|
|
||||||
QWindowsGeometryHint::mapToGlobal(hwnd, clientPosition),
|
// Qt expects enter/leave events for windows even when some window is capturing mouse input,
|
||||||
|
// except for automatic capture when mouse button is pressed - in that case enter/leave
|
||||||
|
// should be sent only after the last button is released.
|
||||||
|
// We need to track m_windowUnderMouse separately from m_trackedWindow, as
|
||||||
|
// Windows mouse tracking will not trigger WM_MOUSELEAVE for leaving window when
|
||||||
|
// mouse capture is set.
|
||||||
|
if (!platformWindow->hasMouseCapture()
|
||||||
|
|| !platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)) {
|
||||||
|
if (m_windowUnderMouse != currentWindowUnderMouse) {
|
||||||
|
if (m_windowUnderMouse) {
|
||||||
|
if (QWindowsContext::verboseEvents)
|
||||||
|
qDebug() << "Synthetic leave for " << m_windowUnderMouse;
|
||||||
|
QWindowSystemInterface::handleLeaveEvent(m_windowUnderMouse);
|
||||||
|
// Clear tracking if we are no longer over application,
|
||||||
|
// since we have already sent the leave.
|
||||||
|
if (!currentWindowUnderMouse)
|
||||||
|
m_trackedWindow = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentWindowUnderMouse) {
|
||||||
|
if (QWindowsContext::verboseEvents)
|
||||||
|
qDebug() << "Entering " << currentWindowUnderMouse;
|
||||||
|
QWindowsWindow::baseWindowOf(currentWindowUnderMouse)->applyCursor();
|
||||||
|
QWindowSystemInterface::handleEnterEvent(currentWindowUnderMouse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_windowUnderMouse = currentWindowUnderMouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition,
|
||||||
keyStateToMouseButtons((int)msg.wParam),
|
keyStateToMouseButtons((int)msg.wParam),
|
||||||
QWindowsKeyMapper::queryKeyboardModifiers());
|
QWindowsKeyMapper::queryKeyboardModifiers());
|
||||||
return true;
|
return true;
|
||||||
|
@ -78,6 +78,7 @@ private:
|
|||||||
MSG msg, LRESULT *result);
|
MSG msg, LRESULT *result);
|
||||||
|
|
||||||
QPointer<QWindow> m_windowUnderMouse;
|
QPointer<QWindow> m_windowUnderMouse;
|
||||||
|
QPointer<QWindow> m_trackedWindow;
|
||||||
QHash<DWORD, int> m_touchInputIDToTouchPointID;
|
QHash<DWORD, int> m_touchInputIDToTouchPointID;
|
||||||
QTouchDevice *m_touchDevice;
|
QTouchDevice *m_touchDevice;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user