/* This file is part of the KDE project SPDX-FileCopyrightText: 2021 Steffen Hartleib SPDX-License-Identifier: LGPL-2.1-or-later */ #include #include #include #include #include class KTwoFingerSwipeTest : public QObject { Q_OBJECT QPointingDevice *mDev = nullptr; QMainWindow mMainWindow; QWidget mWidget; KTwoFingerTapRecognizer *mTwoFingerRec = nullptr; Qt::GestureType mKTwoFingerTapGesture; QPoint mTouchPointPos = QPoint(100, 100); QSignalSpy *mSpyTapFinished = nullptr; QSignalSpy *mSpyTapStarted = nullptr; QSignalSpy *mSpyTapUpdated = nullptr; QSignalSpy *mSpyTapCanceled = nullptr; Q_SIGNALS: void tapStarted(KTwoFingerTap *); void tapFinished(KTwoFingerTap *); void tapUpdated(KTwoFingerTap *); void tapCanceled(KTwoFingerTap *); protected: bool eventFilter(QObject *watched, QEvent *e) override { if (e->type() == QEvent::Gesture) { QGestureEvent *gEvent = static_cast(e); KTwoFingerTap *tap = static_cast(gEvent->gesture(mKTwoFingerTapGesture)); if (tap) { const Qt::GestureState state = tap->state(); if (state == Qt::GestureFinished) { Q_EMIT tapFinished(tap); } else if (state == Qt::GestureStarted) { Q_EMIT tapStarted(tap); } else if (state == Qt::GestureUpdated) { Q_EMIT tapUpdated(tap); } else if (state == Qt::GestureCanceled) { Q_EMIT tapCanceled(tap); } } e->accept(); return true; } return QObject::eventFilter(watched, e); } protected Q_SLOTS: void slotTapFinished (KTwoFingerTap *tap) { compareGesturePositions(tap); } void slotTapStarted (KTwoFingerTap *tap) { compareGesturePositions(tap); } void slotTapUpdated (KTwoFingerTap *tap) { compareGesturePositions(tap); } void slotTapCanceled (KTwoFingerTap *tap) { compareGesturePositions(tap); } private: void compareGesturePositions(KTwoFingerTap *tap) { QCOMPARE(tap->pos(), mTouchPointPos); QCOMPARE(tap->screenPos(), mWidget.mapToGlobal(mTouchPointPos)); QCOMPARE(tap->hotSpot(), mWidget.mapToGlobal(mTouchPointPos)); QCOMPARE(tap->scenePos(), mWidget.mapToGlobal(mTouchPointPos)); QVERIFY(tap->hasHotSpot()); } void clearSignalSpys() { mSpyTapFinished->clear(); mSpyTapCanceled->clear(); mSpyTapUpdated->clear(); mSpyTapStarted->clear(); } private Q_SLOTS: void cleanupTestCase() { delete mSpyTapFinished; delete mSpyTapCanceled; delete mSpyTapUpdated; delete mSpyTapStarted; } void initTestCase() { mDev = QTest::createTouchDevice(); mMainWindow.setGeometry(0, 0, 500, 500); mMainWindow.setCentralWidget(&mWidget); mMainWindow.show(); mWidget.installEventFilter(this); mWidget.setAttribute(Qt::WA_AcceptTouchEvents); QVERIFY(QTest::qWaitForWindowActive(&mMainWindow)); QVERIFY(QTest::qWaitForWindowActive(&mWidget)); mTwoFingerRec = new KTwoFingerTapRecognizer(); QVERIFY(mTwoFingerRec); mKTwoFingerTapGesture = QGestureRecognizer::registerRecognizer(mTwoFingerRec); QVERIFY(mKTwoFingerTapGesture & Qt::CustomGesture); mWidget.grabGesture(mKTwoFingerTapGesture); connect(this, &KTwoFingerSwipeTest::tapFinished, this, &KTwoFingerSwipeTest::slotTapFinished); connect(this, &KTwoFingerSwipeTest::tapStarted, this, &KTwoFingerSwipeTest::slotTapStarted); connect(this, &KTwoFingerSwipeTest::tapUpdated, this, &KTwoFingerSwipeTest::slotTapUpdated); connect(this, &KTwoFingerSwipeTest::tapCanceled, this, &KTwoFingerSwipeTest::slotTapCanceled); mSpyTapFinished = new QSignalSpy(this, &KTwoFingerSwipeTest::tapFinished); QVERIFY(mSpyTapFinished->isValid()); mSpyTapStarted = new QSignalSpy(this, &KTwoFingerSwipeTest::tapStarted); QVERIFY(mSpyTapStarted->isValid()); mSpyTapUpdated = new QSignalSpy(this, &KTwoFingerSwipeTest::tapUpdated); QVERIFY(mSpyTapUpdated->isValid()); mSpyTapCanceled = new QSignalSpy(this, &KTwoFingerSwipeTest::tapCanceled); QVERIFY(mSpyTapCanceled->isValid()); QTest::qWait(1000); } void testChangeTapRadius() { QVERIFY(mTwoFingerRec->tapRadius() >= 0); mTwoFingerRec->setTapRadius(10); QCOMPARE(mTwoFingerRec->tapRadius(), 10); mTwoFingerRec->setTapRadius(-100); QCOMPARE(mTwoFingerRec->tapRadius(), 0); mTwoFingerRec->setTapRadius(40); QCOMPARE(mTwoFingerRec->tapRadius(), 40); } void testSuccessfulGesture() { // Test a successful gesture with two fingers, where the touch points wiggle only a little bit. clearSignalSpys(); int tapRadius = mTwoFingerRec->tapRadius(); QPoint wiggleRoom = QPoint (tapRadius / 2, tapRadius / 2); QTest::touchEvent(&mWidget, mDev) .press(0, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos + wiggleRoom, (QWidget *) nullptr) .press(1, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .move(1, mTouchPointPos + wiggleRoom, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .release(1, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .release(0, mTouchPointPos, (QWidget *) nullptr); if (mSpyTapStarted->count() == 0) { QVERIFY(mSpyTapStarted->wait(1000)); } if (mSpyTapFinished->count() == 0) { QVERIFY(mSpyTapFinished->wait(1000)); } QCOMPARE(mSpyTapStarted->count(), 1); QCOMPARE(mSpyTapFinished->count(), 1); QCOMPARE(mSpyTapCanceled->count(), 0); QVERIFY(mSpyTapUpdated->count() > 0); } void testFailingGesture() { // Test a failing gesture with two fingers, where the touch points wiggle too much at beginning. clearSignalSpys(); int tapRadius = mTwoFingerRec->tapRadius(); QPoint wiggleRoom = QPoint (tapRadius, tapRadius); QTest::touchEvent(&mWidget, mDev) .press(0, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos + wiggleRoom, (QWidget *) nullptr) .press(1, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .move(1, mTouchPointPos + wiggleRoom, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .release(1, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .release(0, mTouchPointPos, (QWidget *) nullptr); QCOMPARE(mSpyTapStarted->count(), 0); QCOMPARE(mSpyTapFinished->count(), 0); QCOMPARE(mSpyTapCanceled->count(), 0); QCOMPARE(mSpyTapUpdated->count(), 0); } void testFailingGesture2() { // Test a failing gesture with two fingers, where the touch points wiggle too much in the middle. clearSignalSpys(); int tapRadius = mTwoFingerRec->tapRadius(); QPoint wiggleRoom = QPoint (tapRadius, tapRadius); QTest::touchEvent(&mWidget, mDev) .press(0, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .press(1, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .move(1, mTouchPointPos + wiggleRoom, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .release(1, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .release(0, mTouchPointPos, (QWidget *) nullptr); if (mSpyTapStarted->count() == 0) { QVERIFY(mSpyTapStarted->wait(1000)); } QCOMPARE(mSpyTapStarted->count(), 1); QCOMPARE(mSpyTapFinished->count(), 0); QCOMPARE(mSpyTapCanceled->count(), 1); QVERIFY(mSpyTapUpdated->count() >= 0); } void testFailingGesture3() { // Test a failing gesture with two fingers, where the touch points wiggle too much in the middle, // and the second finger press and release successively. clearSignalSpys(); int tapRadius = mTwoFingerRec->tapRadius(); QPoint wiggleRoom = QPoint (tapRadius, tapRadius); QTest::touchEvent(&mWidget, mDev) .press(0, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .press(1, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .move(1, mTouchPointPos + wiggleRoom, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .release(1, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .press(1, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .release(1, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .release(0, mTouchPointPos, (QWidget *) nullptr); if (mSpyTapStarted->count() == 0) { QVERIFY(mSpyTapStarted->wait(1000)); } QCOMPARE(mSpyTapStarted->count(), 1); QCOMPARE(mSpyTapFinished->count(), 0); QCOMPARE(mSpyTapCanceled->count(), 1); QVERIFY(mSpyTapUpdated->count() >= 0); } void testFailingGesture_threeFingers() { // the test a gesture with three fingers should be end with gesture canceled. clearSignalSpys(); int tapRadius = mTwoFingerRec->tapRadius(); QPoint wiggleRoom = QPoint (tapRadius / 2, tapRadius / 2); QTest::touchEvent(&mWidget, mDev) .press(0, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .press(1, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .move(1, mTouchPointPos + wiggleRoom, (QWidget *) nullptr) .press(2, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .release(1, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .release(0, mTouchPointPos, (QWidget *) nullptr); if (mSpyTapStarted->count() == 0) { QVERIFY(mSpyTapStarted->wait(1000)); } QCOMPARE(mSpyTapStarted->count(), 1); QCOMPARE(mSpyTapFinished->count(), 0); QCOMPARE(mSpyTapCanceled->count(), 1); QVERIFY(mSpyTapUpdated->count() >= 0); } void testFailingGesture_threeFingers2() { clearSignalSpys(); QTest::touchEvent(&mWidget, mDev) .press(0, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .press(1, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .move(1, mTouchPointPos, (QWidget *) nullptr) .press(2, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .move(1, mTouchPointPos, (QWidget *) nullptr) .release(3, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .release(1, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .press(1, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr) .release(1, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .release(1, mTouchPointPos, (QWidget *) nullptr); if (mSpyTapStarted->count() == 0) { QVERIFY(mSpyTapStarted->wait(1000)); } QCOMPARE(mSpyTapStarted->count(), 1); QCOMPARE(mSpyTapFinished->count(), 0); QCOMPARE(mSpyTapCanceled->count(), 1); QVERIFY(mSpyTapUpdated->count() >= 0); } void testFailingGesture_oneFinger() { // Test a failing gesture where we use only one finger. clearSignalSpys(); int tapRadius = mTwoFingerRec->tapRadius(); QPoint wiggleRoom = QPoint (tapRadius / 2, tapRadius / 2); QTest::touchEvent(&mWidget, mDev) .press(0, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos + wiggleRoom, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .move(0, mTouchPointPos, (QWidget *) nullptr); QTest::touchEvent(&mWidget, mDev) .release(0, mTouchPointPos, (QWidget *) nullptr); QCOMPARE(mSpyTapStarted->count(), 0); QCOMPARE(mSpyTapFinished->count(), 0); QCOMPARE(mSpyTapCanceled->count(), 0); QCOMPARE(mSpyTapUpdated->count(), 0); } void testSomeRandomTaps() { for (int i = 0; i < 50; ++i) { int v1 = rand() % 450; int v2 = rand() % 450; mTouchPointPos = QPoint(v1, v2); testSuccessfulGesture(); } } }; QTEST_MAIN(KTwoFingerSwipeTest) #include "ktwofingertaptest.moc"