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"