diff options
Diffstat (limited to 'src/testlib/qtestmouse.h')
-rw-r--r-- | src/testlib/qtestmouse.h | 146 |
1 files changed, 59 insertions, 87 deletions
diff --git a/src/testlib/qtestmouse.h b/src/testlib/qtestmouse.h index 4848462be6..567d80c521 100644 --- a/src/testlib/qtestmouse.h +++ b/src/testlib/qtestmouse.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtTest module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QTESTMOUSE_H #define QTESTMOUSE_H @@ -77,7 +41,6 @@ namespace QTest { enum MouseAction { MousePress, MouseRelease, MouseClick, MouseDClick, MouseMove }; - extern Q_TESTLIB_EXPORT Qt::MouseButton lastMouseButton; // ### unsued extern Q_TESTLIB_EXPORT int lastMouseTimestamp; // This value is used to emulate timestamps to avoid creating double clicks by mistake. @@ -85,13 +48,22 @@ namespace QTest // to depend on platform themes. static const int mouseDoubleClickInterval = 500; -/*! \internal - - This function mocks all mouse events by bypassing the windowing system. The - result is that the mouse events do not come from the system via Qt platform - plugins, but are created on the spot and immediately available for processing - by Qt. -*/ + /*! \internal + This function creates a QPA mouse event of type specified by \a action + and calls QWindowSystemInterface::handleMouseEvent(), simulating the + windowing system and bypassing the platform plugin. \a delay is the + amount of time to be added to the simulated clock so that + QInputEvent::timestamp() will be greater than that of the previous + event. We expect all event-handling code to rely on the event + timestamps, not the system clock; therefore tests can be run faster + than real-time. + + If \a delay is not given, a default minimum mouse delay is used, and + unintended double-click events are prevented by incrementing the + timestamp by 500ms after each mouse release. Therefore, to test + double-clicks, it's necessary to give a realistic \a delay value (for + example, 10ms). + */ static void mouseEvent(MouseAction action, QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey, QPoint pos, int delay=-1) { @@ -101,23 +73,19 @@ namespace QTest // pos is in window local coordinates const QSize windowSize = window->geometry().size(); if (windowSize.width() <= pos.x() || windowSize.height() <= pos.y()) { - QTest::qWarn(qPrintable(QString::fromLatin1("Mouse event at %1, %2 occurs outside of target window (%3x%4).") - .arg(pos.x()).arg(pos.y()).arg(windowSize.width()).arg(windowSize.height()))); + qWarning("Mouse event at %d, %d occurs outside target window (%dx%d).", + pos.x(), pos.y(), windowSize.width(), windowSize.height()); } - if (delay == -1 || delay < defaultMouseDelay()) - delay = defaultMouseDelay(); - if (delay > 0) { - QTest::qWait(delay); - lastMouseTimestamp += delay; - } + int actualDelay = (delay == -1 || delay < defaultMouseDelay()) ? defaultMouseDelay() : delay; + lastMouseTimestamp += qMax(1, actualDelay); if (pos.isNull()) pos = QPoint(window->width() / 2, window->height() / 2); - QTEST_ASSERT(uint(stateKey) == 0 || stateKey & Qt::KeyboardModifierMask); + QTEST_ASSERT(!stateKey || stateKey & Qt::KeyboardModifierMask); - stateKey &= static_cast<unsigned int>(Qt::KeyboardModifierMask); + stateKey &= Qt::KeyboardModifierMask; QPointF global = window->mapToGlobal(pos); QPointer<QWindow> w(window); @@ -128,30 +96,29 @@ namespace QTest case MouseDClick: qtestMouseButtons.setFlag(button, true); qt_handleMouseEvent(w, pos, global, qtestMouseButtons, button, QEvent::MouseButtonPress, - stateKey, ++lastMouseTimestamp); + stateKey, lastMouseTimestamp); qtestMouseButtons.setFlag(button, false); qt_handleMouseEvent(w, pos, global, qtestMouseButtons, button, QEvent::MouseButtonRelease, - stateKey, ++lastMouseTimestamp); + stateKey, lastMouseTimestamp); Q_FALLTHROUGH(); case MousePress: case MouseClick: qtestMouseButtons.setFlag(button, true); qt_handleMouseEvent(w, pos, global, qtestMouseButtons, button, QEvent::MouseButtonPress, - stateKey, ++lastMouseTimestamp); - lastMouseButton = button; // ### unsued + stateKey, lastMouseTimestamp); if (action == MousePress) break; Q_FALLTHROUGH(); case MouseRelease: qtestMouseButtons.setFlag(button, false); qt_handleMouseEvent(w, pos, global, qtestMouseButtons, button, QEvent::MouseButtonRelease, - stateKey, ++lastMouseTimestamp); - lastMouseTimestamp += mouseDoubleClickInterval; // avoid double clicks being generated - lastMouseButton = Qt::NoButton; // ### unsued + stateKey, lastMouseTimestamp); + if (delay == -1) + lastMouseTimestamp += mouseDoubleClickInterval; // avoid double clicks being generated break; case MouseMove: qt_handleMouseEvent(w, pos, global, qtestMouseButtons, Qt::NoButton, QEvent::MouseMove, - stateKey, ++lastMouseTimestamp); + stateKey, lastMouseTimestamp); break; default: QTEST_ASSERT(false); @@ -196,10 +163,7 @@ namespace QTest if (delay == -1 || delay < defaultMouseDelay()) delay = defaultMouseDelay(); - if (delay > 0) { - QTest::qWait(delay); - lastMouseTimestamp += delay; - } + lastMouseTimestamp += qMax(1, delay); if (action == MouseClick) { mouseEvent(MousePress, widget, button, stateKey, pos); @@ -207,43 +171,51 @@ namespace QTest return; } - QTEST_ASSERT(stateKey == 0 || stateKey & Qt::KeyboardModifierMask); + QTEST_ASSERT(!stateKey || stateKey & Qt::KeyboardModifierMask); - stateKey &= static_cast<unsigned int>(Qt::KeyboardModifierMask); + stateKey &= Qt::KeyboardModifierMask; - QMouseEvent me(QEvent::User, QPointF(), Qt::LeftButton, QTestPrivate::qtestMouseButtons, stateKey, QPointingDevice::primaryPointingDevice()); + QEvent::Type meType = QEvent::None; + using namespace QTestPrivate; switch (action) { case MousePress: - me = QMouseEvent(QEvent::MouseButtonPress, pos, widget->mapToGlobal(pos), button, button, stateKey, QPointingDevice::primaryPointingDevice()); - me.setTimestamp(++lastMouseTimestamp); + qtestMouseButtons.setFlag(button, true); + meType = QEvent::MouseButtonPress; break; case MouseRelease: - me = QMouseEvent(QEvent::MouseButtonRelease, pos, widget->mapToGlobal(pos), button, Qt::MouseButton(), stateKey, QPointingDevice::primaryPointingDevice()); - me.setTimestamp(++lastMouseTimestamp); - lastMouseTimestamp += mouseDoubleClickInterval; // avoid double clicks being generated + qtestMouseButtons.setFlag(button, false); + meType = QEvent::MouseButtonRelease; break; case MouseDClick: - me = QMouseEvent(QEvent::MouseButtonDblClick, pos, widget->mapToGlobal(pos), button, button, stateKey, QPointingDevice::primaryPointingDevice()); - me.setTimestamp(++lastMouseTimestamp); + qtestMouseButtons.setFlag(button, true); + meType = QEvent::MouseButtonDblClick; break; case MouseMove: - QCursor::setPos(widget->mapToGlobal(pos)); -#ifdef Q_OS_MAC - QTest::qWait(20); -#else - qApp->processEvents(); -#endif - return; + // ### Qt 7: compatibility with < Qt 6.3, we should not rely on QCursor::setPos + // for generating mouse move events, and code that depends on QCursor::pos should + // be tested using QCursor::setPos explicitly. + if (qtestMouseButtons == Qt::NoButton) { + QCursor::setPos(widget->mapToGlobal(pos)); + qApp->processEvents(); + return; + } + meType = QEvent::MouseMove; + break; default: QTEST_ASSERT(false); } + QMouseEvent me(meType, pos, widget->mapToGlobal(pos), button, qtestMouseButtons, stateKey, QPointingDevice::primaryPointingDevice()); + me.setTimestamp(lastMouseTimestamp); + if (action == MouseRelease) // avoid double clicks being generated + lastMouseTimestamp += mouseDoubleClickInterval; + QSpontaneKeyEvent::setSpontaneous(&me); if (!qApp->notify(widget, &me)) { static const char *const mouseActionNames[] = { "MousePress", "MouseRelease", "MouseClick", "MouseDClick", "MouseMove" }; - QString warning = QString::fromLatin1("Mouse event \"%1\" not accepted by receiving widget"); - QTest::qWarn(warning.arg(QString::fromLatin1(mouseActionNames[static_cast<int>(action)])).toLatin1().data()); + qWarning("Mouse event \"%s\" not accepted by receiving widget", + mouseActionNames[static_cast<int>(action)]); } #endif } |