/**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** 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 General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** 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-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include Q_LOGGING_CATEGORY(lcTests, "qt.gui.tests") class MouseEventWidget : public QWindow { public: MouseEventWidget(QWindow *parent = nullptr) : QWindow(parent) { setGeometry(100, 100, 100, 100); } bool grabExclusive = false; bool grabPassive = false; bool mousePressEventRecieved; bool mouseReleaseEventRecieved; int mousePressButton; int mousePressButtons; int mousePressModifiers; int mouseReleaseButton; int mouseReleaseButtons; int mouseReleaseModifiers; ulong timestamp; ulong pressTimestamp; ulong lastTimestamp; QVector2D velocity; protected: void mousePressEvent(QMouseEvent *e) override { const auto &firstPoint = e->point(0); qCDebug(lcTests) << e << firstPoint; timestamp = firstPoint.timestamp(); lastTimestamp = firstPoint.lastTimestamp(); if (e->type() == QEvent::MouseButtonPress) { auto firstPoint = e->points().first(); QCOMPARE(e->exclusiveGrabber(firstPoint), nullptr); QVERIFY(e->passiveGrabbers(firstPoint).isEmpty()); QCOMPARE(firstPoint.timeHeld(), 0); QCOMPARE(firstPoint.pressTimestamp(), e->timestamp()); pressTimestamp = e->timestamp(); } QWindow::mousePressEvent(e); mousePressButton = e->button(); mousePressButtons = e->buttons(); mousePressModifiers = e->modifiers(); mousePressEventRecieved = true; e->accept(); // It's not normal for QWindow to be the grabber, but that's easier to test // without needing to create child ojects. if (grabExclusive) e->setExclusiveGrabber(firstPoint, this); if (grabPassive) e->addPassiveGrabber(firstPoint, this); } void mouseMoveEvent(QMouseEvent *e) override { qCDebug(lcTests) << e << e->points().first(); timestamp = e->points().first().timestamp(); lastTimestamp = e->points().first().lastTimestamp(); velocity = e->points().first().velocity(); } void mouseReleaseEvent(QMouseEvent *e) override { qCDebug(lcTests) << e << e->points().first(); QWindow::mouseReleaseEvent(e); mouseReleaseButton = e->button(); mouseReleaseButtons = e->buttons(); mouseReleaseModifiers = e->modifiers(); timestamp = e->points().first().timestamp(); lastTimestamp = e->points().first().lastTimestamp(); velocity = e->points().first().velocity(); mouseReleaseEventRecieved = true; e->accept(); } }; class tst_QMouseEvent : public QObject { Q_OBJECT public slots: void initTestCase(); void cleanupTestCase(); void init(); private slots: void mouseEventBasic(); void checkMousePressEvent_data(); void checkMousePressEvent(); void checkMouseReleaseEvent_data(); void checkMouseReleaseEvent(); void grabbers_data(); void grabbers(); void velocity(); private: MouseEventWidget* testMouseWidget; }; void tst_QMouseEvent::initTestCase() { testMouseWidget = new MouseEventWidget; testMouseWidget->show(); } void tst_QMouseEvent::cleanupTestCase() { delete testMouseWidget; } void tst_QMouseEvent::init() { testMouseWidget->mousePressEventRecieved = false; testMouseWidget->mouseReleaseEventRecieved = false; testMouseWidget->mousePressButton = 0; testMouseWidget->mousePressButtons = 0; testMouseWidget->mousePressModifiers = 0; testMouseWidget->mouseReleaseButton = 0; testMouseWidget->mouseReleaseButtons = 0; testMouseWidget->mouseReleaseModifiers = 0; } void tst_QMouseEvent::mouseEventBasic() { QPointF local(100, 100); QPointF scene(200, 200); QPointF screen(300, 300); // Press left button QMouseEvent me(QEvent::MouseButtonPress, local, scene, screen, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); QVERIFY(me.isInputEvent()); QVERIFY(me.isPointerEvent()); QCOMPARE(me.isAccepted(), true); QCOMPARE(me.button(), Qt::LeftButton); QCOMPARE(me.buttons(), Qt::LeftButton); QVERIFY(me.isPressEvent()); QVERIFY(!me.isReleaseEvent()); QCOMPARE(me.position(), local); QCOMPARE(me.scenePosition(), scene); QCOMPARE(me.globalPosition(), screen); // Press right button while left is already pressed me = QMouseEvent(QEvent::MouseButtonPress, local, scene, screen, Qt::RightButton, Qt::LeftButton | Qt::RightButton, Qt::NoModifier); QVERIFY(me.isPressEvent()); QVERIFY(!me.isReleaseEvent()); // Release right button while left is still pressed me = QMouseEvent(QEvent::MouseButtonRelease, local, scene, screen, Qt::RightButton, Qt::LeftButton, Qt::NoModifier); QVERIFY(!me.isPressEvent()); QVERIFY(me.isReleaseEvent()); // Release left button in the usual way me = QMouseEvent(QEvent::MouseButtonRelease, local, scene, screen, Qt::LeftButton, Qt::NoButton, Qt::NoModifier); QVERIFY(!me.isPressEvent()); QVERIFY(me.isReleaseEvent()); } void tst_QMouseEvent::checkMousePressEvent_data() { QTest::addColumn("buttonPressed"); QTest::addColumn("keyPressed"); QTest::newRow("leftButton-nokey") << int(Qt::LeftButton) << int(Qt::NoButton); QTest::newRow("leftButton-shiftkey") << int(Qt::LeftButton) << int(Qt::ShiftModifier); QTest::newRow("leftButton-controlkey") << int(Qt::LeftButton) << int(Qt::ControlModifier); QTest::newRow("leftButton-altkey") << int(Qt::LeftButton) << int(Qt::AltModifier); QTest::newRow("leftButton-metakey") << int(Qt::LeftButton) << int(Qt::MetaModifier); QTest::newRow("rightButton-nokey") << int(Qt::RightButton) << int(Qt::NoButton); QTest::newRow("rightButton-shiftkey") << int(Qt::RightButton) << int(Qt::ShiftModifier); QTest::newRow("rightButton-controlkey") << int(Qt::RightButton) << int(Qt::ControlModifier); QTest::newRow("rightButton-altkey") << int(Qt::RightButton) << int(Qt::AltModifier); QTest::newRow("rightButton-metakey") << int(Qt::RightButton) << int(Qt::MetaModifier); QTest::newRow("middleButton-nokey") << int(Qt::MiddleButton) << int(Qt::NoButton); QTest::newRow("middleButton-shiftkey") << int(Qt::MiddleButton) << int(Qt::ShiftModifier); QTest::newRow("middleButton-controlkey") << int(Qt::MiddleButton) << int(Qt::ControlModifier); QTest::newRow("middleButton-altkey") << int(Qt::MiddleButton) << int(Qt::AltModifier); QTest::newRow("middleButton-metakey") << int(Qt::MiddleButton) << int(Qt::MetaModifier); } void tst_QMouseEvent::checkMousePressEvent() { QFETCH(int,buttonPressed); QFETCH(int,keyPressed); int button = buttonPressed; int buttons = button; int modifiers = keyPressed; QTest::mousePress(testMouseWidget, Qt::MouseButton(buttonPressed), Qt::KeyboardModifiers(keyPressed)); qApp->processEvents(); QVERIFY(testMouseWidget->mousePressEventRecieved); QCOMPARE(testMouseWidget->mousePressButton, button); QCOMPARE(testMouseWidget->mousePressButtons, buttons); QCOMPARE(testMouseWidget->mousePressModifiers, modifiers); QTest::mouseRelease(testMouseWidget, Qt::MouseButton(buttonPressed), Qt::KeyboardModifiers(keyPressed)); qApp->processEvents(); } void tst_QMouseEvent::checkMouseReleaseEvent_data() { QTest::addColumn("buttonReleased"); QTest::addColumn("keyPressed"); QTest::newRow("leftButton-nokey") << int(Qt::LeftButton) << int(Qt::NoButton); QTest::newRow("leftButton-shiftkey") << int(Qt::LeftButton) << int(Qt::ShiftModifier); QTest::newRow("leftButton-controlkey") << int(Qt::LeftButton) << int(Qt::ControlModifier); QTest::newRow("leftButton-altkey") << int(Qt::LeftButton) << int(Qt::AltModifier); QTest::newRow("leftButton-metakey") << int(Qt::LeftButton) << int(Qt::MetaModifier); QTest::newRow("rightButton-nokey") << int(Qt::RightButton) << int(Qt::NoButton); QTest::newRow("rightButton-shiftkey") << int(Qt::RightButton) << int(Qt::ShiftModifier); QTest::newRow("rightButton-controlkey") << int(Qt::RightButton) << int(Qt::ControlModifier); QTest::newRow("rightButton-altkey") << int(Qt::RightButton) << int(Qt::AltModifier); QTest::newRow("rightButton-metakey") << int(Qt::RightButton) << int(Qt::MetaModifier); QTest::newRow("middleButton-nokey") << int(Qt::MiddleButton) << int(Qt::NoButton); QTest::newRow("middleButton-shiftkey") << int(Qt::MiddleButton) << int(Qt::ShiftModifier); QTest::newRow("middleButton-controlkey") << int(Qt::MiddleButton) << int(Qt::ControlModifier); QTest::newRow("middleButton-altkey") << int(Qt::MiddleButton) << int(Qt::AltModifier); QTest::newRow("middleButton-metakey") << int(Qt::MiddleButton) << int(Qt::MetaModifier); } void tst_QMouseEvent::checkMouseReleaseEvent() { QFETCH(int,buttonReleased); QFETCH(int,keyPressed); int button = buttonReleased; int buttons = 0; int modifiers = keyPressed; QTest::mouseClick(testMouseWidget, Qt::MouseButton(buttonReleased), Qt::KeyboardModifiers(keyPressed)); qApp->processEvents(); QVERIFY(testMouseWidget->mouseReleaseEventRecieved); QCOMPARE(testMouseWidget->mouseReleaseButton, button); QCOMPARE(testMouseWidget->mouseReleaseButtons, buttons); QCOMPARE(testMouseWidget->mouseReleaseModifiers, modifiers); } void tst_QMouseEvent::grabbers_data() { QTest::addColumn("grabExclusive"); QTest::addColumn("grabPassive"); QTest::newRow("no grab") << false << false; QTest::newRow("exclusive") << true << false; QTest::newRow("passive") << false << true; } void tst_QMouseEvent::grabbers() { QFETCH(bool, grabExclusive); QFETCH(bool, grabPassive); testMouseWidget->grabExclusive = grabExclusive; testMouseWidget->grabPassive = grabPassive; QTest::mousePress(testMouseWidget, Qt::LeftButton, Qt::KeyboardModifiers(), {10, 10}); auto devPriv = QPointingDevicePrivate::get(QPointingDevice::primaryPointingDevice()); QCOMPARE(devPriv->activePoints.count(), 1); // Ensure that grabbers are persistent between events, within the stored touchpoints auto firstEPD = devPriv->pointById(0); QCOMPARE(firstEPD->eventPoint.pressTimestamp(), testMouseWidget->pressTimestamp); QCOMPARE(firstEPD->exclusiveGrabber, grabExclusive ? testMouseWidget : nullptr); QCOMPARE(firstEPD->passiveGrabbers.count(), grabPassive ? 1 : 0); if (grabPassive) QCOMPARE(firstEPD->passiveGrabbers.first(), testMouseWidget); // Ensure that grabbers are forgotten after release delivery QTest::mouseRelease(testMouseWidget, Qt::LeftButton, Qt::KeyboardModifiers(), {10, 10}); QTRY_COMPARE(firstEPD->exclusiveGrabber, nullptr); QCOMPARE(firstEPD->passiveGrabbers.count(), 0); } void tst_QMouseEvent::velocity() { testMouseWidget->grabExclusive = true; auto devPriv = QPointingDevicePrivate::get(const_cast(QPointingDevice::primaryPointingDevice())); devPriv->activePoints.clear(); qCDebug(lcTests) << "sending mouse press event"; QPoint pos(10, 10); QTest::mousePress(testMouseWidget, Qt::LeftButton, Qt::KeyboardModifiers(), pos); QCOMPARE(devPriv->activePoints.count(), 1); QVERIFY(devPriv->activePoints.count() <= 2); const auto &firstPoint = devPriv->pointById(0)->eventPoint; QVERIFY(firstPoint.timestamp() > 0); QCOMPARE(firstPoint.state(), QEventPoint::State::Pressed); ulong timestamp = firstPoint.timestamp(); for (int i = 1; i < 4; ++i) { qCDebug(lcTests) << "sending mouse move event" << i; pos += {10, 10}; QTest::mouseMove(testMouseWidget, pos, 1); qApp->processEvents(); qCDebug(lcTests) << firstPoint; // currently we expect it to be updated in-place in devPriv->activePoints QVERIFY(firstPoint.timestamp() > timestamp); QVERIFY(testMouseWidget->timestamp > testMouseWidget->lastTimestamp); QCOMPARE(testMouseWidget->timestamp, firstPoint.timestamp()); timestamp = firstPoint.timestamp(); QVERIFY(testMouseWidget->velocity.x() > 0); QVERIFY(testMouseWidget->velocity.y() > 0); } QTest::mouseRelease(testMouseWidget, Qt::LeftButton, Qt::KeyboardModifiers(), pos, 1); qCDebug(lcTests) << firstPoint; QVERIFY(testMouseWidget->velocity.x() > 0); QVERIFY(testMouseWidget->velocity.y() > 0); } QTEST_MAIN(tst_QMouseEvent) #include "tst_qmouseevent.moc"