File indexing completed on 2024-04-28 15:31:55

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2021 Steffen Hartleib <steffenhartleib@t-online.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-or-later
0006 */
0007 
0008 #include <ktwofingertap.h>
0009 
0010 #include <QTest>
0011 #include <QSignalSpy>
0012 #include <QWidget>
0013 #include <QMainWindow>
0014 
0015 class KTwoFingerSwipeTest : public QObject
0016 {
0017     Q_OBJECT
0018 
0019     QTouchDevice *mDev = nullptr;
0020 
0021     QMainWindow mMainWindow;
0022     QWidget mWidget;
0023     KTwoFingerTapRecognizer *mTwoFingerRec = nullptr;
0024     Qt::GestureType mKTwoFingerTapGesture;
0025     QPoint mTouchPointPos = QPoint(100, 100);
0026     QSignalSpy *mSpyTapFinished = nullptr;
0027     QSignalSpy *mSpyTapStarted = nullptr;
0028     QSignalSpy *mSpyTapUpdated = nullptr;
0029     QSignalSpy *mSpyTapCanceled = nullptr;
0030 
0031 Q_SIGNALS:
0032     void tapStarted(KTwoFingerTap *);
0033     void tapFinished(KTwoFingerTap *);
0034     void tapUpdated(KTwoFingerTap *);
0035     void tapCanceled(KTwoFingerTap *);
0036 
0037 protected:
0038     bool eventFilter(QObject *watched, QEvent *e) override
0039     {
0040         if (e->type() == QEvent::Gesture) {
0041             QGestureEvent *gEvent = static_cast<QGestureEvent *>(e);
0042             KTwoFingerTap *tap = static_cast<KTwoFingerTap *>(gEvent->gesture(mKTwoFingerTapGesture));
0043             if (tap) {
0044                 const Qt::GestureState state = tap->state();
0045                 if (state == Qt::GestureFinished) {
0046                     Q_EMIT tapFinished(tap);
0047                 } else if (state == Qt::GestureStarted) {
0048                     Q_EMIT tapStarted(tap);
0049                 } else if (state == Qt::GestureUpdated) {
0050                     Q_EMIT tapUpdated(tap);
0051                 } else if (state == Qt::GestureCanceled) {
0052                     Q_EMIT tapCanceled(tap);
0053                 }
0054             }
0055             e->accept();
0056             return true;
0057         }
0058         return QObject::eventFilter(watched, e);
0059     }
0060 
0061 protected Q_SLOTS:
0062     void slotTapFinished (KTwoFingerTap *tap)
0063     {
0064         compareGesturePositions(tap);
0065     }
0066     void slotTapStarted (KTwoFingerTap *tap)
0067     {
0068         compareGesturePositions(tap);
0069     }
0070     void slotTapUpdated (KTwoFingerTap *tap)
0071     {
0072         compareGesturePositions(tap);
0073     }
0074     void slotTapCanceled (KTwoFingerTap *tap)
0075     {
0076         compareGesturePositions(tap);
0077     }
0078 private:
0079     void compareGesturePositions(KTwoFingerTap *tap)
0080     {
0081         QCOMPARE(tap->pos(), mTouchPointPos);
0082         QCOMPARE(tap->screenPos(), mWidget.mapToGlobal(mTouchPointPos));
0083         QCOMPARE(tap->hotSpot(), mWidget.mapToGlobal(mTouchPointPos));
0084         QCOMPARE(tap->scenePos(), mWidget.mapToGlobal(mTouchPointPos));
0085         QVERIFY(tap->hasHotSpot());
0086     }
0087 
0088     void clearSignalSpys()
0089     {
0090         mSpyTapFinished->clear();
0091         mSpyTapCanceled->clear();
0092         mSpyTapUpdated->clear();
0093         mSpyTapStarted->clear();
0094     }
0095 
0096 private Q_SLOTS:
0097     void initTestCase()
0098     {
0099         mDev = QTest::createTouchDevice();
0100 
0101         mMainWindow.setGeometry(0, 0, 500, 500);
0102         mMainWindow.setCentralWidget(&mWidget);
0103         mMainWindow.show();
0104 
0105         mWidget.installEventFilter(this);
0106         mWidget.setAttribute(Qt::WA_AcceptTouchEvents);
0107 
0108         QVERIFY(QTest::qWaitForWindowActive(&mMainWindow));
0109         QVERIFY(QTest::qWaitForWindowActive(&mWidget));
0110 
0111         mTwoFingerRec = new KTwoFingerTapRecognizer();
0112         QVERIFY(mTwoFingerRec);
0113 
0114         mKTwoFingerTapGesture = QGestureRecognizer::registerRecognizer(mTwoFingerRec);
0115         QVERIFY(mKTwoFingerTapGesture & Qt::CustomGesture);
0116 
0117         mWidget.grabGesture(mKTwoFingerTapGesture);
0118 
0119         connect(this, &KTwoFingerSwipeTest::tapFinished, this, &KTwoFingerSwipeTest::slotTapFinished);
0120         connect(this, &KTwoFingerSwipeTest::tapStarted, this, &KTwoFingerSwipeTest::slotTapStarted);
0121         connect(this, &KTwoFingerSwipeTest::tapUpdated, this, &KTwoFingerSwipeTest::slotTapUpdated);
0122         connect(this, &KTwoFingerSwipeTest::tapCanceled, this, &KTwoFingerSwipeTest::slotTapCanceled);
0123 
0124         mSpyTapFinished = new QSignalSpy(this, &KTwoFingerSwipeTest::tapFinished);
0125         QVERIFY(mSpyTapFinished->isValid());
0126 
0127         mSpyTapStarted = new QSignalSpy(this, &KTwoFingerSwipeTest::tapStarted);
0128         QVERIFY(mSpyTapStarted->isValid());
0129 
0130         mSpyTapUpdated = new QSignalSpy(this, &KTwoFingerSwipeTest::tapUpdated);
0131         QVERIFY(mSpyTapUpdated->isValid());
0132 
0133         mSpyTapCanceled = new QSignalSpy(this, &KTwoFingerSwipeTest::tapCanceled);
0134         QVERIFY(mSpyTapCanceled->isValid());
0135 
0136         QTest::qWait(1000);
0137     }
0138 
0139     void testChangeTapRadius()
0140     {
0141         QVERIFY(mTwoFingerRec->tapRadius() >= 0);
0142 
0143         mTwoFingerRec->setTapRadius(10);
0144         QCOMPARE(mTwoFingerRec->tapRadius(), 10);
0145 
0146         mTwoFingerRec->setTapRadius(-100);
0147         QCOMPARE(mTwoFingerRec->tapRadius(), 0);
0148 
0149         mTwoFingerRec->setTapRadius(40);
0150         QCOMPARE(mTwoFingerRec->tapRadius(), 40);
0151     }
0152 
0153     void testSuccessfulGesture()
0154     {
0155         // Test a successful gesture with two fingers, where the touch points wiggle only a little bit.
0156 
0157         clearSignalSpys();
0158 
0159         int tapRadius = mTwoFingerRec->tapRadius();
0160         QPoint wiggleRoom = QPoint (tapRadius / 2, tapRadius / 2);
0161 
0162         QTest::touchEvent(&mWidget, mDev)
0163             .press(0, mTouchPointPos, (QWidget *) nullptr);
0164 
0165         QTest::touchEvent(&mWidget, mDev)
0166             .move(0, mTouchPointPos + wiggleRoom, (QWidget *) nullptr)
0167             .press(1, mTouchPointPos, (QWidget *) nullptr);
0168 
0169         QTest::touchEvent(&mWidget, mDev)
0170             .move(0, mTouchPointPos, (QWidget *) nullptr)
0171             .move(1, mTouchPointPos + wiggleRoom, (QWidget *) nullptr);
0172 
0173         QTest::touchEvent(&mWidget, mDev)
0174             .move(0, mTouchPointPos, (QWidget *) nullptr)
0175             .release(1, mTouchPointPos, (QWidget *) nullptr);
0176 
0177         QTest::touchEvent(&mWidget, mDev)
0178             .release(0, mTouchPointPos, (QWidget *) nullptr);
0179 
0180         if (mSpyTapStarted->count() == 0) {
0181             QVERIFY(mSpyTapStarted->wait(1000));
0182         }
0183         if (mSpyTapFinished->count() == 0) {
0184             QVERIFY(mSpyTapFinished->wait(1000));
0185         }
0186 
0187         QCOMPARE(mSpyTapStarted->count(), 1);
0188         QCOMPARE(mSpyTapFinished->count(), 1);
0189         QCOMPARE(mSpyTapCanceled->count(), 0);
0190         QVERIFY(mSpyTapUpdated->count() > 0);
0191     }
0192 
0193     void testFailingGesture()
0194     {
0195         // Test a failing gesture with two fingers, where the touch points wiggle too much at beginning.
0196 
0197         clearSignalSpys();
0198 
0199         int tapRadius = mTwoFingerRec->tapRadius();
0200         QPoint wiggleRoom = QPoint (tapRadius, tapRadius);
0201 
0202         QTest::touchEvent(&mWidget, mDev)
0203             .press(0, mTouchPointPos, (QWidget *) nullptr);
0204 
0205         QTest::touchEvent(&mWidget, mDev)
0206             .move(0, mTouchPointPos + wiggleRoom, (QWidget *) nullptr)
0207             .press(1, mTouchPointPos, (QWidget *) nullptr);
0208 
0209         QTest::touchEvent(&mWidget, mDev)
0210             .move(0, mTouchPointPos, (QWidget *) nullptr)
0211             .move(1, mTouchPointPos + wiggleRoom, (QWidget *) nullptr);
0212 
0213         QTest::touchEvent(&mWidget, mDev)
0214             .move(0, mTouchPointPos, (QWidget *) nullptr)
0215             .release(1, mTouchPointPos, (QWidget *) nullptr);
0216 
0217         QTest::touchEvent(&mWidget, mDev)
0218             .release(0, mTouchPointPos, (QWidget *) nullptr);
0219 
0220         QCOMPARE(mSpyTapStarted->count(), 0);
0221         QCOMPARE(mSpyTapFinished->count(), 0);
0222         QCOMPARE(mSpyTapCanceled->count(), 0);
0223         QCOMPARE(mSpyTapUpdated->count(), 0);
0224     }
0225 
0226     void testFailingGesture2()
0227     {
0228         // Test a failing gesture with two fingers, where the touch points wiggle too much in the middle.
0229         clearSignalSpys();
0230         int tapRadius = mTwoFingerRec->tapRadius();
0231         QPoint wiggleRoom = QPoint (tapRadius, tapRadius);
0232 
0233         QTest::touchEvent(&mWidget, mDev)
0234             .press(0, mTouchPointPos, (QWidget *) nullptr);
0235 
0236         QTest::touchEvent(&mWidget, mDev)
0237             .move(0, mTouchPointPos, (QWidget *) nullptr)
0238             .press(1, mTouchPointPos, (QWidget *) nullptr);
0239 
0240         QTest::touchEvent(&mWidget, mDev)
0241             .move(0, mTouchPointPos, (QWidget *) nullptr)
0242             .move(1, mTouchPointPos + wiggleRoom, (QWidget *) nullptr);
0243 
0244         QTest::touchEvent(&mWidget, mDev)
0245             .move(0, mTouchPointPos, (QWidget *) nullptr)
0246             .release(1, mTouchPointPos, (QWidget *) nullptr);
0247 
0248         QTest::touchEvent(&mWidget, mDev)
0249             .release(0, mTouchPointPos, (QWidget *) nullptr);
0250 
0251         if (mSpyTapStarted->count() == 0) {
0252             QVERIFY(mSpyTapStarted->wait(1000));
0253         }
0254         QCOMPARE(mSpyTapStarted->count(), 1);
0255         QCOMPARE(mSpyTapFinished->count(), 0);
0256         QCOMPARE(mSpyTapCanceled->count(), 1);
0257         QVERIFY(mSpyTapUpdated->count() >= 0);
0258     }
0259 
0260     void testFailingGesture3()
0261     {
0262         // Test a failing gesture with two fingers, where the touch points wiggle too much in the middle,
0263         // and the second finger press and release successively.
0264 
0265         clearSignalSpys();
0266         int tapRadius = mTwoFingerRec->tapRadius();
0267         QPoint wiggleRoom = QPoint (tapRadius, tapRadius);
0268 
0269         QTest::touchEvent(&mWidget, mDev)
0270             .press(0, mTouchPointPos, (QWidget *) nullptr);
0271 
0272         QTest::touchEvent(&mWidget, mDev)
0273             .move(0, mTouchPointPos, (QWidget *) nullptr)
0274             .press(1, mTouchPointPos, (QWidget *) nullptr);
0275 
0276         QTest::touchEvent(&mWidget, mDev)
0277             .move(0, mTouchPointPos, (QWidget *) nullptr)
0278             .move(1, mTouchPointPos + wiggleRoom, (QWidget *) nullptr);
0279 
0280         QTest::touchEvent(&mWidget, mDev)
0281             .move(0, mTouchPointPos, (QWidget *) nullptr)
0282             .release(1, mTouchPointPos, (QWidget *) nullptr);
0283 
0284         QTest::touchEvent(&mWidget, mDev)
0285             .move(0, mTouchPointPos, (QWidget *) nullptr)
0286             .press(1, mTouchPointPos, (QWidget *) nullptr);
0287 
0288         QTest::touchEvent(&mWidget, mDev)
0289             .move(0, mTouchPointPos, (QWidget *) nullptr)
0290             .release(1, mTouchPointPos, (QWidget *) nullptr);
0291 
0292         QTest::touchEvent(&mWidget, mDev)
0293             .release(0, mTouchPointPos, (QWidget *) nullptr);
0294 
0295         if (mSpyTapStarted->count() == 0) {
0296             QVERIFY(mSpyTapStarted->wait(1000));
0297         }
0298         QCOMPARE(mSpyTapStarted->count(), 1);
0299         QCOMPARE(mSpyTapFinished->count(), 0);
0300         QCOMPARE(mSpyTapCanceled->count(), 1);
0301         QVERIFY(mSpyTapUpdated->count() >= 0);
0302     }
0303 
0304     void testFailingGesture_threeFingers()
0305     {
0306         // the test a gesture with three fingers should be end with gesture canceled.
0307         clearSignalSpys();
0308         int tapRadius = mTwoFingerRec->tapRadius();
0309         QPoint wiggleRoom = QPoint (tapRadius / 2, tapRadius / 2);
0310 
0311         QTest::touchEvent(&mWidget, mDev)
0312             .press(0, mTouchPointPos, (QWidget *) nullptr);
0313 
0314         QTest::touchEvent(&mWidget, mDev)
0315             .move(0, mTouchPointPos, (QWidget *) nullptr)
0316             .press(1, mTouchPointPos, (QWidget *) nullptr);
0317 
0318         QTest::touchEvent(&mWidget, mDev)
0319             .move(0, mTouchPointPos, (QWidget *) nullptr)
0320             .move(1, mTouchPointPos + wiggleRoom, (QWidget *) nullptr)
0321             .press(2, mTouchPointPos, (QWidget *) nullptr);
0322 
0323         QTest::touchEvent(&mWidget, mDev)
0324             .move(0, mTouchPointPos, (QWidget *) nullptr)
0325             .release(1, mTouchPointPos, (QWidget *) nullptr);
0326 
0327         QTest::touchEvent(&mWidget, mDev)
0328             .release(0, mTouchPointPos, (QWidget *) nullptr);
0329 
0330         if (mSpyTapStarted->count() == 0) {
0331             QVERIFY(mSpyTapStarted->wait(1000));
0332         }
0333         QCOMPARE(mSpyTapStarted->count(), 1);
0334         QCOMPARE(mSpyTapFinished->count(), 0);
0335         QCOMPARE(mSpyTapCanceled->count(), 1);
0336         QVERIFY(mSpyTapUpdated->count() >= 0);
0337     }
0338 
0339     void testFailingGesture_threeFingers2()
0340     {
0341 
0342         clearSignalSpys();
0343 
0344         QTest::touchEvent(&mWidget, mDev)
0345             .press(0, mTouchPointPos, (QWidget *) nullptr);
0346 
0347         QTest::touchEvent(&mWidget, mDev)
0348             .move(0, mTouchPointPos, (QWidget *) nullptr)
0349             .press(1, mTouchPointPos, (QWidget *) nullptr);
0350 
0351         QTest::touchEvent(&mWidget, mDev)
0352             .move(0, mTouchPointPos, (QWidget *) nullptr)
0353             .move(1, mTouchPointPos, (QWidget *) nullptr)
0354             .press(2, mTouchPointPos, (QWidget *) nullptr);
0355 
0356         QTest::touchEvent(&mWidget, mDev)
0357             .move(0, mTouchPointPos, (QWidget *) nullptr)
0358             .move(1, mTouchPointPos, (QWidget *) nullptr)
0359             .release(3, mTouchPointPos, (QWidget *) nullptr);
0360 
0361         QTest::touchEvent(&mWidget, mDev)
0362             .move(0, mTouchPointPos, (QWidget *) nullptr)
0363             .release(1, mTouchPointPos, (QWidget *) nullptr);
0364 
0365         QTest::touchEvent(&mWidget, mDev)
0366             .move(0, mTouchPointPos, (QWidget *) nullptr)
0367             .press(1, mTouchPointPos, (QWidget *) nullptr);
0368 
0369         QTest::touchEvent(&mWidget, mDev)
0370             .move(0, mTouchPointPos, (QWidget *) nullptr)
0371             .release(1, mTouchPointPos, (QWidget *) nullptr);
0372 
0373         QTest::touchEvent(&mWidget, mDev)
0374             .release(1, mTouchPointPos, (QWidget *) nullptr);
0375 
0376         if (mSpyTapStarted->count() == 0) {
0377             QVERIFY(mSpyTapStarted->wait(1000));
0378         }
0379         QCOMPARE(mSpyTapStarted->count(), 1);
0380         QCOMPARE(mSpyTapFinished->count(), 0);
0381         QCOMPARE(mSpyTapCanceled->count(), 1);
0382         QVERIFY(mSpyTapUpdated->count() >= 0);
0383     }
0384 
0385     void testFailingGesture_oneFinger()
0386     {
0387         // Test a failing gesture where we use only one finger.
0388         clearSignalSpys();
0389         int tapRadius = mTwoFingerRec->tapRadius();
0390         QPoint wiggleRoom = QPoint (tapRadius / 2, tapRadius / 2);
0391 
0392         QTest::touchEvent(&mWidget, mDev)
0393             .press(0, mTouchPointPos, (QWidget *) nullptr);
0394 
0395         QTest::touchEvent(&mWidget, mDev)
0396             .move(0, mTouchPointPos + wiggleRoom, (QWidget *) nullptr);
0397 
0398         QTest::touchEvent(&mWidget, mDev)
0399             .move(0, mTouchPointPos, (QWidget *) nullptr);
0400 
0401         QTest::touchEvent(&mWidget, mDev)
0402             .release(0, mTouchPointPos, (QWidget *) nullptr);
0403 
0404         QCOMPARE(mSpyTapStarted->count(), 0);
0405         QCOMPARE(mSpyTapFinished->count(), 0);
0406         QCOMPARE(mSpyTapCanceled->count(), 0);
0407         QCOMPARE(mSpyTapUpdated->count(), 0);
0408     }
0409     void testSomeRandomTaps()
0410     {
0411         for (int i = 0; i < 50; ++i) {
0412             int v1 = rand() % 450;
0413             int v2 = rand() % 450;
0414             mTouchPointPos = QPoint(v1, v2);
0415             testSuccessfulGesture();
0416         }
0417     }
0418 };
0419 
0420 QTEST_MAIN(KTwoFingerSwipeTest)
0421 
0422 #include "ktwofingertaptest.moc"