Windows QPA: Discard spurious mouse move events
Windows sends a mouse move with no buttons pressed to signal "Enter" when a window is shown over the cursor. Discard the event and only use it for generating QEvent::Enter as not to confuse tests. This is preparing for the use of the new QPA API for mouse events. Change-Id: I3eb7f3dad82d27d0b425c7eaf34b1eee11592074 Reviewed-by: Gatis Paeglis <gatis.paeglis@qt.io>
This commit is contained in:
parent
d08e0e861a
commit
bb45b75f3d
@ -178,6 +178,8 @@ Qt::MouseButtons QWindowsMouseHandler::queryMouseButtons()
|
||||
return result;
|
||||
}
|
||||
|
||||
static QPoint lastMouseMovePos;
|
||||
|
||||
bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
|
||||
QtWindows::WindowsEventType et,
|
||||
MSG msg, LRESULT *result)
|
||||
@ -192,6 +194,29 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
|
||||
if (et == QtWindows::MouseWheelEvent)
|
||||
return translateMouseWheelEvent(window, hwnd, msg, result);
|
||||
|
||||
const QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
|
||||
QPoint clientPosition;
|
||||
QPoint globalPosition;
|
||||
if (et & QtWindows::NonClientEventFlag) {
|
||||
globalPosition = winEventPosition;
|
||||
clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition);
|
||||
} else {
|
||||
clientPosition = winEventPosition;
|
||||
globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition);
|
||||
}
|
||||
|
||||
// Windows sends a mouse move with no buttons pressed to signal "Enter"
|
||||
// when a window is shown over the cursor. Discard the event and only use
|
||||
// it for generating QEvent::Enter to be consistent with other platforms -
|
||||
// X11 and macOS.
|
||||
bool discardEvent = false;
|
||||
if (msg.message == WM_MOUSEMOVE) {
|
||||
const bool samePosition = globalPosition == lastMouseMovePos;
|
||||
lastMouseMovePos = globalPosition;
|
||||
if (msg.wParam == 0 && (m_windowUnderMouse.isNull() || samePosition))
|
||||
discardEvent = true;
|
||||
}
|
||||
|
||||
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
|
||||
|
||||
// Check for events synthesized from touch. Lower byte is touch index, 0 means pen.
|
||||
@ -210,10 +235,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
|
||||
}
|
||||
}
|
||||
|
||||
const QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
|
||||
if (et & QtWindows::NonClientEventFlag) {
|
||||
const QPoint globalPosition = winEventPosition;
|
||||
const QPoint clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition);
|
||||
const Qt::MouseButtons buttons = QWindowsMouseHandler::queryMouseButtons();
|
||||
QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition,
|
||||
globalPosition, buttons,
|
||||
@ -269,7 +291,6 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
|
||||
}
|
||||
}
|
||||
|
||||
const QPoint globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition);
|
||||
// In this context, neither an invisible nor a transparent window (transparent regarding mouse
|
||||
// events, "click-through") can be considered as the window under mouse.
|
||||
QWindow *currentWindowUnderMouse = platformWindow->hasMouseCapture() ?
|
||||
@ -369,9 +390,11 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
|
||||
m_windowUnderMouse = currentWindowUnderMouse;
|
||||
}
|
||||
|
||||
QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons,
|
||||
QWindowsKeyMapper::queryKeyboardModifiers(),
|
||||
source);
|
||||
if (!discardEvent) {
|
||||
QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons,
|
||||
QWindowsKeyMapper::queryKeyboardModifiers(),
|
||||
source);
|
||||
}
|
||||
m_previousCaptureWindow = hasCapture ? window : 0;
|
||||
// QTBUG-48117, force synchronous handling for the extra buttons so that WM_APPCOMMAND
|
||||
// is sent for unhandled WM_XBUTTONDOWN.
|
||||
|
@ -97,6 +97,7 @@ private slots:
|
||||
void modalWindowPosition();
|
||||
#ifndef QT_NO_CURSOR
|
||||
void modalWindowEnterEventOnHide_QTBUG35109();
|
||||
void spuriousMouseMove();
|
||||
#endif
|
||||
void windowsTransientChildren();
|
||||
void requestUpdate();
|
||||
@ -887,7 +888,7 @@ void tst_QWindow::isActive()
|
||||
QVERIFY(child.isActive());
|
||||
}
|
||||
|
||||
class InputTestWindow : public QWindow
|
||||
class InputTestWindow : public ColoredWindow
|
||||
{
|
||||
public:
|
||||
void keyPressEvent(QKeyEvent *event) {
|
||||
@ -981,7 +982,9 @@ public:
|
||||
enterEventCount = leaveEventCount = 0;
|
||||
}
|
||||
|
||||
InputTestWindow() {
|
||||
explicit InputTestWindow(const QColor &color = Qt::white, QWindow *parent = nullptr)
|
||||
: ColoredWindow(color, parent)
|
||||
{
|
||||
keyPressCode = keyReleaseCode = 0;
|
||||
mousePressButton = mouseReleaseButton = mouseMoveButton = 0;
|
||||
ignoreMouse = ignoreTouch = false;
|
||||
@ -2202,7 +2205,51 @@ void tst_QWindow::modalWindowEnterEventOnHide_QTBUG35109()
|
||||
QTRY_COMPARE(root.enterEventCount, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Verify that no spurious mouse move events are received. On Windows, there is
|
||||
// no enter event, the OS sends mouse move events instead. Test that the QPA
|
||||
// plugin properly suppresses those since they can interfere with tests.
|
||||
// Simulate a main window setup with a modal dialog on top, keep the cursor
|
||||
// in the center and check that no mouse events are recorded.
|
||||
void tst_QWindow::spuriousMouseMove()
|
||||
{
|
||||
const QString &platformName = QGuiApplication::platformName();
|
||||
if (platformName == QLatin1String("offscreen") || platformName == QLatin1String("cocoa"))
|
||||
QSKIP("No enter events sent");
|
||||
const QRect screenGeometry = QGuiApplication::primaryScreen()->geometry();
|
||||
const QPoint center = screenGeometry.center();
|
||||
QCursor::setPos(center);
|
||||
QRect windowGeometry(QPoint(), 2 * m_testWindowSize);
|
||||
windowGeometry.moveCenter(center);
|
||||
QTRY_COMPARE(QCursor::pos(), center);
|
||||
InputTestWindow topLevel;
|
||||
topLevel.setTitle(QTest::currentTestFunction());
|
||||
topLevel.setGeometry(windowGeometry);
|
||||
topLevel.show();
|
||||
QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
|
||||
QTRY_VERIFY(topLevel.enterEventCount > 0);
|
||||
InputTestWindow dialog(Qt::yellow);
|
||||
dialog.setTransientParent(&topLevel);
|
||||
dialog.setTitle("Dialog " + topLevel.title());
|
||||
dialog.setModality(Qt::ApplicationModal);
|
||||
windowGeometry.setSize(m_testWindowSize);
|
||||
windowGeometry.moveCenter(center);
|
||||
dialog.setGeometry(windowGeometry);
|
||||
dialog.show();
|
||||
QVERIFY(QTest::qWaitForWindowExposed(&dialog));
|
||||
QTRY_VERIFY(dialog.enterEventCount > 0);
|
||||
dialog.setVisible(false);
|
||||
QCOMPARE(dialog.mousePressedCount, 0);
|
||||
QCOMPARE(dialog.mouseReleasedCount, 0);
|
||||
QCOMPARE(dialog.mouseMovedCount, 0);
|
||||
QCOMPARE(dialog.mouseDoubleClickedCount, 0);
|
||||
topLevel.setVisible(false);
|
||||
QCOMPARE(topLevel.mousePressedCount, 0);
|
||||
QCOMPARE(topLevel.mouseReleasedCount, 0);
|
||||
QCOMPARE(topLevel.mouseMovedCount, 0);
|
||||
QCOMPARE(topLevel.mouseDoubleClickedCount, 0);
|
||||
}
|
||||
#endif // !QT_NO_CURSOR
|
||||
|
||||
static bool isNativeWindowVisible(const QWindow *window)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user