File indexing completed on 2024-04-28 03:58:58

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     QPointingDevice *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 cleanupTestCase()
0098     {
0099         delete mSpyTapFinished;
0100         delete mSpyTapCanceled;
0101         delete mSpyTapUpdated;
0102         delete mSpyTapStarted;
0103     }
0104 
0105     void initTestCase()
0106     {
0107         mDev = QTest::createTouchDevice();
0108 
0109         mMainWindow.setGeometry(0, 0, 500, 500);
0110         mMainWindow.setCentralWidget(&mWidget);
0111         mMainWindow.show();
0112 
0113         mWidget.installEventFilter(this);
0114         mWidget.setAttribute(Qt::WA_AcceptTouchEvents);
0115 
0116         QVERIFY(QTest::qWaitForWindowActive(&mMainWindow));
0117         QVERIFY(QTest::qWaitForWindowActive(&mWidget));
0118 
0119         mTwoFingerRec = new KTwoFingerTapRecognizer();
0120         QVERIFY(mTwoFingerRec);
0121 
0122         mKTwoFingerTapGesture = QGestureRecognizer::registerRecognizer(mTwoFingerRec);
0123         QVERIFY(mKTwoFingerTapGesture & Qt::CustomGesture);
0124 
0125         mWidget.grabGesture(mKTwoFingerTapGesture);
0126 
0127         connect(this, &KTwoFingerSwipeTest::tapFinished, this, &KTwoFingerSwipeTest::slotTapFinished);
0128         connect(this, &KTwoFingerSwipeTest::tapStarted, this, &KTwoFingerSwipeTest::slotTapStarted);
0129         connect(this, &KTwoFingerSwipeTest::tapUpdated, this, &KTwoFingerSwipeTest::slotTapUpdated);
0130         connect(this, &KTwoFingerSwipeTest::tapCanceled, this, &KTwoFingerSwipeTest::slotTapCanceled);
0131 
0132         mSpyTapFinished = new QSignalSpy(this, &KTwoFingerSwipeTest::tapFinished);
0133         QVERIFY(mSpyTapFinished->isValid());
0134 
0135         mSpyTapStarted = new QSignalSpy(this, &KTwoFingerSwipeTest::tapStarted);
0136         QVERIFY(mSpyTapStarted->isValid());
0137 
0138         mSpyTapUpdated = new QSignalSpy(this, &KTwoFingerSwipeTest::tapUpdated);
0139         QVERIFY(mSpyTapUpdated->isValid());
0140 
0141         mSpyTapCanceled = new QSignalSpy(this, &KTwoFingerSwipeTest::tapCanceled);
0142         QVERIFY(mSpyTapCanceled->isValid());
0143 
0144         QTest::qWait(1000);
0145     }
0146 
0147     void testChangeTapRadius()
0148     {
0149         QVERIFY(mTwoFingerRec->tapRadius() >= 0);
0150 
0151         mTwoFingerRec->setTapRadius(10);
0152         QCOMPARE(mTwoFingerRec->tapRadius(), 10);
0153 
0154         mTwoFingerRec->setTapRadius(-100);
0155         QCOMPARE(mTwoFingerRec->tapRadius(), 0);
0156 
0157         mTwoFingerRec->setTapRadius(40);
0158         QCOMPARE(mTwoFingerRec->tapRadius(), 40);
0159     }
0160 
0161     void testSuccessfulGesture()
0162     {
0163         // Test a successful gesture with two fingers, where the touch points wiggle only a little bit.
0164 
0165         clearSignalSpys();
0166 
0167         int tapRadius = mTwoFingerRec->tapRadius();
0168         QPoint wiggleRoom = QPoint (tapRadius / 2, tapRadius / 2);
0169 
0170         QTest::touchEvent(&mWidget, mDev)
0171             .press(0, mTouchPointPos, (QWidget *) nullptr);
0172 
0173         QTest::touchEvent(&mWidget, mDev)
0174             .move(0, mTouchPointPos + wiggleRoom, (QWidget *) nullptr)
0175             .press(1, mTouchPointPos, (QWidget *) nullptr);
0176 
0177         QTest::touchEvent(&mWidget, mDev)
0178             .move(0, mTouchPointPos, (QWidget *) nullptr)
0179             .move(1, mTouchPointPos + wiggleRoom, (QWidget *) nullptr);
0180 
0181         QTest::touchEvent(&mWidget, mDev)
0182             .move(0, mTouchPointPos, (QWidget *) nullptr)
0183             .release(1, mTouchPointPos, (QWidget *) nullptr);
0184 
0185         QTest::touchEvent(&mWidget, mDev)
0186             .release(0, mTouchPointPos, (QWidget *) nullptr);
0187 
0188         if (mSpyTapStarted->count() == 0) {
0189             QVERIFY(mSpyTapStarted->wait(1000));
0190         }
0191         if (mSpyTapFinished->count() == 0) {
0192             QVERIFY(mSpyTapFinished->wait(1000));
0193         }
0194 
0195         QCOMPARE(mSpyTapStarted->count(), 1);
0196         QCOMPARE(mSpyTapFinished->count(), 1);
0197         QCOMPARE(mSpyTapCanceled->count(), 0);
0198         QVERIFY(mSpyTapUpdated->count() > 0);
0199     }
0200 
0201     void testFailingGesture()
0202     {
0203         // Test a failing gesture with two fingers, where the touch points wiggle too much at beginning.
0204 
0205         clearSignalSpys();
0206 
0207         int tapRadius = mTwoFingerRec->tapRadius();
0208         QPoint wiggleRoom = QPoint (tapRadius, tapRadius);
0209 
0210         QTest::touchEvent(&mWidget, mDev)
0211             .press(0, mTouchPointPos, (QWidget *) nullptr);
0212 
0213         QTest::touchEvent(&mWidget, mDev)
0214             .move(0, mTouchPointPos + wiggleRoom, (QWidget *) nullptr)
0215             .press(1, mTouchPointPos, (QWidget *) nullptr);
0216 
0217         QTest::touchEvent(&mWidget, mDev)
0218             .move(0, mTouchPointPos, (QWidget *) nullptr)
0219             .move(1, mTouchPointPos + wiggleRoom, (QWidget *) nullptr);
0220 
0221         QTest::touchEvent(&mWidget, mDev)
0222             .move(0, mTouchPointPos, (QWidget *) nullptr)
0223             .release(1, mTouchPointPos, (QWidget *) nullptr);
0224 
0225         QTest::touchEvent(&mWidget, mDev)
0226             .release(0, mTouchPointPos, (QWidget *) nullptr);
0227 
0228         QCOMPARE(mSpyTapStarted->count(), 0);
0229         QCOMPARE(mSpyTapFinished->count(), 0);
0230         QCOMPARE(mSpyTapCanceled->count(), 0);
0231         QCOMPARE(mSpyTapUpdated->count(), 0);
0232     }
0233 
0234     void testFailingGesture2()
0235     {
0236         // Test a failing gesture with two fingers, where the touch points wiggle too much in the middle.
0237         clearSignalSpys();
0238         int tapRadius = mTwoFingerRec->tapRadius();
0239         QPoint wiggleRoom = QPoint (tapRadius, tapRadius);
0240 
0241         QTest::touchEvent(&mWidget, mDev)
0242             .press(0, mTouchPointPos, (QWidget *) nullptr);
0243 
0244         QTest::touchEvent(&mWidget, mDev)
0245             .move(0, mTouchPointPos, (QWidget *) nullptr)
0246             .press(1, mTouchPointPos, (QWidget *) nullptr);
0247 
0248         QTest::touchEvent(&mWidget, mDev)
0249             .move(0, mTouchPointPos, (QWidget *) nullptr)
0250             .move(1, mTouchPointPos + wiggleRoom, (QWidget *) nullptr);
0251 
0252         QTest::touchEvent(&mWidget, mDev)
0253             .move(0, mTouchPointPos, (QWidget *) nullptr)
0254             .release(1, mTouchPointPos, (QWidget *) nullptr);
0255 
0256         QTest::touchEvent(&mWidget, mDev)
0257             .release(0, mTouchPointPos, (QWidget *) nullptr);
0258 
0259         if (mSpyTapStarted->count() == 0) {
0260             QVERIFY(mSpyTapStarted->wait(1000));
0261         }
0262         QCOMPARE(mSpyTapStarted->count(), 1);
0263         QCOMPARE(mSpyTapFinished->count(), 0);
0264         QCOMPARE(mSpyTapCanceled->count(), 1);
0265         QVERIFY(mSpyTapUpdated->count() >= 0);
0266     }
0267 
0268     void testFailingGesture3()
0269     {
0270         // Test a failing gesture with two fingers, where the touch points wiggle too much in the middle,
0271         // and the second finger press and release successively.
0272 
0273         clearSignalSpys();
0274         int tapRadius = mTwoFingerRec->tapRadius();
0275         QPoint wiggleRoom = QPoint (tapRadius, tapRadius);
0276 
0277         QTest::touchEvent(&mWidget, mDev)
0278             .press(0, mTouchPointPos, (QWidget *) nullptr);
0279 
0280         QTest::touchEvent(&mWidget, mDev)
0281             .move(0, mTouchPointPos, (QWidget *) nullptr)
0282             .press(1, mTouchPointPos, (QWidget *) nullptr);
0283 
0284         QTest::touchEvent(&mWidget, mDev)
0285             .move(0, mTouchPointPos, (QWidget *) nullptr)
0286             .move(1, mTouchPointPos + wiggleRoom, (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             .move(0, mTouchPointPos, (QWidget *) nullptr)
0294             .press(1, mTouchPointPos, (QWidget *) nullptr);
0295 
0296         QTest::touchEvent(&mWidget, mDev)
0297             .move(0, mTouchPointPos, (QWidget *) nullptr)
0298             .release(1, mTouchPointPos, (QWidget *) nullptr);
0299 
0300         QTest::touchEvent(&mWidget, mDev)
0301             .release(0, mTouchPointPos, (QWidget *) nullptr);
0302 
0303         if (mSpyTapStarted->count() == 0) {
0304             QVERIFY(mSpyTapStarted->wait(1000));
0305         }
0306         QCOMPARE(mSpyTapStarted->count(), 1);
0307         QCOMPARE(mSpyTapFinished->count(), 0);
0308         QCOMPARE(mSpyTapCanceled->count(), 1);
0309         QVERIFY(mSpyTapUpdated->count() >= 0);
0310     }
0311 
0312     void testFailingGesture_threeFingers()
0313     {
0314         // the test a gesture with three fingers should be end with gesture canceled.
0315         clearSignalSpys();
0316         int tapRadius = mTwoFingerRec->tapRadius();
0317         QPoint wiggleRoom = QPoint (tapRadius / 2, tapRadius / 2);
0318 
0319         QTest::touchEvent(&mWidget, mDev)
0320             .press(0, mTouchPointPos, (QWidget *) nullptr);
0321 
0322         QTest::touchEvent(&mWidget, mDev)
0323             .move(0, mTouchPointPos, (QWidget *) nullptr)
0324             .press(1, mTouchPointPos, (QWidget *) nullptr);
0325 
0326         QTest::touchEvent(&mWidget, mDev)
0327             .move(0, mTouchPointPos, (QWidget *) nullptr)
0328             .move(1, mTouchPointPos + wiggleRoom, (QWidget *) nullptr)
0329             .press(2, mTouchPointPos, (QWidget *) nullptr);
0330 
0331         QTest::touchEvent(&mWidget, mDev)
0332             .move(0, mTouchPointPos, (QWidget *) nullptr)
0333             .release(1, mTouchPointPos, (QWidget *) nullptr);
0334 
0335         QTest::touchEvent(&mWidget, mDev)
0336             .release(0, mTouchPointPos, (QWidget *) nullptr);
0337 
0338         if (mSpyTapStarted->count() == 0) {
0339             QVERIFY(mSpyTapStarted->wait(1000));
0340         }
0341         QCOMPARE(mSpyTapStarted->count(), 1);
0342         QCOMPARE(mSpyTapFinished->count(), 0);
0343         QCOMPARE(mSpyTapCanceled->count(), 1);
0344         QVERIFY(mSpyTapUpdated->count() >= 0);
0345     }
0346 
0347     void testFailingGesture_threeFingers2()
0348     {
0349 
0350         clearSignalSpys();
0351 
0352         QTest::touchEvent(&mWidget, mDev)
0353             .press(0, mTouchPointPos, (QWidget *) nullptr);
0354 
0355         QTest::touchEvent(&mWidget, mDev)
0356             .move(0, mTouchPointPos, (QWidget *) nullptr)
0357             .press(1, mTouchPointPos, (QWidget *) nullptr);
0358 
0359         QTest::touchEvent(&mWidget, mDev)
0360             .move(0, mTouchPointPos, (QWidget *) nullptr)
0361             .move(1, mTouchPointPos, (QWidget *) nullptr)
0362             .press(2, mTouchPointPos, (QWidget *) nullptr);
0363 
0364         QTest::touchEvent(&mWidget, mDev)
0365             .move(0, mTouchPointPos, (QWidget *) nullptr)
0366             .move(1, mTouchPointPos, (QWidget *) nullptr)
0367             .release(3, 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             .move(0, mTouchPointPos, (QWidget *) nullptr)
0375             .press(1, mTouchPointPos, (QWidget *) nullptr);
0376 
0377         QTest::touchEvent(&mWidget, mDev)
0378             .move(0, mTouchPointPos, (QWidget *) nullptr)
0379             .release(1, mTouchPointPos, (QWidget *) nullptr);
0380 
0381         QTest::touchEvent(&mWidget, mDev)
0382             .release(1, mTouchPointPos, (QWidget *) nullptr);
0383 
0384         if (mSpyTapStarted->count() == 0) {
0385             QVERIFY(mSpyTapStarted->wait(1000));
0386         }
0387         QCOMPARE(mSpyTapStarted->count(), 1);
0388         QCOMPARE(mSpyTapFinished->count(), 0);
0389         QCOMPARE(mSpyTapCanceled->count(), 1);
0390         QVERIFY(mSpyTapUpdated->count() >= 0);
0391     }
0392 
0393     void testFailingGesture_oneFinger()
0394     {
0395         // Test a failing gesture where we use only one finger.
0396         clearSignalSpys();
0397         int tapRadius = mTwoFingerRec->tapRadius();
0398         QPoint wiggleRoom = QPoint (tapRadius / 2, tapRadius / 2);
0399 
0400         QTest::touchEvent(&mWidget, mDev)
0401             .press(0, mTouchPointPos, (QWidget *) nullptr);
0402 
0403         QTest::touchEvent(&mWidget, mDev)
0404             .move(0, mTouchPointPos + wiggleRoom, (QWidget *) nullptr);
0405 
0406         QTest::touchEvent(&mWidget, mDev)
0407             .move(0, mTouchPointPos, (QWidget *) nullptr);
0408 
0409         QTest::touchEvent(&mWidget, mDev)
0410             .release(0, mTouchPointPos, (QWidget *) nullptr);
0411 
0412         QCOMPARE(mSpyTapStarted->count(), 0);
0413         QCOMPARE(mSpyTapFinished->count(), 0);
0414         QCOMPARE(mSpyTapCanceled->count(), 0);
0415         QCOMPARE(mSpyTapUpdated->count(), 0);
0416     }
0417     void testSomeRandomTaps()
0418     {
0419         for (int i = 0; i < 50; ++i) {
0420             int v1 = rand() % 450;
0421             int v2 = rand() % 450;
0422             mTouchPointPos = QPoint(v1, v2);
0423             testSuccessfulGesture();
0424         }
0425     }
0426 };
0427 
0428 QTEST_MAIN(KTwoFingerSwipeTest)
0429 
0430 #include "ktwofingertaptest.moc"