1/****************************************************************************
2**
3** Copyright (C) 2020 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the $MODULE$ of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtGui/QScreen>
30#include <QtWidgets/QGraphicsItem>
31#include <QtWidgets/QGraphicsScene>
32#include <QtWidgets/QGraphicsView>
33#include <QtWidgets/QGraphicsWidget>
34#include <QtWidgets/QWidget>
35#include <QtTest>
36#include <qpa/qwindowsysteminterface.h>
37#include <qpa/qwindowsysteminterface_p.h>
38#include <private/qhighdpiscaling_p.h>
39#include <private/qtouchdevice_p.h>
40
41class tst_QTouchEventWidget : public QWidget
42{
43public:
44 QList<QTouchEvent::TouchPoint> touchBeginPoints, touchUpdatePoints, touchEndPoints;
45 bool seenTouchBegin, seenTouchUpdate, seenTouchEnd;
46 bool acceptTouchBegin, acceptTouchUpdate, acceptTouchEnd;
47 bool deleteInTouchBegin, deleteInTouchUpdate, deleteInTouchEnd;
48 ulong timestamp;
49 QTouchDevice *deviceFromEvent;
50
51 explicit tst_QTouchEventWidget(QWidget *parent = nullptr) : QWidget(parent)
52 {
53 reset();
54 }
55
56 void reset()
57 {
58 touchBeginPoints.clear();
59 touchUpdatePoints.clear();
60 touchEndPoints.clear();
61 seenTouchBegin = seenTouchUpdate = seenTouchEnd = false;
62 acceptTouchBegin = acceptTouchUpdate = acceptTouchEnd = true;
63 deleteInTouchBegin = deleteInTouchUpdate = deleteInTouchEnd = false;
64 }
65
66 bool event(QEvent *event) override
67 {
68 switch (event->type()) {
69 case QEvent::TouchBegin:
70 if (seenTouchBegin) qWarning(msg: "TouchBegin: already seen a TouchBegin");
71 if (seenTouchUpdate) qWarning(msg: "TouchBegin: TouchUpdate cannot happen before TouchBegin");
72 if (seenTouchEnd) qWarning(msg: "TouchBegin: TouchEnd cannot happen before TouchBegin");
73 seenTouchBegin = !seenTouchBegin && !seenTouchUpdate && !seenTouchEnd;
74 touchBeginPoints = static_cast<QTouchEvent *>(event)->touchPoints();
75 timestamp = static_cast<QTouchEvent *>(event)->timestamp();
76 deviceFromEvent = static_cast<QTouchEvent *>(event)->device();
77 event->setAccepted(acceptTouchBegin);
78 if (deleteInTouchBegin)
79 delete this;
80 break;
81 case QEvent::TouchUpdate:
82 if (!seenTouchBegin) qWarning(msg: "TouchUpdate: have not seen TouchBegin");
83 if (seenTouchEnd) qWarning(msg: "TouchUpdate: TouchEnd cannot happen before TouchUpdate");
84 seenTouchUpdate = seenTouchBegin && !seenTouchEnd;
85 touchUpdatePoints = static_cast<QTouchEvent *>(event)->touchPoints();
86 timestamp = static_cast<QTouchEvent *>(event)->timestamp();
87 deviceFromEvent = static_cast<QTouchEvent *>(event)->device();
88 event->setAccepted(acceptTouchUpdate);
89 if (deleteInTouchUpdate)
90 delete this;
91 break;
92 case QEvent::TouchEnd:
93 if (!seenTouchBegin) qWarning(msg: "TouchEnd: have not seen TouchBegin");
94 if (seenTouchEnd) qWarning(msg: "TouchEnd: already seen a TouchEnd");
95 seenTouchEnd = seenTouchBegin && !seenTouchEnd;
96 touchEndPoints = static_cast<QTouchEvent *>(event)->touchPoints();
97 timestamp = static_cast<QTouchEvent *>(event)->timestamp();
98 deviceFromEvent = static_cast<QTouchEvent *>(event)->device();
99 event->setAccepted(acceptTouchEnd);
100 if (deleteInTouchEnd)
101 delete this;
102 break;
103 default:
104 return QWidget::event(event);
105 }
106 return true;
107 }
108};
109
110class tst_QTouchEventGraphicsItem : public QGraphicsItem
111{
112public:
113 QList<QTouchEvent::TouchPoint> touchBeginPoints, touchUpdatePoints, touchEndPoints;
114 bool seenTouchBegin, seenTouchUpdate, seenTouchEnd;
115 int touchBeginCounter, touchUpdateCounter, touchEndCounter;
116 bool acceptTouchBegin, acceptTouchUpdate, acceptTouchEnd;
117 bool deleteInTouchBegin, deleteInTouchUpdate, deleteInTouchEnd;
118 tst_QTouchEventGraphicsItem **weakpointer;
119
120 explicit tst_QTouchEventGraphicsItem(QGraphicsItem *parent = nullptr)
121 : QGraphicsItem(parent), weakpointer(0)
122 {
123 reset();
124 }
125
126 ~tst_QTouchEventGraphicsItem()
127 {
128 if (weakpointer)
129 *weakpointer = 0;
130 }
131
132 void reset()
133 {
134 touchBeginPoints.clear();
135 touchUpdatePoints.clear();
136 touchEndPoints.clear();
137 seenTouchBegin = seenTouchUpdate = seenTouchEnd = false;
138 touchBeginCounter = touchUpdateCounter = touchEndCounter = 0;
139 acceptTouchBegin = acceptTouchUpdate = acceptTouchEnd = true;
140 deleteInTouchBegin = deleteInTouchUpdate = deleteInTouchEnd = false;
141 }
142
143 QRectF boundingRect() const override { return QRectF(0, 0, 10, 10); }
144 void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override
145 {
146 painter->fillRect(r: QRectF(QPointF(0, 0), boundingRect().size()), c: Qt::yellow);
147 }
148
149 bool sceneEvent(QEvent *event) override
150 {
151 switch (event->type()) {
152 case QEvent::TouchBegin:
153 if (seenTouchBegin) qWarning(msg: "TouchBegin: already seen a TouchBegin");
154 if (seenTouchUpdate) qWarning(msg: "TouchBegin: TouchUpdate cannot happen before TouchBegin");
155 if (seenTouchEnd) qWarning(msg: "TouchBegin: TouchEnd cannot happen before TouchBegin");
156 seenTouchBegin = !seenTouchBegin && !seenTouchUpdate && !seenTouchEnd;
157 ++touchBeginCounter;
158 touchBeginPoints = static_cast<QTouchEvent *>(event)->touchPoints();
159 event->setAccepted(acceptTouchBegin);
160 if (deleteInTouchBegin)
161 delete this;
162 break;
163 case QEvent::TouchUpdate:
164 if (!seenTouchBegin) qWarning(msg: "TouchUpdate: have not seen TouchBegin");
165 if (seenTouchEnd) qWarning(msg: "TouchUpdate: TouchEnd cannot happen before TouchUpdate");
166 seenTouchUpdate = seenTouchBegin && !seenTouchEnd;
167 ++touchUpdateCounter;
168 touchUpdatePoints = static_cast<QTouchEvent *>(event)->touchPoints();
169 event->setAccepted(acceptTouchUpdate);
170 if (deleteInTouchUpdate)
171 delete this;
172 break;
173 case QEvent::TouchEnd:
174 if (!seenTouchBegin) qWarning(msg: "TouchEnd: have not seen TouchBegin");
175 if (seenTouchEnd) qWarning(msg: "TouchEnd: already seen a TouchEnd");
176 seenTouchEnd = seenTouchBegin && !seenTouchEnd;
177 ++touchEndCounter;
178 touchEndPoints = static_cast<QTouchEvent *>(event)->touchPoints();
179 event->setAccepted(acceptTouchEnd);
180 if (deleteInTouchEnd)
181 delete this;
182 break;
183 default:
184 return QGraphicsItem::sceneEvent(event);
185 }
186 return true;
187 }
188};
189
190class tst_QTouchEvent : public QObject
191{
192 Q_OBJECT
193public:
194 tst_QTouchEvent();
195
196private slots:
197 void cleanup();
198 void qPointerUniqueId();
199 void touchDisabledByDefault();
200 void touchEventAcceptedByDefault();
201 void touchBeginPropagatesWhenIgnored();
202 void touchUpdateAndEndNeverPropagate();
203 void basicRawEventTranslation();
204 void basicRawEventTranslationOfIds();
205 void multiPointRawEventTranslationOnTouchScreen();
206 void multiPointRawEventTranslationOnTouchPad();
207 void touchOnMultipleTouchscreens();
208 void deleteInEventHandler();
209 void deleteInRawEventTranslation();
210 void crashInQGraphicsSceneAfterNotHandlingTouchBegin();
211 void touchBeginWithGraphicsWidget();
212 void testQGuiAppDelivery();
213 void testMultiDevice();
214
215private:
216 QTouchDevice *touchScreenDevice;
217 QTouchDevice *secondaryTouchScreenDevice;
218 QTouchDevice *touchPadDevice;
219};
220
221tst_QTouchEvent::tst_QTouchEvent()
222 : touchScreenDevice(QTest::createTouchDevice())
223 , secondaryTouchScreenDevice(QTest::createTouchDevice())
224 , touchPadDevice(QTest::createTouchDevice(devType: QTouchDevice::TouchPad))
225{
226}
227
228void tst_QTouchEvent::cleanup()
229{
230 QVERIFY(QGuiApplication::topLevelWindows().isEmpty());
231 QWindowSystemInterfacePrivate::clearPointIdMap();
232}
233
234void tst_QTouchEvent::qPointerUniqueId()
235{
236 QPointingDeviceUniqueId id1, id2;
237
238 QCOMPARE(id1.numericId(), Q_INT64_C(-1));
239 QVERIFY(!id1.isValid());
240
241 QVERIFY( id1 == id2);
242 QVERIFY(!(id1 != id2));
243
244 QSet<QPointingDeviceUniqueId> set; // compile test
245 set.insert(value: id1);
246 set.insert(value: id2);
247 QCOMPARE(set.size(), 1);
248
249
250 const auto id3 = QPointingDeviceUniqueId::fromNumericId(id: -1);
251 QCOMPARE(id3.numericId(), Q_INT64_C(-1));
252 QVERIFY(!id3.isValid());
253
254 QVERIFY( id1 == id3);
255 QVERIFY(!(id1 != id3));
256
257 set.insert(value: id3);
258 QCOMPARE(set.size(), 1);
259
260
261 const auto id4 = QPointingDeviceUniqueId::fromNumericId(id: 4);
262 QCOMPARE(id4.numericId(), Q_INT64_C(4));
263 QVERIFY(id4.isValid());
264
265 QVERIFY( id1 != id4);
266 QVERIFY(!(id1 == id4));
267
268 set.insert(value: id4);
269 QCOMPARE(set.size(), 2);
270}
271
272void tst_QTouchEvent::touchDisabledByDefault()
273{
274 // QWidget
275 {
276 // the widget attribute is not enabled by default
277 QWidget widget;
278 QVERIFY(!widget.testAttribute(Qt::WA_AcceptTouchEvents));
279
280 // events should not be accepted since they are not enabled
281 QList<QTouchEvent::TouchPoint> touchPoints;
282 touchPoints.append(t: QTouchEvent::TouchPoint(0));
283 QTouchEvent touchEvent(QEvent::TouchBegin,
284 touchScreenDevice,
285 Qt::NoModifier,
286 Qt::TouchPointPressed,
287 touchPoints);
288 QVERIFY(!QApplication::sendEvent(&widget, &touchEvent));
289 QVERIFY(!touchEvent.isAccepted());
290 }
291
292 // QGraphicsView
293 {
294 QGraphicsScene scene;
295 tst_QTouchEventGraphicsItem item;
296 QGraphicsView view(&scene);
297 scene.addItem(item: &item);
298 item.setPos(ax: 100, ay: 100);
299 view.resize(w: 200, h: 200);
300 view.fitInView(rect: scene.sceneRect());
301
302 // touch events are not accepted by default
303 QVERIFY(!item.acceptTouchEvents());
304
305 // compose an event to the scene that is over the item
306 QTouchEvent::TouchPoint touchPoint(0);
307 touchPoint.setState(Qt::TouchPointPressed);
308 touchPoint.setPos(view.mapFromScene(point: item.mapToScene(point: item.boundingRect().center())));
309 touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint()));
310 touchPoint.setScenePos(view.mapToScene(point: touchPoint.pos().toPoint()));
311 QTouchEvent touchEvent(QEvent::TouchBegin,
312 touchScreenDevice,
313 Qt::NoModifier,
314 Qt::TouchPointPressed,
315 (QList<QTouchEvent::TouchPoint>() << touchPoint));
316 QVERIFY(!QApplication::sendEvent(view.viewport(), &touchEvent));
317 QVERIFY(!touchEvent.isAccepted());
318 QVERIFY(!item.seenTouchBegin);
319 }
320}
321
322void tst_QTouchEvent::touchEventAcceptedByDefault()
323{
324 // QWidget
325 {
326 // enabling touch events should automatically accept touch events
327 QWidget widget;
328 widget.setAttribute(Qt::WA_AcceptTouchEvents);
329
330 // QWidget handles touch event by converting them into a mouse event, so the event is both
331 // accepted and handled (res == true)
332 QList<QTouchEvent::TouchPoint> touchPoints;
333 touchPoints.append(t: QTouchEvent::TouchPoint(0));
334 QTouchEvent touchEvent(QEvent::TouchBegin,
335 touchScreenDevice,
336 Qt::NoModifier,
337 Qt::TouchPointPressed,
338 touchPoints);
339 QVERIFY(QApplication::sendEvent(&widget, &touchEvent));
340 QVERIFY(!touchEvent.isAccepted()); // Qt 5.X ignores touch events.
341
342 // tst_QTouchEventWidget does handle, sending succeeds
343 tst_QTouchEventWidget touchWidget;
344 touchWidget.setAttribute(Qt::WA_AcceptTouchEvents);
345 touchEvent.ignore();
346 QVERIFY(QApplication::sendEvent(&touchWidget, &touchEvent));
347 QVERIFY(touchEvent.isAccepted());
348 }
349
350 // QGraphicsView
351 {
352 QGraphicsScene scene;
353 tst_QTouchEventGraphicsItem item;
354 QGraphicsView view(&scene);
355 scene.addItem(item: &item);
356 item.setPos(ax: 100, ay: 100);
357 view.resize(w: 200, h: 200);
358 view.fitInView(rect: scene.sceneRect());
359
360 // enabling touch events on the item also enables events on the viewport
361 item.setAcceptTouchEvents(true);
362 QVERIFY(view.viewport()->testAttribute(Qt::WA_AcceptTouchEvents));
363
364 // compose an event to the scene that is over the item
365 QTouchEvent::TouchPoint touchPoint(0);
366 touchPoint.setState(Qt::TouchPointPressed);
367 touchPoint.setPos(view.mapFromScene(point: item.mapToScene(point: item.boundingRect().center())));
368 touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint()));
369 touchPoint.setScenePos(view.mapToScene(point: touchPoint.pos().toPoint()));
370 QTouchEvent touchEvent(QEvent::TouchBegin,
371 touchScreenDevice,
372 Qt::NoModifier,
373 Qt::TouchPointPressed,
374 (QList<QTouchEvent::TouchPoint>() << touchPoint));
375 QVERIFY(QApplication::sendEvent(view.viewport(), &touchEvent));
376 QVERIFY(touchEvent.isAccepted());
377 QVERIFY(item.seenTouchBegin);
378 }
379}
380
381void tst_QTouchEvent::touchBeginPropagatesWhenIgnored()
382{
383 // QWidget
384 {
385 tst_QTouchEventWidget window, child, grandchild;
386 child.setParent(&window);
387 grandchild.setParent(&child);
388
389 // all widgets accept touch events, grandchild ignores, so child sees the event, but not window
390 window.setAttribute(Qt::WA_AcceptTouchEvents);
391 child.setAttribute(Qt::WA_AcceptTouchEvents);
392 grandchild.setAttribute(Qt::WA_AcceptTouchEvents);
393 grandchild.acceptTouchBegin = false;
394
395 QList<QTouchEvent::TouchPoint> touchPoints;
396 touchPoints.append(t: QTouchEvent::TouchPoint(0));
397 QTouchEvent touchEvent(QEvent::TouchBegin,
398 touchScreenDevice,
399 Qt::NoModifier,
400 Qt::TouchPointPressed,
401 touchPoints);
402 QVERIFY(QApplication::sendEvent(&grandchild, &touchEvent));
403 QVERIFY(touchEvent.isAccepted());
404 QVERIFY(grandchild.seenTouchBegin);
405 QVERIFY(child.seenTouchBegin);
406 QVERIFY(!window.seenTouchBegin);
407
408 // disable touch on grandchild. even though it doesn't accept it, child should still get the
409 // TouchBegin
410 grandchild.reset();
411 child.reset();
412 window.reset();
413 grandchild.setAttribute(Qt::WA_AcceptTouchEvents, on: false);
414
415 touchEvent.ignore();
416 QVERIFY(QApplication::sendEvent(&grandchild, &touchEvent));
417 QVERIFY(touchEvent.isAccepted());
418 QVERIFY(!grandchild.seenTouchBegin);
419 QVERIFY(child.seenTouchBegin);
420 QVERIFY(!window.seenTouchBegin);
421 }
422
423 // QGraphicsView
424 {
425 QGraphicsScene scene;
426 tst_QTouchEventGraphicsItem root, child, grandchild;
427 QGraphicsView view(&scene);
428 scene.addItem(item: &root);
429 root.setPos(ax: 100, ay: 100);
430 child.setParentItem(&root);
431 grandchild.setParentItem(&child);
432 view.resize(w: 200, h: 200);
433 view.fitInView(rect: scene.sceneRect());
434
435 // all items accept touch events, grandchild ignores, so child sees the event, but not root
436 root.setAcceptTouchEvents(true);
437 child.setAcceptTouchEvents(true);
438 grandchild.setAcceptTouchEvents(true);
439 grandchild.acceptTouchBegin = false;
440
441 // compose an event to the scene that is over the grandchild
442 QTouchEvent::TouchPoint touchPoint(0);
443 touchPoint.setState(Qt::TouchPointPressed);
444 touchPoint.setPos(view.mapFromScene(point: grandchild.mapToScene(point: grandchild.boundingRect().center())));
445 touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint()));
446 touchPoint.setScenePos(view.mapToScene(point: touchPoint.pos().toPoint()));
447 QTouchEvent touchEvent(QEvent::TouchBegin,
448 touchScreenDevice,
449 Qt::NoModifier,
450 Qt::TouchPointPressed,
451 (QList<QTouchEvent::TouchPoint>() << touchPoint));
452 QVERIFY(QApplication::sendEvent(view.viewport(), &touchEvent));
453 QVERIFY(touchEvent.isAccepted());
454 QVERIFY(grandchild.seenTouchBegin);
455 QVERIFY(child.seenTouchBegin);
456 QVERIFY(!root.seenTouchBegin);
457 }
458
459 // QGraphicsView
460 {
461 QGraphicsScene scene;
462 tst_QTouchEventGraphicsItem root, child, grandchild;
463 QGraphicsView view(&scene);
464 scene.addItem(item: &root);
465 root.setPos(ax: 100, ay: 100);
466 child.setParentItem(&root);
467 grandchild.setParentItem(&child);
468 view.resize(w: 200, h: 200);
469 view.fitInView(rect: scene.sceneRect());
470
471 // leave touch disabled on grandchild. even though it doesn't accept it, child should
472 // still get the TouchBegin
473 root.setAcceptTouchEvents(true);
474 child.setAcceptTouchEvents(true);
475
476 // compose an event to the scene that is over the grandchild
477 QTouchEvent::TouchPoint touchPoint(0);
478 touchPoint.setState(Qt::TouchPointPressed);
479 touchPoint.setPos(view.mapFromScene(point: grandchild.mapToScene(point: grandchild.boundingRect().center())));
480 touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint()));
481 touchPoint.setScenePos(view.mapToScene(point: touchPoint.pos().toPoint()));
482 QTouchEvent touchEvent(QEvent::TouchBegin,
483 touchScreenDevice,
484 Qt::NoModifier,
485 Qt::TouchPointPressed,
486 (QList<QTouchEvent::TouchPoint>() << touchPoint));
487 QVERIFY(QApplication::sendEvent(view.viewport(), &touchEvent));
488 QVERIFY(touchEvent.isAccepted());
489 QVERIFY(!grandchild.seenTouchBegin);
490 QVERIFY(child.seenTouchBegin);
491 QVERIFY(!root.seenTouchBegin);
492 }
493}
494
495void tst_QTouchEvent::touchUpdateAndEndNeverPropagate()
496{
497 // QWidget
498 {
499 tst_QTouchEventWidget window, child;
500 child.setParent(&window);
501
502 window.setAttribute(Qt::WA_AcceptTouchEvents);
503 child.setAttribute(Qt::WA_AcceptTouchEvents);
504 child.acceptTouchUpdate = false;
505 child.acceptTouchEnd = false;
506
507 QList<QTouchEvent::TouchPoint> touchPoints;
508 touchPoints.append(t: QTouchEvent::TouchPoint(0));
509 QTouchEvent touchBeginEvent(QEvent::TouchBegin,
510 touchScreenDevice,
511 Qt::NoModifier,
512 Qt::TouchPointPressed,
513 touchPoints);
514 QVERIFY(QApplication::sendEvent(&child, &touchBeginEvent));
515 QVERIFY(touchBeginEvent.isAccepted());
516 QVERIFY(child.seenTouchBegin);
517 QVERIFY(!window.seenTouchBegin);
518
519 // send the touch update to the child, but ignore it, it doesn't propagate
520 QTouchEvent touchUpdateEvent(QEvent::TouchUpdate,
521 touchScreenDevice,
522 Qt::NoModifier,
523 Qt::TouchPointMoved,
524 touchPoints);
525 QVERIFY(QApplication::sendEvent(&child, &touchUpdateEvent));
526 QVERIFY(!touchUpdateEvent.isAccepted());
527 QVERIFY(child.seenTouchUpdate);
528 QVERIFY(!window.seenTouchUpdate);
529
530 // send the touch end, same thing should happen as with touch update
531 QTouchEvent touchEndEvent(QEvent::TouchEnd,
532 touchScreenDevice,
533 Qt::NoModifier,
534 Qt::TouchPointReleased,
535 touchPoints);
536 QVERIFY(QApplication::sendEvent(&child, &touchEndEvent));
537 QVERIFY(!touchEndEvent.isAccepted());
538 QVERIFY(child.seenTouchEnd);
539 QVERIFY(!window.seenTouchEnd);
540 }
541
542 // QGraphicsView
543 {
544 QGraphicsScene scene;
545 tst_QTouchEventGraphicsItem root, child, grandchild;
546 QGraphicsView view(&scene);
547 scene.addItem(item: &root);
548 root.setPos(ax: 100, ay: 100);
549 child.setParentItem(&root);
550 grandchild.setParentItem(&child);
551 view.resize(w: 200, h: 200);
552 view.fitInView(rect: scene.sceneRect());
553
554 root.setAcceptTouchEvents(true);
555 child.setAcceptTouchEvents(true);
556 child.acceptTouchUpdate = false;
557 child.acceptTouchEnd = false;
558
559 // compose an event to the scene that is over the child
560 QTouchEvent::TouchPoint touchPoint(0);
561 touchPoint.setState(Qt::TouchPointPressed);
562 touchPoint.setPos(view.mapFromScene(point: grandchild.mapToScene(point: grandchild.boundingRect().center())));
563 touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint()));
564 touchPoint.setScenePos(view.mapToScene(point: touchPoint.pos().toPoint()));
565 QTouchEvent touchBeginEvent(QEvent::TouchBegin,
566 touchScreenDevice,
567 Qt::NoModifier,
568 Qt::TouchPointPressed,
569 (QList<QTouchEvent::TouchPoint>() << touchPoint));
570 QVERIFY(QApplication::sendEvent(view.viewport(), &touchBeginEvent));
571 QVERIFY(touchBeginEvent.isAccepted());
572 QVERIFY(child.seenTouchBegin);
573 QVERIFY(!root.seenTouchBegin);
574
575 // send the touch update to the child, but ignore it, it doesn't propagate
576 touchPoint.setState(Qt::TouchPointMoved);
577 QTouchEvent touchUpdateEvent(QEvent::TouchUpdate,
578 touchScreenDevice,
579 Qt::NoModifier,
580 Qt::TouchPointMoved,
581 (QList<QTouchEvent::TouchPoint>() << touchPoint));
582 QVERIFY(QApplication::sendEvent(view.viewport(), &touchUpdateEvent));
583 // the scene accepts the event, since it found an item to send the event to
584 QVERIFY(!touchUpdateEvent.isAccepted());
585 QVERIFY(child.seenTouchUpdate);
586 QVERIFY(!root.seenTouchUpdate);
587
588 // send the touch end, same thing should happen as with touch update
589 touchPoint.setState(Qt::TouchPointReleased);
590 QTouchEvent touchEndEvent(QEvent::TouchEnd,
591 touchScreenDevice,
592 Qt::NoModifier,
593 Qt::TouchPointReleased,
594 (QList<QTouchEvent::TouchPoint>() << touchPoint));
595 QVERIFY(QApplication::sendEvent(view.viewport(), &touchEndEvent));
596 // the scene accepts the event, since it found an item to send the event to
597 QVERIFY(!touchEndEvent.isAccepted());
598 QVERIFY(child.seenTouchEnd);
599 QVERIFY(!root.seenTouchEnd);
600 }
601}
602
603QPointF normalized(const QPointF &pos, const QRectF &rect)
604{
605 return QPointF(pos.x() / rect.width(), pos.y() / rect.height());
606}
607
608void tst_QTouchEvent::basicRawEventTranslation()
609{
610 tst_QTouchEventWidget touchWidget;
611 touchWidget.setWindowTitle(QTest::currentTestFunction());
612 touchWidget.setAttribute(Qt::WA_AcceptTouchEvents);
613 touchWidget.setGeometry(ax: 100, ay: 100, aw: 400, ah: 300);
614 touchWidget.show();
615 QVERIFY(QTest::qWaitForWindowExposed(&touchWidget));
616
617 QPointF pos = touchWidget.rect().center();
618 QPointF screenPos = touchWidget.mapToGlobal(pos.toPoint());
619 QPointF delta(10, 10);
620 QRectF screenGeometry = touchWidget.screen()->geometry();
621
622 QTouchEvent::TouchPoint rawTouchPoint;
623 rawTouchPoint.setId(0);
624
625 // this should be translated to a TouchBegin
626 rawTouchPoint.setState(Qt::TouchPointPressed);
627 rawTouchPoint.setScreenPos(screenPos);
628 rawTouchPoint.setNormalizedPos(normalized(pos: rawTouchPoint.pos(), rect: screenGeometry));
629 QVector<QPointF> rawPosList;
630 rawPosList << QPointF(12, 34) << QPointF(56, 78);
631 rawTouchPoint.setRawScreenPositions(rawPosList);
632 const ulong timestamp = 1234;
633 QWindow *window = touchWidget.windowHandle();
634 QList<QWindowSystemInterface::TouchPoint> nativeTouchPoints =
635 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: QList<QTouchEvent::TouchPoint>() << rawTouchPoint, window);
636 QWindowSystemInterface::handleTouchEvent(window, timestamp, device: touchScreenDevice, points: nativeTouchPoints);
637 QCoreApplication::processEvents();
638 QVERIFY(touchWidget.seenTouchBegin);
639 QVERIFY(!touchWidget.seenTouchUpdate);
640 QVERIFY(!touchWidget.seenTouchEnd);
641 QCOMPARE(touchWidget.touchBeginPoints.count(), 1);
642 QCOMPARE(touchWidget.timestamp, timestamp);
643 QTouchEvent::TouchPoint touchBeginPoint = touchWidget.touchBeginPoints.first();
644 const int touchPointId = (QTouchDevicePrivate::get(q: touchScreenDevice)->id << 24) + 1;
645 QCOMPARE(touchBeginPoint.id(), touchPointId);
646 QCOMPARE(touchBeginPoint.state(), rawTouchPoint.state());
647 QCOMPARE(touchBeginPoint.pos(), pos);
648 QCOMPARE(touchBeginPoint.startPos(), pos);
649 QCOMPARE(touchBeginPoint.lastPos(), pos);
650 QCOMPARE(touchBeginPoint.scenePos(), rawTouchPoint.screenPos());
651 QCOMPARE(touchBeginPoint.startScenePos(), rawTouchPoint.screenPos());
652 QCOMPARE(touchBeginPoint.lastScenePos(), rawTouchPoint.screenPos());
653 QCOMPARE(touchBeginPoint.screenPos(), rawTouchPoint.screenPos());
654 QCOMPARE(touchBeginPoint.startScreenPos(), rawTouchPoint.screenPos());
655 QCOMPARE(touchBeginPoint.lastScreenPos(), rawTouchPoint.screenPos());
656 QCOMPARE(touchBeginPoint.normalizedPos(), rawTouchPoint.normalizedPos());
657 QCOMPARE(touchBeginPoint.startNormalizedPos(), touchBeginPoint.normalizedPos());
658 QCOMPARE(touchBeginPoint.lastNormalizedPos(), touchBeginPoint.normalizedPos());
659 QCOMPARE(touchBeginPoint.pos(), pos);
660 QCOMPARE(touchBeginPoint.screenPos(), rawTouchPoint.screenPos());
661 QCOMPARE(touchBeginPoint.scenePos(), touchBeginPoint.scenePos());
662 QCOMPARE(touchBeginPoint.ellipseDiameters(), QSizeF(0, 0));
663 QCOMPARE(touchBeginPoint.pressure(), qreal(1.));
664 QCOMPARE(touchBeginPoint.velocity(), QVector2D());
665 if (!QHighDpiScaling::isActive())
666 QCOMPARE(touchBeginPoint.rawScreenPositions(), rawPosList);
667
668 // moving the point should translate to TouchUpdate
669 rawTouchPoint.setState(Qt::TouchPointMoved);
670 rawTouchPoint.setScreenPos(screenPos + delta);
671 rawTouchPoint.setNormalizedPos(normalized(pos: rawTouchPoint.pos(), rect: screenGeometry));
672 nativeTouchPoints =
673 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: QList<QTouchEvent::TouchPoint>() << rawTouchPoint, window);
674 QWindowSystemInterface::handleTouchEvent(window, timestamp: 0, device: touchScreenDevice, points: nativeTouchPoints);
675 QCoreApplication::processEvents();
676 QVERIFY(touchWidget.seenTouchBegin);
677 QVERIFY(touchWidget.seenTouchUpdate);
678 QVERIFY(!touchWidget.seenTouchEnd);
679 QCOMPARE(touchWidget.touchUpdatePoints.count(), 1);
680 QTouchEvent::TouchPoint touchUpdatePoint = touchWidget.touchUpdatePoints.first();
681 QCOMPARE(touchUpdatePoint.id(), touchPointId);
682 QCOMPARE(touchUpdatePoint.state(), rawTouchPoint.state());
683 QCOMPARE(touchUpdatePoint.pos(), pos + delta);
684 QCOMPARE(touchUpdatePoint.startPos(), pos);
685 QCOMPARE(touchUpdatePoint.lastPos(), pos);
686 QCOMPARE(touchUpdatePoint.scenePos(), rawTouchPoint.screenPos());
687 QCOMPARE(touchUpdatePoint.startScenePos(), screenPos);
688 QCOMPARE(touchUpdatePoint.lastScenePos(), screenPos);
689 QCOMPARE(touchUpdatePoint.screenPos(), rawTouchPoint.screenPos());
690 QCOMPARE(touchUpdatePoint.startScreenPos(), screenPos);
691 QCOMPARE(touchUpdatePoint.lastScreenPos(), screenPos);
692 QCOMPARE(touchUpdatePoint.normalizedPos(), rawTouchPoint.normalizedPos());
693 QCOMPARE(touchUpdatePoint.startNormalizedPos(), touchBeginPoint.normalizedPos());
694 QCOMPARE(touchUpdatePoint.lastNormalizedPos(), touchBeginPoint.normalizedPos());
695 QCOMPARE(touchUpdatePoint.pos(), pos + delta);
696 QCOMPARE(touchUpdatePoint.screenPos(), rawTouchPoint.screenPos());
697 QCOMPARE(touchUpdatePoint.scenePos(), touchUpdatePoint.scenePos());
698 QCOMPARE(touchUpdatePoint.ellipseDiameters(), QSizeF(0, 0));
699 QCOMPARE(touchUpdatePoint.pressure(), qreal(1.));
700
701 // releasing the point translates to TouchEnd
702 rawTouchPoint.setState(Qt::TouchPointReleased);
703 rawTouchPoint.setScreenPos(screenPos + delta + delta);
704 rawTouchPoint.setNormalizedPos(normalized(pos: rawTouchPoint.pos(), rect: screenGeometry));
705 nativeTouchPoints =
706 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: QList<QTouchEvent::TouchPoint>() << rawTouchPoint, window);
707 QWindowSystemInterface::handleTouchEvent(window, timestamp: 0, device: touchScreenDevice, points: nativeTouchPoints);
708 QCoreApplication::processEvents();
709 QVERIFY(touchWidget.seenTouchBegin);
710 QVERIFY(touchWidget.seenTouchUpdate);
711 QVERIFY(touchWidget.seenTouchEnd);
712 QCOMPARE(touchWidget.touchEndPoints.count(), 1);
713 QTouchEvent::TouchPoint touchEndPoint = touchWidget.touchEndPoints.first();
714 QCOMPARE(touchEndPoint.id(), touchPointId);
715 QCOMPARE(touchEndPoint.state(), rawTouchPoint.state());
716 QCOMPARE(touchEndPoint.pos(), pos + delta + delta);
717 QCOMPARE(touchEndPoint.startPos(), pos);
718 QCOMPARE(touchEndPoint.lastPos(), pos + delta);
719 QCOMPARE(touchEndPoint.scenePos(), rawTouchPoint.screenPos());
720 QCOMPARE(touchEndPoint.startScenePos(), screenPos);
721 QCOMPARE(touchEndPoint.lastScenePos(), screenPos + delta);
722 QCOMPARE(touchEndPoint.screenPos(), rawTouchPoint.screenPos());
723 QCOMPARE(touchEndPoint.startScreenPos(), screenPos);
724 QCOMPARE(touchEndPoint.lastScreenPos(), screenPos + delta);
725 QCOMPARE(touchEndPoint.normalizedPos(), rawTouchPoint.normalizedPos());
726 QCOMPARE(touchEndPoint.startNormalizedPos(), touchBeginPoint.normalizedPos());
727 QCOMPARE(touchEndPoint.lastNormalizedPos(), touchUpdatePoint.normalizedPos());
728 QCOMPARE(touchEndPoint.pos(), pos + delta + delta);
729 QCOMPARE(touchEndPoint.screenPos(), rawTouchPoint.screenPos());
730 QCOMPARE(touchEndPoint.scenePos(), touchEndPoint.scenePos());
731 QCOMPARE(touchEndPoint.ellipseDiameters(), QSizeF(0, 0));
732 QCOMPARE(touchEndPoint.pressure(), qreal(0.));
733}
734
735void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen()
736{
737 tst_QTouchEventWidget touchWidget;
738 touchWidget.setWindowTitle(QTest::currentTestFunction());
739 touchWidget.setAttribute(Qt::WA_AcceptTouchEvents);
740 touchWidget.setGeometry(ax: 100, ay: 100, aw: 400, ah: 300);
741
742 tst_QTouchEventWidget leftWidget(&touchWidget);
743 leftWidget.setAttribute(Qt::WA_AcceptTouchEvents);
744 leftWidget.setGeometry(ax: 0, ay: 100, aw: 100, ah: 100);
745
746 tst_QTouchEventWidget rightWidget(&touchWidget);
747 rightWidget.setAttribute(Qt::WA_AcceptTouchEvents);
748 rightWidget.setGeometry(ax: 300, ay: 100, aw: 100, ah: 100);
749
750 touchWidget.show();
751 QVERIFY(QTest::qWaitForWindowExposed(&touchWidget));
752
753 QPointF leftPos = leftWidget.rect().center();
754 QPointF rightPos = rightWidget.rect().center();
755 QPointF centerPos = touchWidget.rect().center();
756 QPointF leftScreenPos = leftWidget.mapToGlobal(leftPos.toPoint());
757 QPointF rightScreenPos = rightWidget.mapToGlobal(rightPos.toPoint());
758 QPointF centerScreenPos = touchWidget.mapToGlobal(centerPos.toPoint());
759 QRectF screenGeometry = touchWidget.screen()->geometry();
760
761 QList<QTouchEvent::TouchPoint> rawTouchPoints;
762 rawTouchPoints.append(t: QTouchEvent::TouchPoint(0));
763 rawTouchPoints.append(t: QTouchEvent::TouchPoint(1));
764
765 // generate TouchBegins on both leftWidget and rightWidget
766 rawTouchPoints[0].setState(Qt::TouchPointPressed);
767 rawTouchPoints[0].setScreenPos(leftScreenPos);
768 rawTouchPoints[0].setNormalizedPos(normalized(pos: rawTouchPoints[0].pos(), rect: screenGeometry));
769 rawTouchPoints[1].setState(Qt::TouchPointPressed);
770 rawTouchPoints[1].setScreenPos(rightScreenPos);
771 rawTouchPoints[1].setNormalizedPos(normalized(pos: rawTouchPoints[1].pos(), rect: screenGeometry));
772 QWindow *window = touchWidget.windowHandle();
773 QList<QWindowSystemInterface::TouchPoint> nativeTouchPoints =
774 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: rawTouchPoints, window);
775 QWindowSystemInterface::handleTouchEvent(window, timestamp: 0, device: touchScreenDevice, points: nativeTouchPoints);
776 QCoreApplication::processEvents();
777 QVERIFY(!touchWidget.seenTouchBegin);
778 QVERIFY(!touchWidget.seenTouchUpdate);
779 QVERIFY(!touchWidget.seenTouchEnd);
780 QVERIFY(leftWidget.seenTouchBegin);
781 QVERIFY(!leftWidget.seenTouchUpdate);
782 QVERIFY(!leftWidget.seenTouchEnd);
783 QVERIFY(rightWidget.seenTouchBegin);
784 QVERIFY(!rightWidget.seenTouchUpdate);
785 QVERIFY(!rightWidget.seenTouchEnd);
786 QCOMPARE(leftWidget.touchBeginPoints.count(), 1);
787 QCOMPARE(rightWidget.touchBeginPoints.count(), 1);
788 const int touchPointId0 = (QTouchDevicePrivate::get(q: touchScreenDevice)->id << 24) + 1;
789 const int touchPointId1 = touchPointId0 + 1;
790 {
791 QTouchEvent::TouchPoint leftTouchPoint = leftWidget.touchBeginPoints.first();
792 QCOMPARE(leftTouchPoint.id(), touchPointId0);
793 QCOMPARE(leftTouchPoint.state(), rawTouchPoints[0].state());
794 QCOMPARE(leftTouchPoint.pos(), leftPos);
795 QCOMPARE(leftTouchPoint.startPos(), leftPos);
796 QCOMPARE(leftTouchPoint.lastPos(), leftPos);
797 QCOMPARE(leftTouchPoint.scenePos(), leftScreenPos);
798 QCOMPARE(leftTouchPoint.startScenePos(), leftScreenPos);
799 QCOMPARE(leftTouchPoint.lastScenePos(), leftScreenPos);
800 QCOMPARE(leftTouchPoint.screenPos(), leftScreenPos);
801 QCOMPARE(leftTouchPoint.startScreenPos(), leftScreenPos);
802 QCOMPARE(leftTouchPoint.lastScreenPos(), leftScreenPos);
803 QCOMPARE(leftTouchPoint.normalizedPos(), rawTouchPoints[0].normalizedPos());
804 QCOMPARE(leftTouchPoint.startNormalizedPos(), rawTouchPoints[0].normalizedPos());
805 QCOMPARE(leftTouchPoint.lastNormalizedPos(), rawTouchPoints[0].normalizedPos());
806 QCOMPARE(leftTouchPoint.pos(), leftPos);
807 QCOMPARE(leftTouchPoint.scenePos(), leftScreenPos);
808 QCOMPARE(leftTouchPoint.screenPos(), leftScreenPos);
809 QCOMPARE(leftTouchPoint.ellipseDiameters(), QSizeF(0, 0));
810 QCOMPARE(leftTouchPoint.pressure(), qreal(1.));
811
812 QTouchEvent::TouchPoint rightTouchPoint = rightWidget.touchBeginPoints.first();
813 QCOMPARE(rightTouchPoint.id(), touchPointId1);
814 QCOMPARE(rightTouchPoint.state(), rawTouchPoints[1].state());
815 QCOMPARE(rightTouchPoint.pos(), rightPos);
816 QCOMPARE(rightTouchPoint.startPos(), rightPos);
817 QCOMPARE(rightTouchPoint.lastPos(), rightPos);
818 QCOMPARE(rightTouchPoint.scenePos(), rightScreenPos);
819 QCOMPARE(rightTouchPoint.startScenePos(), rightScreenPos);
820 QCOMPARE(rightTouchPoint.lastScenePos(), rightScreenPos);
821 QCOMPARE(rightTouchPoint.screenPos(), rightScreenPos);
822 QCOMPARE(rightTouchPoint.startScreenPos(), rightScreenPos);
823 QCOMPARE(rightTouchPoint.lastScreenPos(), rightScreenPos);
824 QCOMPARE(rightTouchPoint.normalizedPos(), rawTouchPoints[1].normalizedPos());
825 QCOMPARE(rightTouchPoint.startNormalizedPos(), rawTouchPoints[1].normalizedPos());
826 QCOMPARE(rightTouchPoint.lastNormalizedPos(), rawTouchPoints[1].normalizedPos());
827 QCOMPARE(rightTouchPoint.pos(), rightPos);
828 QCOMPARE(rightTouchPoint.scenePos(), rightScreenPos);
829 QCOMPARE(rightTouchPoint.screenPos(), rightScreenPos);
830 QCOMPARE(rightTouchPoint.ellipseDiameters(), QSizeF(0, 0));
831 QCOMPARE(rightTouchPoint.pressure(), qreal(1.));
832 }
833
834 // generate TouchUpdates on both leftWidget and rightWidget
835 rawTouchPoints[0].setState(Qt::TouchPointMoved);
836 rawTouchPoints[0].setScreenPos(centerScreenPos);
837 rawTouchPoints[0].setNormalizedPos(normalized(pos: rawTouchPoints[0].pos(), rect: screenGeometry));
838 rawTouchPoints[1].setState(Qt::TouchPointMoved);
839 rawTouchPoints[1].setScreenPos(centerScreenPos);
840 rawTouchPoints[1].setNormalizedPos(normalized(pos: rawTouchPoints[1].pos(), rect: screenGeometry));
841 nativeTouchPoints =
842 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: rawTouchPoints, window);
843 QWindowSystemInterface::handleTouchEvent(window, timestamp: 0, device: touchScreenDevice, points: nativeTouchPoints);
844 QCoreApplication::processEvents();
845 QVERIFY(!touchWidget.seenTouchBegin);
846 QVERIFY(!touchWidget.seenTouchUpdate);
847 QVERIFY(!touchWidget.seenTouchEnd);
848 QVERIFY(leftWidget.seenTouchBegin);
849 QVERIFY(leftWidget.seenTouchUpdate);
850 QVERIFY(!leftWidget.seenTouchEnd);
851 QVERIFY(rightWidget.seenTouchBegin);
852 QVERIFY(rightWidget.seenTouchUpdate);
853 QVERIFY(!rightWidget.seenTouchEnd);
854 QCOMPARE(leftWidget.touchUpdatePoints.count(), 1);
855 QCOMPARE(rightWidget.touchUpdatePoints.count(), 1);
856 {
857 QTouchEvent::TouchPoint leftTouchPoint = leftWidget.touchUpdatePoints.first();
858 QCOMPARE(leftTouchPoint.id(), touchPointId0);
859 QCOMPARE(leftTouchPoint.state(), rawTouchPoints[0].state());
860 QCOMPARE(leftTouchPoint.pos(), QPointF(leftWidget.mapFromParent(centerPos.toPoint())));
861 QCOMPARE(leftTouchPoint.startPos(), leftPos);
862 QCOMPARE(leftTouchPoint.lastPos(), leftPos);
863 QCOMPARE(leftTouchPoint.scenePos(), centerScreenPos);
864 QCOMPARE(leftTouchPoint.startScenePos(), leftScreenPos);
865 QCOMPARE(leftTouchPoint.lastScenePos(), leftScreenPos);
866 QCOMPARE(leftTouchPoint.screenPos(), centerScreenPos);
867 QCOMPARE(leftTouchPoint.startScreenPos(), leftScreenPos);
868 QCOMPARE(leftTouchPoint.lastScreenPos(), leftScreenPos);
869 QCOMPARE(leftTouchPoint.normalizedPos(), rawTouchPoints[0].normalizedPos());
870 QCOMPARE(leftTouchPoint.startNormalizedPos(), rawTouchPoints[0].normalizedPos());
871 QCOMPARE(leftTouchPoint.lastNormalizedPos(), rawTouchPoints[0].normalizedPos());
872 QCOMPARE(leftTouchPoint.pos(), leftWidget.mapFromParent(centerPos.toPoint()));
873 QCOMPARE(leftTouchPoint.scenePos(), centerScreenPos);
874 QCOMPARE(leftTouchPoint.screenPos(), centerScreenPos);
875 QCOMPARE(leftTouchPoint.ellipseDiameters(), QSizeF(0, 0));
876 QCOMPARE(leftTouchPoint.pressure(), qreal(1.));
877
878 QTouchEvent::TouchPoint rightTouchPoint = rightWidget.touchUpdatePoints.first();
879 QCOMPARE(rightTouchPoint.id(), touchPointId1);
880 QCOMPARE(rightTouchPoint.state(), rawTouchPoints[1].state());
881 QCOMPARE(rightTouchPoint.pos(), QPointF(rightWidget.mapFromParent(centerPos.toPoint())));
882 QCOMPARE(rightTouchPoint.startPos(), rightPos);
883 QCOMPARE(rightTouchPoint.lastPos(), rightPos);
884 QCOMPARE(rightTouchPoint.scenePos(), centerScreenPos);
885 QCOMPARE(rightTouchPoint.startScenePos(), rightScreenPos);
886 QCOMPARE(rightTouchPoint.lastScenePos(), rightScreenPos);
887 QCOMPARE(rightTouchPoint.screenPos(), centerScreenPos);
888 QCOMPARE(rightTouchPoint.startScreenPos(), rightScreenPos);
889 QCOMPARE(rightTouchPoint.lastScreenPos(), rightScreenPos);
890 QCOMPARE(rightTouchPoint.normalizedPos(), rawTouchPoints[1].normalizedPos());
891 QCOMPARE(rightTouchPoint.startNormalizedPos(), rawTouchPoints[1].normalizedPos());
892 QCOMPARE(rightTouchPoint.lastNormalizedPos(), rawTouchPoints[1].normalizedPos());
893 QCOMPARE(rightTouchPoint.pos(), rightWidget.mapFromParent(centerPos.toPoint()));
894 QCOMPARE(rightTouchPoint.scenePos(), centerScreenPos);
895 QCOMPARE(rightTouchPoint.screenPos(), centerScreenPos);
896 QCOMPARE(rightTouchPoint.ellipseDiameters(), QSizeF(0, 0));
897 QCOMPARE(rightTouchPoint.pressure(), qreal(1.));
898 }
899
900 // generate TouchEnds on both leftWidget and rightWidget
901 rawTouchPoints[0].setState(Qt::TouchPointReleased);
902 rawTouchPoints[0].setScreenPos(centerScreenPos);
903 rawTouchPoints[0].setNormalizedPos(normalized(pos: rawTouchPoints[0].pos(), rect: screenGeometry));
904 rawTouchPoints[1].setState(Qt::TouchPointReleased);
905 rawTouchPoints[1].setScreenPos(centerScreenPos);
906 rawTouchPoints[1].setNormalizedPos(normalized(pos: rawTouchPoints[1].pos(), rect: screenGeometry));
907 nativeTouchPoints =
908 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: rawTouchPoints, window);
909 QWindowSystemInterface::handleTouchEvent(window, timestamp: 0, device: touchScreenDevice, points: nativeTouchPoints);
910 QCoreApplication::processEvents();
911 QVERIFY(!touchWidget.seenTouchBegin);
912 QVERIFY(!touchWidget.seenTouchUpdate);
913 QVERIFY(!touchWidget.seenTouchEnd);
914 QVERIFY(leftWidget.seenTouchBegin);
915 QVERIFY(leftWidget.seenTouchUpdate);
916 QVERIFY(leftWidget.seenTouchEnd);
917 QVERIFY(rightWidget.seenTouchBegin);
918 QVERIFY(rightWidget.seenTouchUpdate);
919 QVERIFY(rightWidget.seenTouchEnd);
920 QCOMPARE(leftWidget.touchEndPoints.count(), 1);
921 QCOMPARE(rightWidget.touchEndPoints.count(), 1);
922 {
923 QTouchEvent::TouchPoint leftTouchPoint = leftWidget.touchEndPoints.first();
924 QCOMPARE(leftTouchPoint.id(), touchPointId0);
925 QCOMPARE(leftTouchPoint.state(), rawTouchPoints[0].state());
926 QCOMPARE(leftTouchPoint.pos(), QPointF(leftWidget.mapFromParent(centerPos.toPoint())));
927 QCOMPARE(leftTouchPoint.startPos(), leftPos);
928 QCOMPARE(leftTouchPoint.lastPos(), leftTouchPoint.pos());
929 QCOMPARE(leftTouchPoint.scenePos(), centerScreenPos);
930 QCOMPARE(leftTouchPoint.startScenePos(), leftScreenPos);
931 QCOMPARE(leftTouchPoint.lastScenePos(), leftTouchPoint.scenePos());
932 QCOMPARE(leftTouchPoint.screenPos(), centerScreenPos);
933 QCOMPARE(leftTouchPoint.startScreenPos(), leftScreenPos);
934 QCOMPARE(leftTouchPoint.lastScreenPos(), leftTouchPoint.screenPos());
935 QCOMPARE(leftTouchPoint.normalizedPos(), rawTouchPoints[0].normalizedPos());
936 QCOMPARE(leftTouchPoint.startNormalizedPos(), rawTouchPoints[0].normalizedPos());
937 QCOMPARE(leftTouchPoint.lastNormalizedPos(), rawTouchPoints[0].normalizedPos());
938 QCOMPARE(leftTouchPoint.pos(), leftWidget.mapFromParent(centerPos.toPoint()));
939 QCOMPARE(leftTouchPoint.scenePos(), centerScreenPos);
940 QCOMPARE(leftTouchPoint.screenPos(), centerScreenPos);
941 QCOMPARE(leftTouchPoint.ellipseDiameters(), QSizeF(0, 0));
942 QCOMPARE(leftTouchPoint.pressure(), qreal(0.));
943
944 QTouchEvent::TouchPoint rightTouchPoint = rightWidget.touchEndPoints.first();
945 QCOMPARE(rightTouchPoint.id(), touchPointId1);
946 QCOMPARE(rightTouchPoint.state(), rawTouchPoints[1].state());
947 QCOMPARE(rightTouchPoint.pos(), QPointF(rightWidget.mapFromParent(centerPos.toPoint())));
948 QCOMPARE(rightTouchPoint.startPos(), rightPos);
949 QCOMPARE(rightTouchPoint.lastPos(), rightTouchPoint.pos());
950 QCOMPARE(rightTouchPoint.scenePos(), centerScreenPos);
951 QCOMPARE(rightTouchPoint.startScenePos(), rightScreenPos);
952 QCOMPARE(rightTouchPoint.lastScenePos(), rightTouchPoint.scenePos());
953 QCOMPARE(rightTouchPoint.screenPos(), centerScreenPos);
954 QCOMPARE(rightTouchPoint.startScreenPos(), rightScreenPos);
955 QCOMPARE(rightTouchPoint.lastScreenPos(), rightTouchPoint.screenPos());
956 QCOMPARE(rightTouchPoint.normalizedPos(), rawTouchPoints[1].normalizedPos());
957 QCOMPARE(rightTouchPoint.startNormalizedPos(), rawTouchPoints[1].normalizedPos());
958 QCOMPARE(rightTouchPoint.lastNormalizedPos(), rawTouchPoints[1].normalizedPos());
959 QCOMPARE(rightTouchPoint.pos(), rightWidget.mapFromParent(centerPos.toPoint()));
960 QCOMPARE(rightTouchPoint.scenePos(), centerScreenPos);
961 QCOMPARE(rightTouchPoint.screenPos(), centerScreenPos);
962 QCOMPARE(rightTouchPoint.ellipseDiameters(), QSizeF(0, 0));
963 QCOMPARE(rightTouchPoint.pressure(), qreal(0.));
964 }
965}
966
967void tst_QTouchEvent::touchOnMultipleTouchscreens()
968{
969 tst_QTouchEventWidget touchWidget;
970 touchWidget.setWindowTitle(QTest::currentTestFunction());
971 touchWidget.setAttribute(Qt::WA_AcceptTouchEvents);
972 touchWidget.setGeometry(ax: 100, ay: 100, aw: 400, ah: 300);
973 touchWidget.show();
974 QVERIFY(QTest::qWaitForWindowExposed(&touchWidget));
975 QWindow *window = touchWidget.windowHandle();
976
977 QPointF pos = touchWidget.rect().center();
978 QPointF screenPos = touchWidget.mapToGlobal(pos.toPoint());
979 QPointF delta(10, 10);
980 QRectF screenGeometry = touchWidget.screen()->geometry();
981
982 QVector<QTouchEvent::TouchPoint> rawTouchPoints(3);
983 rawTouchPoints[0].setId(0);
984 rawTouchPoints[1].setId(10);
985 rawTouchPoints[2].setId(11);
986
987 // this should be translated to a TouchBegin
988 rawTouchPoints[0].setState(Qt::TouchPointPressed);
989 rawTouchPoints[0].setScreenPos(screenPos);
990 rawTouchPoints[0].setNormalizedPos(normalized(pos: rawTouchPoints[0].pos(), rect: screenGeometry));
991 rawTouchPoints[0].setRawScreenPositions({{12, 34}, {56, 78}});
992 ulong timestamp = 1234;
993 QList<QWindowSystemInterface::TouchPoint> nativeTouchPoints =
994 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: QList<QTouchEvent::TouchPoint>() << rawTouchPoints[0], window);
995 QWindowSystemInterface::handleTouchEvent(window, timestamp, device: touchScreenDevice, points: nativeTouchPoints);
996 QCoreApplication::processEvents();
997 QVERIFY(touchWidget.seenTouchBegin);
998 QVERIFY(!touchWidget.seenTouchUpdate);
999 QVERIFY(!touchWidget.seenTouchEnd);
1000 QCOMPARE(touchWidget.touchBeginPoints.count(), 1);
1001 QCOMPARE(touchWidget.timestamp, timestamp);
1002 QTouchEvent::TouchPoint touchBeginPoint = touchWidget.touchBeginPoints.first();
1003 const int touchPointId = (QTouchDevicePrivate::get(q: touchScreenDevice)->id << 24) + 1;
1004 const int secTouchPointId = (QTouchDevicePrivate::get(q: secondaryTouchScreenDevice)->id << 24) + 2;
1005 QCOMPARE(touchBeginPoint.id(), touchPointId);
1006 QCOMPARE(touchBeginPoint.state(), rawTouchPoints[0].state());
1007 QCOMPARE(touchBeginPoint.pos(), pos);
1008
1009 // press a point on secondaryTouchScreenDevice
1010 touchWidget.seenTouchBegin = false;
1011 rawTouchPoints[1].setState(Qt::TouchPointPressed);
1012 rawTouchPoints[1].setScreenPos(screenPos);
1013 rawTouchPoints[1].setNormalizedPos(normalized(pos: rawTouchPoints[1].pos(), rect: screenGeometry));
1014 rawTouchPoints[1].setRawScreenPositions({{90, 100}, {110, 120}});
1015 nativeTouchPoints =
1016 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: QList<QTouchEvent::TouchPoint>() << rawTouchPoints[1], window);
1017 QWindowSystemInterface::handleTouchEvent(window, timestamp: ++timestamp, device: secondaryTouchScreenDevice, points: nativeTouchPoints);
1018 QCoreApplication::processEvents();
1019 QVERIFY(!touchWidget.seenTouchEnd);
1020 QCOMPARE(touchWidget.touchBeginPoints.count(), 1);
1021 QCOMPARE(touchWidget.timestamp, timestamp);
1022 touchBeginPoint = touchWidget.touchBeginPoints[0];
1023 QCOMPARE(touchBeginPoint.id(), (QTouchDevicePrivate::get(secondaryTouchScreenDevice)->id << 24) + 2);
1024 QCOMPARE(touchBeginPoint.state(), rawTouchPoints[1].state());
1025 QCOMPARE(touchBeginPoint.pos(), pos);
1026
1027 // press another point on secondaryTouchScreenDevice
1028 touchWidget.seenTouchBegin = false;
1029 rawTouchPoints[2].setState(Qt::TouchPointPressed);
1030 rawTouchPoints[2].setScreenPos(screenPos);
1031 rawTouchPoints[2].setNormalizedPos(normalized(pos: rawTouchPoints[2].pos(), rect: screenGeometry));
1032 rawTouchPoints[2].setRawScreenPositions({{130, 140}, {150, 160}});
1033 nativeTouchPoints =
1034 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: QList<QTouchEvent::TouchPoint>() << rawTouchPoints[2], window);
1035 QWindowSystemInterface::handleTouchEvent(window, timestamp: ++timestamp, device: secondaryTouchScreenDevice, points: nativeTouchPoints);
1036 QCoreApplication::processEvents();
1037 QVERIFY(!touchWidget.seenTouchEnd);
1038 QCOMPARE(touchWidget.touchBeginPoints.count(), 1);
1039 QCOMPARE(touchWidget.timestamp, timestamp);
1040 touchBeginPoint = touchWidget.touchBeginPoints[0];
1041 QCOMPARE(touchBeginPoint.id(), (QTouchDevicePrivate::get(secondaryTouchScreenDevice)->id << 24) + 3);
1042 QCOMPARE(touchBeginPoint.state(), rawTouchPoints[2].state());
1043 QCOMPARE(touchBeginPoint.pos(), pos);
1044
1045 // moving the first point should translate to TouchUpdate
1046 rawTouchPoints[0].setState(Qt::TouchPointMoved);
1047 rawTouchPoints[0].setScreenPos(screenPos + delta);
1048 rawTouchPoints[0].setNormalizedPos(normalized(pos: rawTouchPoints[0].pos(), rect: screenGeometry));
1049 nativeTouchPoints =
1050 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: QList<QTouchEvent::TouchPoint>() << rawTouchPoints[0], window);
1051 QWindowSystemInterface::handleTouchEvent(window, timestamp: ++timestamp, device: touchScreenDevice, points: nativeTouchPoints);
1052 QCoreApplication::processEvents();
1053 QVERIFY(touchWidget.seenTouchBegin);
1054 QVERIFY(touchWidget.seenTouchUpdate);
1055 QVERIFY(!touchWidget.seenTouchEnd);
1056 QCOMPARE(touchWidget.touchUpdatePoints.count(), 1);
1057 QTouchEvent::TouchPoint touchUpdatePoint = touchWidget.touchUpdatePoints.first();
1058 QCOMPARE(touchUpdatePoint.id(), touchPointId);
1059 QCOMPARE(touchUpdatePoint.state(), rawTouchPoints[0].state());
1060 QCOMPARE(touchUpdatePoint.pos(), pos + delta);
1061
1062 // releasing the first point translates to TouchEnd
1063 rawTouchPoints[0].setState(Qt::TouchPointReleased);
1064 rawTouchPoints[0].setScreenPos(screenPos + delta + delta);
1065 rawTouchPoints[0].setNormalizedPos(normalized(pos: rawTouchPoints[0].pos(), rect: screenGeometry));
1066 nativeTouchPoints =
1067 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: QList<QTouchEvent::TouchPoint>() << rawTouchPoints[0], window);
1068 QWindowSystemInterface::handleTouchEvent(window, timestamp: ++timestamp, device: touchScreenDevice, points: nativeTouchPoints);
1069 QCoreApplication::processEvents();
1070 QVERIFY(touchWidget.seenTouchBegin);
1071 QVERIFY(touchWidget.seenTouchUpdate);
1072 QVERIFY(touchWidget.seenTouchEnd);
1073 QCOMPARE(touchWidget.touchEndPoints.count(), 1);
1074 QTouchEvent::TouchPoint touchEndPoint = touchWidget.touchEndPoints.first();
1075 QCOMPARE(touchEndPoint.id(), touchPointId);
1076 QCOMPARE(touchEndPoint.state(), rawTouchPoints[0].state());
1077 QCOMPARE(touchEndPoint.pos(), pos + delta + delta);
1078
1079 // Widgets don't normally handle this case: if a TouchEnd was seen before, then
1080 // WA_WState_AcceptedTouchBeginEvent will be false, and
1081 // QApplicationPrivate::translateRawTouchEvent will ignore touch events that aren't TouchBegin.
1082 // So we have to set it true. It _did_ in fact accept the touch begin from the secondary device,
1083 // but it also got a TouchEnd from the primary device in the meantime.
1084 touchWidget.setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, on: true);
1085
1086 // Releasing one point on the secondary touchscreen does not yet generate TouchEnd.
1087 touchWidget.seenTouchEnd = false;
1088 touchWidget.touchEndPoints.clear();
1089 rawTouchPoints[1].setState(Qt::TouchPointReleased);
1090 rawTouchPoints[2].setState(Qt::TouchPointStationary);
1091 nativeTouchPoints =
1092 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: QList<QTouchEvent::TouchPoint>() << rawTouchPoints[1] << rawTouchPoints[2], window);
1093 QWindowSystemInterface::handleTouchEvent(window, timestamp: ++timestamp, device: secondaryTouchScreenDevice, points: nativeTouchPoints);
1094 QCoreApplication::processEvents();
1095 QVERIFY(touchWidget.seenTouchBegin);
1096 QVERIFY(touchWidget.seenTouchUpdate);
1097 QVERIFY(!touchWidget.seenTouchEnd);
1098 QCOMPARE(touchWidget.touchUpdatePoints.count(), 2);
1099 QCOMPARE(touchWidget.touchUpdatePoints[0].id(), secTouchPointId);
1100 QCOMPARE(touchWidget.touchUpdatePoints[1].id(), secTouchPointId + 1);
1101
1102 // releasing the last point on the secondary touchscreen translates to TouchEnd
1103 touchWidget.seenTouchEnd = false;
1104 rawTouchPoints[2].setState(Qt::TouchPointReleased);
1105 nativeTouchPoints =
1106 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: QList<QTouchEvent::TouchPoint>() << rawTouchPoints[2], window);
1107 QWindowSystemInterface::handleTouchEvent(window, timestamp: ++timestamp, device: secondaryTouchScreenDevice, points: nativeTouchPoints);
1108 QCoreApplication::processEvents();
1109 QVERIFY(touchWidget.seenTouchBegin);
1110 QVERIFY(touchWidget.seenTouchUpdate);
1111 QVERIFY(touchWidget.seenTouchEnd);
1112 QCOMPARE(touchWidget.touchEndPoints.count(), 1);
1113 touchEndPoint = touchWidget.touchEndPoints.first();
1114 QCOMPARE(touchEndPoint.id(), secTouchPointId + 1);
1115 QCOMPARE(touchEndPoint.state(), rawTouchPoints[2].state());
1116}
1117
1118void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad()
1119{
1120 tst_QTouchEventWidget touchWidget;
1121 touchWidget.setWindowTitle(QTest::currentTestFunction());
1122 touchWidget.setAttribute(Qt::WA_AcceptTouchEvents);
1123 touchWidget.setGeometry(ax: 100, ay: 100, aw: 400, ah: 300);
1124
1125 tst_QTouchEventWidget leftWidget(&touchWidget);
1126 leftWidget.setAttribute(Qt::WA_AcceptTouchEvents);
1127 leftWidget.setGeometry(ax: 0, ay: 100, aw: 100, ah: 100);
1128 leftWidget.acceptTouchBegin =true;
1129
1130 tst_QTouchEventWidget rightWidget(&touchWidget);
1131 rightWidget.setAttribute(Qt::WA_AcceptTouchEvents);
1132 rightWidget.setGeometry(ax: 300, ay: 100, aw: 100, ah: 100);
1133
1134 touchWidget.show();
1135 QVERIFY(QTest::qWaitForWindowExposed(&touchWidget));
1136
1137 QPointF leftPos = leftWidget.rect().center();
1138 QPointF rightPos = rightWidget.rect().center();
1139 QPointF centerPos = touchWidget.rect().center();
1140 QPointF leftScreenPos = leftWidget.mapToGlobal(leftPos.toPoint());
1141 QPointF rightScreenPos = rightWidget.mapToGlobal(rightPos.toPoint());
1142 QPointF centerScreenPos = touchWidget.mapToGlobal(centerPos.toPoint());
1143 QRectF screenGeometry = touchWidget.screen()->geometry();
1144
1145 QList<QTouchEvent::TouchPoint> rawTouchPoints;
1146 rawTouchPoints.append(t: QTouchEvent::TouchPoint(0));
1147 rawTouchPoints.append(t: QTouchEvent::TouchPoint(1));
1148
1149 // generate TouchBegin on leftWidget only
1150 rawTouchPoints[0].setState(Qt::TouchPointPressed);
1151 rawTouchPoints[0].setScreenPos(leftScreenPos);
1152 rawTouchPoints[0].setNormalizedPos(normalized(pos: rawTouchPoints[0].pos(), rect: screenGeometry));
1153 rawTouchPoints[1].setState(Qt::TouchPointPressed);
1154 rawTouchPoints[1].setScreenPos(rightScreenPos);
1155 rawTouchPoints[1].setNormalizedPos(normalized(pos: rawTouchPoints[1].pos(), rect: screenGeometry));
1156 QWindow *window = touchWidget.windowHandle();
1157 QList<QWindowSystemInterface::TouchPoint> nativeTouchPoints =
1158 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: rawTouchPoints, window);
1159 QWindowSystemInterface::handleTouchEvent(window, timestamp: 0, device: touchPadDevice, points: nativeTouchPoints);
1160 QCoreApplication::processEvents();
1161 QVERIFY(!touchWidget.seenTouchBegin);
1162 QVERIFY(!touchWidget.seenTouchUpdate);
1163 QVERIFY(!touchWidget.seenTouchEnd);
1164 QEXPECT_FAIL("", "QTBUG-46266, fails in Qt 5", Abort);
1165 QVERIFY(!leftWidget.seenTouchBegin);
1166 QVERIFY(!leftWidget.seenTouchUpdate);
1167 QVERIFY(!leftWidget.seenTouchEnd);
1168 QVERIFY(!rightWidget.seenTouchBegin);
1169 QVERIFY(!rightWidget.seenTouchUpdate);
1170 QVERIFY(!rightWidget.seenTouchEnd);
1171 QCOMPARE(leftWidget.touchBeginPoints.count(), 2);
1172 QCOMPARE(rightWidget.touchBeginPoints.count(), 0);
1173 {
1174 QTouchEvent::TouchPoint leftTouchPoint = leftWidget.touchBeginPoints.at(i: 0);
1175 QCOMPARE(leftTouchPoint.id(), rawTouchPoints[0].id());
1176 QCOMPARE(leftTouchPoint.state(), rawTouchPoints[0].state());
1177 QCOMPARE(leftTouchPoint.pos(), leftPos);
1178 QCOMPARE(leftTouchPoint.startPos(), leftPos);
1179 QCOMPARE(leftTouchPoint.lastPos(), leftPos);
1180 QCOMPARE(leftTouchPoint.scenePos(), leftScreenPos);
1181 QCOMPARE(leftTouchPoint.startScenePos(), leftScreenPos);
1182 QCOMPARE(leftTouchPoint.lastScenePos(), leftScreenPos);
1183 QCOMPARE(leftTouchPoint.screenPos(), leftScreenPos);
1184 QCOMPARE(leftTouchPoint.startScreenPos(), leftScreenPos);
1185 QCOMPARE(leftTouchPoint.lastScreenPos(), leftScreenPos);
1186 QCOMPARE(leftTouchPoint.normalizedPos(), rawTouchPoints[0].normalizedPos());
1187 QCOMPARE(leftTouchPoint.startNormalizedPos(), rawTouchPoints[0].normalizedPos());
1188 QCOMPARE(leftTouchPoint.lastNormalizedPos(), rawTouchPoints[0].normalizedPos());
1189 QCOMPARE(leftTouchPoint.pos(), leftPos);
1190 QCOMPARE(leftTouchPoint.scenePos(), leftScreenPos);
1191 QCOMPARE(leftTouchPoint.screenPos(), leftScreenPos);
1192 QCOMPARE(leftTouchPoint.ellipseDiameters(), QSizeF(0, 0));
1193 QCOMPARE(leftTouchPoint.pressure(), qreal(1.));
1194
1195 QTouchEvent::TouchPoint rightTouchPoint = leftWidget.touchBeginPoints.at(i: 1);
1196 QCOMPARE(rightTouchPoint.id(), rawTouchPoints[1].id());
1197 QCOMPARE(rightTouchPoint.state(), rawTouchPoints[1].state());
1198 QCOMPARE(rightTouchPoint.pos(), QPointF(leftWidget.mapFromGlobal(rightScreenPos.toPoint())));
1199 QCOMPARE(rightTouchPoint.startPos(), QPointF(leftWidget.mapFromGlobal(rightScreenPos.toPoint())));
1200 QCOMPARE(rightTouchPoint.lastPos(), QPointF(leftWidget.mapFromGlobal(rightScreenPos.toPoint())));
1201 QCOMPARE(rightTouchPoint.scenePos(), rightScreenPos);
1202 QCOMPARE(rightTouchPoint.startScenePos(), rightScreenPos);
1203 QCOMPARE(rightTouchPoint.lastScenePos(), rightScreenPos);
1204 QCOMPARE(rightTouchPoint.screenPos(), rightScreenPos);
1205 QCOMPARE(rightTouchPoint.startScreenPos(), rightScreenPos);
1206 QCOMPARE(rightTouchPoint.lastScreenPos(), rightScreenPos);
1207 QCOMPARE(rightTouchPoint.normalizedPos(), rawTouchPoints[1].normalizedPos());
1208 QCOMPARE(rightTouchPoint.startNormalizedPos(), rawTouchPoints[1].normalizedPos());
1209 QCOMPARE(rightTouchPoint.lastNormalizedPos(), rawTouchPoints[1].normalizedPos());
1210 QCOMPARE(rightTouchPoint.pos(), rightWidget.mapFromParent(rightScreenPos.toPoint()));
1211 QCOMPARE(rightTouchPoint.scenePos(), rightScreenPos);
1212 QCOMPARE(rightTouchPoint.screenPos(), rightScreenPos);
1213 QCOMPARE(rightTouchPoint.ellipseDiameters(), QSizeF(0, 0));
1214 QCOMPARE(rightTouchPoint.pressure(), qreal(1.));
1215 }
1216
1217 // generate TouchUpdate on leftWidget
1218 rawTouchPoints[0].setState(Qt::TouchPointMoved);
1219 rawTouchPoints[0].setScreenPos(centerScreenPos);
1220 rawTouchPoints[0].setNormalizedPos(normalized(pos: rawTouchPoints[0].pos(), rect: screenGeometry));
1221 rawTouchPoints[1].setState(Qt::TouchPointMoved);
1222 rawTouchPoints[1].setScreenPos(centerScreenPos);
1223 rawTouchPoints[1].setNormalizedPos(normalized(pos: rawTouchPoints[1].pos(), rect: screenGeometry));
1224 nativeTouchPoints =
1225 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: rawTouchPoints, window);
1226 QWindowSystemInterface::handleTouchEvent(window, timestamp: 0, device: touchPadDevice, points: nativeTouchPoints);
1227 QCoreApplication::processEvents();
1228 QVERIFY(!touchWidget.seenTouchBegin);
1229 QVERIFY(!touchWidget.seenTouchUpdate);
1230 QVERIFY(!touchWidget.seenTouchEnd);
1231 QVERIFY(leftWidget.seenTouchBegin);
1232 QVERIFY(leftWidget.seenTouchUpdate);
1233 QVERIFY(!leftWidget.seenTouchEnd);
1234 QVERIFY(!rightWidget.seenTouchBegin);
1235 QVERIFY(!rightWidget.seenTouchUpdate);
1236 QVERIFY(!rightWidget.seenTouchEnd);
1237 QCOMPARE(leftWidget.touchUpdatePoints.count(), 2);
1238 QCOMPARE(rightWidget.touchUpdatePoints.count(), 0);
1239 {
1240 QTouchEvent::TouchPoint leftTouchPoint = leftWidget.touchUpdatePoints.at(i: 0);
1241 QCOMPARE(leftTouchPoint.id(), rawTouchPoints[0].id());
1242 QCOMPARE(leftTouchPoint.state(), rawTouchPoints[0].state());
1243 QCOMPARE(leftTouchPoint.pos(), QPointF(leftWidget.mapFromParent(centerPos.toPoint())));
1244 QCOMPARE(leftTouchPoint.startPos(), leftPos);
1245 QCOMPARE(leftTouchPoint.lastPos(), leftPos);
1246 QCOMPARE(leftTouchPoint.scenePos(), centerScreenPos);
1247 QCOMPARE(leftTouchPoint.startScenePos(), leftScreenPos);
1248 QCOMPARE(leftTouchPoint.lastScenePos(), leftScreenPos);
1249 QCOMPARE(leftTouchPoint.screenPos(), centerScreenPos);
1250 QCOMPARE(leftTouchPoint.startScreenPos(), leftScreenPos);
1251 QCOMPARE(leftTouchPoint.lastScreenPos(), leftScreenPos);
1252 QCOMPARE(leftTouchPoint.normalizedPos(), rawTouchPoints[0].normalizedPos());
1253 QCOMPARE(leftTouchPoint.startNormalizedPos(), rawTouchPoints[0].normalizedPos());
1254 QCOMPARE(leftTouchPoint.lastNormalizedPos(), rawTouchPoints[0].normalizedPos());
1255 QCOMPARE(leftTouchPoint.pos(), leftWidget.mapFromParent(centerPos.toPoint()));
1256 QCOMPARE(leftTouchPoint.scenePos(), centerScreenPos);
1257 QCOMPARE(leftTouchPoint.screenPos(), centerScreenPos);
1258 QCOMPARE(leftTouchPoint.ellipseDiameters(), QSizeF(0, 0));
1259 QCOMPARE(leftTouchPoint.pressure(), qreal(1.));
1260
1261 QTouchEvent::TouchPoint rightTouchPoint = leftWidget.touchUpdatePoints.at(i: 1);
1262 QCOMPARE(rightTouchPoint.id(), rawTouchPoints[1].id());
1263 QCOMPARE(rightTouchPoint.state(), rawTouchPoints[1].state());
1264 QCOMPARE(rightTouchPoint.pos(), QPointF(leftWidget.mapFromParent(centerPos.toPoint())));
1265 QCOMPARE(rightTouchPoint.startPos(), QPointF(leftWidget.mapFromGlobal(rightScreenPos.toPoint())));
1266 QCOMPARE(rightTouchPoint.lastPos(), QPointF(leftWidget.mapFromGlobal(rightScreenPos.toPoint())));
1267 QCOMPARE(rightTouchPoint.scenePos(), centerScreenPos);
1268 QCOMPARE(rightTouchPoint.startScenePos(), rightScreenPos);
1269 QCOMPARE(rightTouchPoint.lastScenePos(), rightScreenPos);
1270 QCOMPARE(rightTouchPoint.screenPos(), centerScreenPos);
1271 QCOMPARE(rightTouchPoint.startScreenPos(), rightScreenPos);
1272 QCOMPARE(rightTouchPoint.lastScreenPos(), rightScreenPos);
1273 QCOMPARE(rightTouchPoint.normalizedPos(), rawTouchPoints[1].normalizedPos());
1274 QCOMPARE(rightTouchPoint.startNormalizedPos(), rawTouchPoints[1].normalizedPos());
1275 QCOMPARE(rightTouchPoint.lastNormalizedPos(), rawTouchPoints[1].normalizedPos());
1276 QCOMPARE(rightTouchPoint.pos(), leftWidget.mapFromParent(centerPos.toPoint()));
1277 QCOMPARE(rightTouchPoint.scenePos(), centerScreenPos);
1278 QCOMPARE(rightTouchPoint.screenPos(), centerScreenPos);
1279 QCOMPARE(rightTouchPoint.ellipseDiameters(), QSizeF(0, 0));
1280 QCOMPARE(rightTouchPoint.pressure(), qreal(1.));
1281 }
1282
1283 // generate TouchEnd on leftWidget
1284 rawTouchPoints[0].setState(Qt::TouchPointReleased);
1285 rawTouchPoints[0].setScreenPos(centerScreenPos);
1286 rawTouchPoints[0].setNormalizedPos(normalized(pos: rawTouchPoints[0].pos(), rect: screenGeometry));
1287 rawTouchPoints[1].setState(Qt::TouchPointReleased);
1288 rawTouchPoints[1].setScreenPos(centerScreenPos);
1289 rawTouchPoints[1].setNormalizedPos(normalized(pos: rawTouchPoints[1].pos(), rect: screenGeometry));
1290 nativeTouchPoints =
1291 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: rawTouchPoints, window);
1292 QWindowSystemInterface::handleTouchEvent(window, timestamp: 0, device: touchPadDevice, points: nativeTouchPoints);
1293 QCoreApplication::processEvents();
1294 QVERIFY(!touchWidget.seenTouchBegin);
1295 QVERIFY(!touchWidget.seenTouchUpdate);
1296 QVERIFY(!touchWidget.seenTouchEnd);
1297 QVERIFY(leftWidget.seenTouchBegin);
1298 QVERIFY(leftWidget.seenTouchUpdate);
1299 QVERIFY(leftWidget.seenTouchEnd);
1300 QVERIFY(!rightWidget.seenTouchBegin);
1301 QVERIFY(!rightWidget.seenTouchUpdate);
1302 QVERIFY(!rightWidget.seenTouchEnd);
1303 QCOMPARE(leftWidget.touchEndPoints.count(), 2);
1304 QCOMPARE(rightWidget.touchEndPoints.count(), 0);
1305 {
1306 QTouchEvent::TouchPoint leftTouchPoint = leftWidget.touchEndPoints.at(i: 0);
1307 QCOMPARE(leftTouchPoint.id(), rawTouchPoints[0].id());
1308 QCOMPARE(leftTouchPoint.state(), rawTouchPoints[0].state());
1309 QCOMPARE(leftTouchPoint.pos(), QPointF(leftWidget.mapFromParent(centerPos.toPoint())));
1310 QCOMPARE(leftTouchPoint.startPos(), leftPos);
1311 QCOMPARE(leftTouchPoint.lastPos(), leftTouchPoint.pos());
1312 QCOMPARE(leftTouchPoint.scenePos(), centerScreenPos);
1313 QCOMPARE(leftTouchPoint.startScenePos(), leftScreenPos);
1314 QCOMPARE(leftTouchPoint.lastScenePos(), leftTouchPoint.scenePos());
1315 QCOMPARE(leftTouchPoint.screenPos(), centerScreenPos);
1316 QCOMPARE(leftTouchPoint.startScreenPos(), leftScreenPos);
1317 QCOMPARE(leftTouchPoint.lastScreenPos(), leftTouchPoint.screenPos());
1318 QCOMPARE(leftTouchPoint.normalizedPos(), rawTouchPoints[0].normalizedPos());
1319 QCOMPARE(leftTouchPoint.startNormalizedPos(), rawTouchPoints[0].normalizedPos());
1320 QCOMPARE(leftTouchPoint.lastNormalizedPos(), rawTouchPoints[0].normalizedPos());
1321 QCOMPARE(leftTouchPoint.pos(), leftWidget.mapFromParent(centerPos.toPoint()));
1322 QCOMPARE(leftTouchPoint.scenePos(), centerScreenPos);
1323 QCOMPARE(leftTouchPoint.screenPos(), centerScreenPos);
1324 QCOMPARE(leftTouchPoint.ellipseDiameters(), QSizeF(0, 0));
1325 QCOMPARE(leftTouchPoint.pressure(), qreal(0.));
1326
1327 QTouchEvent::TouchPoint rightTouchPoint = leftWidget.touchEndPoints.at(i: 1);
1328 QCOMPARE(rightTouchPoint.id(), rawTouchPoints[1].id());
1329 QCOMPARE(rightTouchPoint.state(), rawTouchPoints[1].state());
1330 QCOMPARE(rightTouchPoint.pos(), QPointF(leftWidget.mapFromParent(centerPos.toPoint())));
1331 QCOMPARE(rightTouchPoint.startPos(), QPointF(leftWidget.mapFromGlobal(rightScreenPos.toPoint())));
1332 QCOMPARE(rightTouchPoint.lastPos(), rightTouchPoint.pos());
1333 QCOMPARE(rightTouchPoint.scenePos(), centerScreenPos);
1334 QCOMPARE(rightTouchPoint.startScenePos(), rightScreenPos);
1335 QCOMPARE(rightTouchPoint.lastScenePos(), rightTouchPoint.scenePos());
1336 QCOMPARE(rightTouchPoint.screenPos(), centerScreenPos);
1337 QCOMPARE(rightTouchPoint.startScreenPos(), rightScreenPos);
1338 QCOMPARE(rightTouchPoint.lastScreenPos(), rightTouchPoint.screenPos());
1339 QCOMPARE(rightTouchPoint.normalizedPos(), rawTouchPoints[1].normalizedPos());
1340 QCOMPARE(rightTouchPoint.startNormalizedPos(), rawTouchPoints[1].normalizedPos());
1341 QCOMPARE(rightTouchPoint.lastNormalizedPos(), rawTouchPoints[1].normalizedPos());
1342 QCOMPARE(rightTouchPoint.pos(), leftWidget.mapFromParent(centerPos.toPoint()));
1343 QCOMPARE(rightTouchPoint.scenePos(), centerScreenPos);
1344 QCOMPARE(rightTouchPoint.screenPos(), centerScreenPos);
1345 QCOMPARE(rightTouchPoint.ellipseDiameters(), QSizeF(0, 0));
1346 QCOMPARE(rightTouchPoint.pressure(), qreal(0.));
1347 }
1348}
1349
1350void tst_QTouchEvent::basicRawEventTranslationOfIds()
1351{
1352 tst_QTouchEventWidget touchWidget;
1353 touchWidget.setWindowTitle(QTest::currentTestFunction());
1354 touchWidget.setAttribute(Qt::WA_AcceptTouchEvents);
1355 touchWidget.setGeometry(ax: 100, ay: 100, aw: 400, ah: 300);
1356 touchWidget.show();
1357 QVERIFY(QTest::qWaitForWindowExposed(&touchWidget));
1358
1359 QVarLengthArray<QPointF, 2> pos;
1360 QVarLengthArray<QPointF, 2> screenPos;
1361 for (int i = 0; i < 2; ++i) {
1362 pos << touchWidget.rect().center() + QPointF(20*i, 20*i);
1363 screenPos << touchWidget.mapToGlobal(pos[i].toPoint());
1364 }
1365 QPointF delta(10, 10);
1366 QRectF screenGeometry = touchWidget.screen()->geometry();
1367
1368 QVector<QPointF> rawPosList;
1369 rawPosList << QPointF(12, 34) << QPointF(56, 78);
1370
1371 QList<QTouchEvent::TouchPoint> rawTouchPoints;
1372
1373 // Press both points, this should be translated to a TouchBegin
1374 for (int i = 0; i < 2; ++i) {
1375 QTouchEvent::TouchPoint rawTouchPoint;
1376 rawTouchPoint.setId(i);
1377 rawTouchPoint.setState(Qt::TouchPointPressed);
1378 rawTouchPoint.setScreenPos(screenPos[i]);
1379 rawTouchPoint.setNormalizedPos(normalized(pos: rawTouchPoint.pos(), rect: screenGeometry));
1380 rawTouchPoint.setRawScreenPositions(rawPosList);
1381 rawTouchPoints << rawTouchPoint;
1382 }
1383 QTouchEvent::TouchPoint &p0 = rawTouchPoints[0];
1384 QTouchEvent::TouchPoint &p1 = rawTouchPoints[1];
1385
1386 const ulong timestamp = 1234;
1387 QWindow *window = touchWidget.windowHandle();
1388 QList<QWindowSystemInterface::TouchPoint> nativeTouchPoints =
1389 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: rawTouchPoints, window);
1390 QWindowSystemInterface::handleTouchEvent(window, timestamp, device: touchScreenDevice, points: nativeTouchPoints);
1391 QCoreApplication::processEvents();
1392 QVERIFY(touchWidget.seenTouchBegin);
1393 QVERIFY(!touchWidget.seenTouchUpdate);
1394 QVERIFY(!touchWidget.seenTouchEnd);
1395 QCOMPARE(touchWidget.touchBeginPoints.count(), 2);
1396
1397 const int initialTouchPointId = (QTouchDevicePrivate::get(q: touchScreenDevice)->id << 24) + 1;
1398
1399 for (int i = 0; i < touchWidget.touchBeginPoints.count(); ++i) {
1400 QTouchEvent::TouchPoint touchBeginPoint = touchWidget.touchBeginPoints.at(i);
1401 QCOMPARE(touchBeginPoint.id(), initialTouchPointId + i);
1402 QCOMPARE(touchBeginPoint.state(), rawTouchPoints[i].state());
1403 }
1404
1405 // moving the point should translate to TouchUpdate
1406 for (int i = 0; i < rawTouchPoints.count(); ++i) {
1407 QTouchEvent::TouchPoint &p = rawTouchPoints[i];
1408 p.setState(Qt::TouchPointMoved);
1409 p.setScreenPos(p.screenPos() + delta);
1410 p.setNormalizedPos(normalized(pos: p.pos(), rect: screenGeometry));
1411 }
1412 nativeTouchPoints =
1413 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: rawTouchPoints, window);
1414 QWindowSystemInterface::handleTouchEvent(window, timestamp: 0, device: touchScreenDevice, points: nativeTouchPoints);
1415 QCoreApplication::processEvents();
1416 QVERIFY(touchWidget.seenTouchBegin);
1417 QVERIFY(touchWidget.seenTouchUpdate);
1418 QVERIFY(!touchWidget.seenTouchEnd);
1419 QCOMPARE(touchWidget.touchUpdatePoints.count(), 2);
1420 QCOMPARE(touchWidget.touchUpdatePoints.at(0).id(), initialTouchPointId);
1421 QCOMPARE(touchWidget.touchUpdatePoints.at(1).id(), initialTouchPointId + 1);
1422
1423 // release last point
1424 p0.setState(Qt::TouchPointStationary);
1425 p1.setState(Qt::TouchPointReleased);
1426
1427 nativeTouchPoints =
1428 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: rawTouchPoints, window);
1429 QWindowSystemInterface::handleTouchEvent(window, timestamp: 0, device: touchScreenDevice, points: nativeTouchPoints);
1430 QCoreApplication::processEvents();
1431 QVERIFY(touchWidget.seenTouchBegin);
1432 QVERIFY(touchWidget.seenTouchUpdate);
1433 QVERIFY(!touchWidget.seenTouchEnd);
1434 QCOMPARE(touchWidget.touchUpdatePoints.count(), 2);
1435 QCOMPARE(touchWidget.touchUpdatePoints[0].id(), initialTouchPointId);
1436 QCOMPARE(touchWidget.touchUpdatePoints[1].id(), initialTouchPointId + 1);
1437
1438 // Press last point again, id should increase
1439 p1.setState(Qt::TouchPointPressed);
1440 p1.setId(42); // new id
1441 nativeTouchPoints =
1442 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: rawTouchPoints, window);
1443 QWindowSystemInterface::handleTouchEvent(window, timestamp: 0, device: touchScreenDevice, points: nativeTouchPoints);
1444 QCoreApplication::processEvents();
1445 QVERIFY(touchWidget.seenTouchBegin);
1446 QVERIFY(touchWidget.seenTouchUpdate);
1447 QVERIFY(!touchWidget.seenTouchEnd);
1448 QCOMPARE(touchWidget.touchUpdatePoints.count(), 2);
1449 QCOMPARE(touchWidget.touchUpdatePoints[0].id(), initialTouchPointId);
1450 QCOMPARE(touchWidget.touchUpdatePoints[1].id(), initialTouchPointId + 2);
1451
1452 // release everything
1453 p0.setState(Qt::TouchPointReleased);
1454 p1.setState(Qt::TouchPointReleased);
1455 nativeTouchPoints =
1456 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: rawTouchPoints, window);
1457 QWindowSystemInterface::handleTouchEvent(window, timestamp: 0, device: touchScreenDevice, points: nativeTouchPoints);
1458 QCoreApplication::processEvents();
1459 QVERIFY(touchWidget.seenTouchBegin);
1460 QVERIFY(touchWidget.seenTouchUpdate);
1461 QVERIFY(touchWidget.seenTouchEnd);
1462 QCOMPARE(touchWidget.touchUpdatePoints.count(), 2);
1463 QCOMPARE(touchWidget.touchUpdatePoints[0].id(), initialTouchPointId);
1464 QCOMPARE(touchWidget.touchUpdatePoints[1].id(), initialTouchPointId + 2);
1465}
1466
1467void tst_QTouchEvent::deleteInEventHandler()
1468{
1469 // QWidget
1470 {
1471 QWidget window;
1472 QPointer<tst_QTouchEventWidget> child1 = new tst_QTouchEventWidget(&window);
1473 QPointer<tst_QTouchEventWidget> child2 = new tst_QTouchEventWidget(&window);
1474 QPointer<tst_QTouchEventWidget> child3 = new tst_QTouchEventWidget(&window);
1475 child1->setAttribute(Qt::WA_AcceptTouchEvents);
1476 child2->setAttribute(Qt::WA_AcceptTouchEvents);
1477 child3->setAttribute(Qt::WA_AcceptTouchEvents);
1478 child1->deleteInTouchBegin = true;
1479 child2->deleteInTouchUpdate = true;
1480 child3->deleteInTouchEnd = true;
1481
1482 QList<QTouchEvent::TouchPoint> touchPoints;
1483 touchPoints.append(t: QTouchEvent::TouchPoint(0));
1484 QTouchEvent touchBeginEvent(QEvent::TouchBegin,
1485 touchScreenDevice,
1486 Qt::NoModifier,
1487 Qt::TouchPointPressed,
1488 touchPoints);
1489 QTouchEvent touchUpdateEvent(QEvent::TouchUpdate,
1490 touchScreenDevice,
1491 Qt::NoModifier,
1492 Qt::TouchPointStationary,
1493 touchPoints);
1494 QTouchEvent touchEndEvent(QEvent::TouchEnd,
1495 touchScreenDevice,
1496 Qt::NoModifier,
1497 Qt::TouchPointReleased,
1498 touchPoints);
1499 touchBeginEvent.ignore();
1500 QVERIFY(QApplication::sendEvent(child1, &touchBeginEvent));
1501 // event is handled, but widget should be deleted
1502 QVERIFY(touchBeginEvent.isAccepted());
1503 QVERIFY(child1.isNull());
1504
1505 touchBeginEvent.ignore();
1506 QVERIFY(QApplication::sendEvent(child2, &touchBeginEvent));
1507 QVERIFY(touchBeginEvent.isAccepted());
1508 QVERIFY(!child2.isNull());
1509 touchUpdateEvent.ignore();
1510 QVERIFY(QApplication::sendEvent(child2, &touchUpdateEvent));
1511 QVERIFY(touchUpdateEvent.isAccepted());
1512 QVERIFY(child2.isNull());
1513
1514 touchBeginEvent.ignore();
1515 QVERIFY(QApplication::sendEvent(child3, &touchBeginEvent));
1516 QVERIFY(touchBeginEvent.isAccepted());
1517 QVERIFY(!child3.isNull());
1518 touchUpdateEvent.ignore();
1519 QVERIFY(QApplication::sendEvent(child3, &touchUpdateEvent));
1520 QVERIFY(touchUpdateEvent.isAccepted());
1521 QVERIFY(!child3.isNull());
1522 touchEndEvent.ignore();
1523 QVERIFY(QApplication::sendEvent(child3, &touchEndEvent));
1524 QVERIFY(touchEndEvent.isAccepted());
1525 QVERIFY(child3.isNull());
1526 }
1527
1528 // QGraphicsView
1529 {
1530 QGraphicsScene scene;
1531 QGraphicsView view(&scene);
1532 QScopedPointer<tst_QTouchEventGraphicsItem> root(new tst_QTouchEventGraphicsItem);
1533 tst_QTouchEventGraphicsItem *child1 = new tst_QTouchEventGraphicsItem(root.data());
1534 tst_QTouchEventGraphicsItem *child2 = new tst_QTouchEventGraphicsItem(root.data());
1535 tst_QTouchEventGraphicsItem *child3 = new tst_QTouchEventGraphicsItem(root.data());
1536 child1->setZValue(1.);
1537 child2->setZValue(0.);
1538 child3->setZValue(-1.);
1539 child1->setAcceptTouchEvents(true);
1540 child2->setAcceptTouchEvents(true);
1541 child3->setAcceptTouchEvents(true);
1542 child1->deleteInTouchBegin = true;
1543 child2->deleteInTouchUpdate = true;
1544 child3->deleteInTouchEnd = true;
1545
1546 scene.addItem(item: root.data());
1547 view.resize(w: 200, h: 200);
1548 view.fitInView(rect: scene.sceneRect());
1549
1550 QTouchEvent::TouchPoint touchPoint(0);
1551 touchPoint.setState(Qt::TouchPointPressed);
1552 touchPoint.setPos(view.mapFromScene(point: child1->mapToScene(point: child1->boundingRect().center())));
1553 touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint()));
1554 touchPoint.setScenePos(view.mapToScene(point: touchPoint.pos().toPoint()));
1555 QList<QTouchEvent::TouchPoint> touchPoints;
1556 touchPoints.append(t: touchPoint);
1557 QTouchEvent touchBeginEvent(QEvent::TouchBegin,
1558 touchScreenDevice,
1559 Qt::NoModifier,
1560 Qt::TouchPointPressed,
1561 touchPoints);
1562 touchPoints[0].setState(Qt::TouchPointMoved);
1563 QTouchEvent touchUpdateEvent(QEvent::TouchUpdate,
1564 touchScreenDevice,
1565 Qt::NoModifier,
1566 Qt::TouchPointMoved,
1567 touchPoints);
1568 touchPoints[0].setState(Qt::TouchPointReleased);
1569 QTouchEvent touchEndEvent(QEvent::TouchEnd,
1570 touchScreenDevice,
1571 Qt::NoModifier,
1572 Qt::TouchPointReleased,
1573 touchPoints);
1574
1575 child1->weakpointer = &child1;
1576 touchBeginEvent.ignore();
1577 QVERIFY(QApplication::sendEvent(view.viewport(), &touchBeginEvent));
1578 QVERIFY(touchBeginEvent.isAccepted());
1579 QVERIFY(!child1);
1580 touchUpdateEvent.ignore();
1581 QVERIFY(QApplication::sendEvent(view.viewport(), &touchUpdateEvent));
1582 QVERIFY(!touchUpdateEvent.isAccepted()); // Qt 5.X ignores touch events.
1583 QVERIFY(!child1);
1584 touchEndEvent.ignore();
1585 QVERIFY(QApplication::sendEvent(view.viewport(), &touchEndEvent));
1586 QVERIFY(!touchUpdateEvent.isAccepted());
1587 QVERIFY(!child1);
1588
1589 child2->weakpointer = &child2;
1590 touchBeginEvent.ignore();
1591 QVERIFY(QApplication::sendEvent(view.viewport(), &touchBeginEvent));
1592 QVERIFY(touchBeginEvent.isAccepted());
1593 QVERIFY(child2);
1594 touchUpdateEvent.ignore();
1595 QVERIFY(QApplication::sendEvent(view.viewport(), &touchUpdateEvent));
1596 QVERIFY(!touchUpdateEvent.isAccepted());
1597 QVERIFY(!child2);
1598 touchEndEvent.ignore();
1599 QVERIFY(QApplication::sendEvent(view.viewport(), &touchEndEvent));
1600 QVERIFY(!touchUpdateEvent.isAccepted());
1601 QVERIFY(!child2);
1602
1603 child3->weakpointer = &child3;
1604 QVERIFY(QApplication::sendEvent(view.viewport(), &touchBeginEvent));
1605 QVERIFY(touchBeginEvent.isAccepted());
1606 QVERIFY(child3);
1607 QVERIFY(QApplication::sendEvent(view.viewport(), &touchUpdateEvent));
1608 QVERIFY(!touchUpdateEvent.isAccepted());
1609 QVERIFY(child3);
1610 QVERIFY(QApplication::sendEvent(view.viewport(), &touchEndEvent));
1611 QVERIFY(!touchEndEvent.isAccepted());
1612 QVERIFY(!child3);
1613 }
1614}
1615
1616void tst_QTouchEvent::deleteInRawEventTranslation()
1617{
1618 tst_QTouchEventWidget touchWidget;
1619 touchWidget.setWindowTitle(QTest::currentTestFunction());
1620 touchWidget.setAttribute(Qt::WA_AcceptTouchEvents);
1621 touchWidget.setGeometry(ax: 100, ay: 100, aw: 300, ah: 300);
1622
1623 QPointer<tst_QTouchEventWidget> leftWidget = new tst_QTouchEventWidget(&touchWidget);
1624 leftWidget->setAttribute(Qt::WA_AcceptTouchEvents);
1625 leftWidget->setGeometry(ax: 0, ay: 100, aw: 100, ah: 100);
1626 leftWidget->deleteInTouchBegin = true;
1627
1628 QPointer<tst_QTouchEventWidget> centerWidget = new tst_QTouchEventWidget(&touchWidget);
1629 centerWidget->setAttribute(Qt::WA_AcceptTouchEvents);
1630 centerWidget->setGeometry(ax: 100, ay: 100, aw: 100, ah: 100);
1631 centerWidget->deleteInTouchUpdate = true;
1632
1633 QPointer<tst_QTouchEventWidget> rightWidget = new tst_QTouchEventWidget(&touchWidget);
1634 rightWidget->setAttribute(Qt::WA_AcceptTouchEvents);
1635 rightWidget->setGeometry(ax: 200, ay: 100, aw: 100, ah: 100);
1636 rightWidget->deleteInTouchEnd = true;
1637
1638 touchWidget.show();
1639 QVERIFY(QTest::qWaitForWindowExposed(&touchWidget));
1640
1641 QPointF leftPos = leftWidget->rect().center();
1642 QPointF centerPos = centerWidget->rect().center();
1643 QPointF rightPos = rightWidget->rect().center();
1644 QPointF leftScreenPos = leftWidget->mapToGlobal(leftPos.toPoint());
1645 QPointF centerScreenPos = centerWidget->mapToGlobal(centerPos.toPoint());
1646 QPointF rightScreenPos = rightWidget->mapToGlobal(rightPos.toPoint());
1647 QRectF screenGeometry = touchWidget.screen()->geometry();
1648
1649 QList<QTouchEvent::TouchPoint> rawTouchPoints;
1650 rawTouchPoints.append(t: QTouchEvent::TouchPoint(0));
1651 rawTouchPoints.append(t: QTouchEvent::TouchPoint(1));
1652 rawTouchPoints.append(t: QTouchEvent::TouchPoint(2));
1653 rawTouchPoints[0].setState(Qt::TouchPointPressed);
1654 rawTouchPoints[0].setScreenPos(leftScreenPos);
1655 rawTouchPoints[0].setNormalizedPos(normalized(pos: rawTouchPoints[0].pos(), rect: screenGeometry));
1656 rawTouchPoints[1].setState(Qt::TouchPointPressed);
1657 rawTouchPoints[1].setScreenPos(centerScreenPos);
1658 rawTouchPoints[1].setNormalizedPos(normalized(pos: rawTouchPoints[1].pos(), rect: screenGeometry));
1659 rawTouchPoints[2].setState(Qt::TouchPointPressed);
1660 rawTouchPoints[2].setScreenPos(rightScreenPos);
1661 rawTouchPoints[2].setNormalizedPos(normalized(pos: rawTouchPoints[2].pos(), rect: screenGeometry));
1662
1663 // generate begin events on all widgets, the left widget should die
1664 QWindow *window = touchWidget.windowHandle();
1665 QList<QWindowSystemInterface::TouchPoint> nativeTouchPoints =
1666 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: rawTouchPoints, window);
1667 QWindowSystemInterface::handleTouchEvent(window, timestamp: 0, device: touchScreenDevice, points: nativeTouchPoints);
1668 QCoreApplication::processEvents();
1669 QVERIFY(leftWidget.isNull());
1670 QVERIFY(!centerWidget.isNull());
1671 QVERIFY(!rightWidget.isNull());
1672
1673 // generate update events on all widget, the center widget should die
1674 rawTouchPoints[0].setState(Qt::TouchPointMoved);
1675 rawTouchPoints[1].setState(Qt::TouchPointMoved);
1676 rawTouchPoints[2].setState(Qt::TouchPointMoved);
1677 nativeTouchPoints =
1678 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: rawTouchPoints, window);
1679 QWindowSystemInterface::handleTouchEvent(window, timestamp: 0, device: touchScreenDevice, points: nativeTouchPoints);
1680 QCoreApplication::processEvents();
1681
1682 // generate end events on all widget, the right widget should die
1683 rawTouchPoints[0].setState(Qt::TouchPointReleased);
1684 rawTouchPoints[1].setState(Qt::TouchPointReleased);
1685 rawTouchPoints[2].setState(Qt::TouchPointReleased);
1686 nativeTouchPoints =
1687 QWindowSystemInterfacePrivate::toNativeTouchPoints(pointList: rawTouchPoints, window);
1688 QWindowSystemInterface::handleTouchEvent(window, timestamp: 0, device: touchScreenDevice, points: nativeTouchPoints);
1689 QCoreApplication::processEvents();
1690}
1691
1692void tst_QTouchEvent::crashInQGraphicsSceneAfterNotHandlingTouchBegin()
1693{
1694 QGraphicsRectItem *rect = new QGraphicsRectItem(0, 0, 100, 100);
1695 rect->setAcceptTouchEvents(true);
1696
1697 QGraphicsRectItem *mainRect = new QGraphicsRectItem(0, 0, 100, 100, rect);
1698 mainRect->setBrush(Qt::lightGray);
1699
1700 QGraphicsRectItem *button = new QGraphicsRectItem(-20, -20, 40, 40, mainRect);
1701 button->setPos(ax: 50, ay: 50);
1702 button->setBrush(Qt::darkGreen);
1703
1704 QGraphicsView view;
1705 QGraphicsScene scene;
1706 scene.addItem(item: rect);
1707 scene.setSceneRect(x: 0,y: 0,w: 100,h: 100);
1708 view.setScene(&scene);
1709
1710 view.show();
1711 QVERIFY(QTest::qWaitForWindowExposed(&view));
1712
1713 QPoint centerPos = view.mapFromScene(point: rect->boundingRect().center());
1714 // Touch the button
1715 QTest::touchEvent(widget: view.viewport(), device: touchScreenDevice).press(touchId: 0, pt: centerPos, window: static_cast<QWindow *>(0));
1716 QTest::touchEvent(widget: view.viewport(), device: touchScreenDevice).release(touchId: 0, pt: centerPos, window: static_cast<QWindow *>(0));
1717 // Touch outside of the button
1718 QTest::touchEvent(widget: view.viewport(), device: touchScreenDevice).press(touchId: 0, pt: view.mapFromScene(point: QPoint(10, 10)), window: static_cast<QWindow *>(0));
1719 QTest::touchEvent(widget: view.viewport(), device: touchScreenDevice).release(touchId: 0, pt: view.mapFromScene(point: QPoint(10, 10)), window: static_cast<QWindow *>(0));
1720}
1721
1722void tst_QTouchEvent::touchBeginWithGraphicsWidget()
1723{
1724 if (QHighDpiScaling::isActive())
1725 QSKIP("Fails when scaling is active");
1726 QGraphicsScene scene;
1727 QGraphicsView view(&scene);
1728 view.setWindowTitle(QTest::currentTestFunction());
1729 QScopedPointer<tst_QTouchEventGraphicsItem> root(new tst_QTouchEventGraphicsItem);
1730 root->setAcceptTouchEvents(true);
1731 scene.addItem(item: root.data());
1732
1733 QScopedPointer<QGraphicsWidget> glassWidget(new QGraphicsWidget);
1734 glassWidget->setMinimumSize(aw: 100, ah: 100);
1735 scene.addItem(item: glassWidget.data());
1736
1737 view.setAlignment(Qt::AlignLeft | Qt::AlignTop);
1738 const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry();
1739 view.resize(availableGeometry.size() - QSize(100, 100));
1740 view.move(availableGeometry.topLeft() + QPoint(50, 50));
1741 view.fitInView(rect: scene.sceneRect());
1742 view.show();
1743 QVERIFY(QTest::qWaitForWindowExposed(&view));
1744
1745 QTest::touchEvent(widget: &view, device: touchScreenDevice)
1746 .press(touchId: 0, pt: view.mapFromScene(point: root->mapToScene(ax: 3,ay: 3)), widget: view.viewport());
1747 QTest::touchEvent(widget: &view, device: touchScreenDevice)
1748 .stationary(touchId: 0)
1749 .press(touchId: 1, pt: view.mapFromScene(point: root->mapToScene(ax: 6,ay: 6)), widget: view.viewport());
1750 QTest::touchEvent(widget: &view, device: touchScreenDevice)
1751 .release(touchId: 0, pt: view.mapFromScene(point: root->mapToScene(ax: 3,ay: 3)), widget: view.viewport())
1752 .release(touchId: 1, pt: view.mapFromScene(point: root->mapToScene(ax: 6,ay: 6)), widget: view.viewport());
1753
1754 QTRY_COMPARE(root->touchBeginCounter, 1);
1755 QCOMPARE(root->touchUpdateCounter, 1);
1756 QCOMPARE(root->touchEndCounter, 1);
1757 QCOMPARE(root->touchUpdatePoints.size(), 2);
1758
1759 root->reset();
1760 glassWidget->setWindowFlags(Qt::Window); // make the glassWidget a panel
1761
1762 QTest::touchEvent(widget: &view, device: touchScreenDevice)
1763 .press(touchId: 0, pt: view.mapFromScene(point: root->mapToScene(ax: 3,ay: 3)), widget: view.viewport());
1764 QTest::touchEvent(widget: &view, device: touchScreenDevice)
1765 .stationary(touchId: 0)
1766 .press(touchId: 1, pt: view.mapFromScene(point: root->mapToScene(ax: 6,ay: 6)), widget: view.viewport());
1767 QTest::touchEvent(widget: &view, device: touchScreenDevice)
1768 .release(touchId: 0, pt: view.mapFromScene(point: root->mapToScene(ax: 3,ay: 3)), widget: view.viewport())
1769 .release(touchId: 1, pt: view.mapFromScene(point: root->mapToScene(ax: 6,ay: 6)), widget: view.viewport());
1770
1771 QCOMPARE(root->touchBeginCounter, 0);
1772 QCOMPARE(root->touchUpdateCounter, 0);
1773 QCOMPARE(root->touchEndCounter, 0);
1774}
1775
1776class WindowTouchEventFilter : public QObject
1777{
1778 Q_OBJECT
1779public:
1780 bool eventFilter(QObject *obj, QEvent *event) override;
1781 struct TouchInfo {
1782 QList<QTouchEvent::TouchPoint> points;
1783 QEvent::Type lastSeenType;
1784 };
1785 QMap<QTouchDevice *, TouchInfo> d;
1786};
1787
1788bool WindowTouchEventFilter::eventFilter(QObject *, QEvent *event)
1789{
1790 if (event->type() == QEvent::TouchBegin
1791 || event->type() == QEvent::TouchUpdate
1792 || event->type() == QEvent::TouchEnd) {
1793 QTouchEvent *te = static_cast<QTouchEvent *>(event);
1794 TouchInfo &td = d[te->device()];
1795 if (event->type() == QEvent::TouchBegin)
1796 td.points.clear();
1797 td.points.append(t: te->touchPoints());
1798 td.lastSeenType = event->type();
1799 }
1800 return false;
1801}
1802
1803void tst_QTouchEvent::testQGuiAppDelivery()
1804{
1805 QWindow w;
1806 w.setGeometry(posx: 100, posy: 100, w: 100, h: 100);
1807 w.show();
1808 QVERIFY(QTest::qWaitForWindowExposed(&w));
1809
1810 WindowTouchEventFilter filter;
1811 w.installEventFilter(filterObj: &filter);
1812
1813 QList<QWindowSystemInterface::TouchPoint> points;
1814
1815 // Pass empty list, should be ignored.
1816 QWindowSystemInterface::handleTouchEvent(window: &w, device: 0, points);
1817 QCoreApplication::processEvents();
1818 QCOMPARE(filter.d.isEmpty(), true);
1819
1820 QWindowSystemInterface::TouchPoint tp;
1821 tp.id = 0;
1822 tp.state = Qt::TouchPointPressed;
1823 tp.area = QRectF(120, 120, 20, 20);
1824 points.append(t: tp);
1825
1826 // Pass 0 as device, should be ignored.
1827 QWindowSystemInterface::handleTouchEvent(window: &w, device: 0, points);
1828 QCoreApplication::processEvents();
1829 QCOMPARE(filter.d.isEmpty(), true);
1830
1831 // Now the real thing.
1832 QWindowSystemInterface::handleTouchEvent(window: &w, device: touchScreenDevice, points); // TouchBegin
1833 QCoreApplication::processEvents();
1834 QCOMPARE(filter.d.count(), 1);
1835 QCOMPARE(filter.d.contains(touchScreenDevice), true);
1836 QCOMPARE(filter.d.value(touchScreenDevice).points.count(), 1);
1837 QCOMPARE(filter.d.value(touchScreenDevice).lastSeenType, QEvent::TouchBegin);
1838
1839 points[0].state = Qt::TouchPointMoved;
1840 QWindowSystemInterface::handleTouchEvent(window: &w, device: touchScreenDevice, points); // TouchUpdate
1841 QCoreApplication::processEvents();
1842 QCOMPARE(filter.d.count(), 1);
1843 QCOMPARE(filter.d.contains(touchScreenDevice), true);
1844 QCOMPARE(filter.d.value(touchScreenDevice).points.count(), 2);
1845 QCOMPARE(filter.d.value(touchScreenDevice).lastSeenType, QEvent::TouchUpdate);
1846
1847 points[0].state = Qt::TouchPointReleased;
1848 QWindowSystemInterface::handleTouchEvent(window: &w, device: touchScreenDevice, points); // TouchEnd
1849 QCoreApplication::processEvents();
1850 QCOMPARE(filter.d.count(), 1);
1851 QCOMPARE(filter.d.contains(touchScreenDevice), true);
1852 QCOMPARE(filter.d.value(touchScreenDevice).points.count(), 3);
1853 QCOMPARE(filter.d.value(touchScreenDevice).lastSeenType, QEvent::TouchEnd);
1854}
1855
1856void tst_QTouchEvent::testMultiDevice()
1857{
1858 QTouchDevice *deviceTwo = QTest::createTouchDevice();
1859
1860 QWindow w;
1861 w.setGeometry(posx: 100, posy: 100, w: 100, h: 100);
1862 w.show();
1863 QVERIFY(QTest::qWaitForWindowExposed(&w));
1864
1865 WindowTouchEventFilter filter;
1866 w.installEventFilter(filterObj: &filter);
1867
1868 QList<QWindowSystemInterface::TouchPoint> pointsOne, pointsTwo;
1869
1870 // touchScreenDevice reports a single point, deviceTwo reports the beginning of a multi-point sequence.
1871 // Even though there is a point with id 0 for both devices, they should be delivered cleanly, independently.
1872 QWindowSystemInterface::TouchPoint tp;
1873 tp.id = 0;
1874 tp.state = Qt::TouchPointPressed;
1875 const QPoint screenOrigin = w.screen()->geometry().topLeft();
1876 const QRectF area0(120, 120, 20, 20);
1877 tp.area = QHighDpi::toNative(value: area0, scaleFactor: QHighDpiScaling::factor(context: &w), origin: screenOrigin);
1878 pointsOne.append(t: tp);
1879
1880 pointsTwo.append(t: tp);
1881 tp.id = 1;
1882 const QRectF area1(140, 140, 20, 20);
1883 tp.area = QHighDpi::toNative(value: area1, scaleFactor: QHighDpiScaling::factor(context: &w), origin: screenOrigin);
1884 pointsTwo.append(t: tp);
1885
1886 QWindowSystemInterface::handleTouchEvent(window: &w, device: touchScreenDevice, points: pointsOne);
1887 QWindowSystemInterface::handleTouchEvent(window: &w, device: deviceTwo, points: pointsTwo);
1888 QCoreApplication::processEvents();
1889
1890 QCOMPARE(filter.d.contains(touchScreenDevice), true);
1891 QCOMPARE(filter.d.contains(deviceTwo), true);
1892
1893 QCOMPARE(filter.d.value(touchScreenDevice).lastSeenType, QEvent::TouchBegin);
1894 QCOMPARE(filter.d.value(deviceTwo).lastSeenType, QEvent::TouchBegin);
1895 QCOMPARE(filter.d.value(touchScreenDevice).points.count(), 1);
1896 QCOMPARE(filter.d.value(deviceTwo).points.count(), 2);
1897
1898 QCOMPARE(filter.d.value(touchScreenDevice).points.at(0).screenPos(), area0.center());
1899 QCOMPARE(filter.d.value(touchScreenDevice).points.at(0).ellipseDiameters(), area0.size());
1900 QCOMPARE(filter.d.value(touchScreenDevice).points.at(0).state(), pointsOne[0].state);
1901
1902 QCOMPARE(filter.d.value(deviceTwo).points.at(0).screenPos(), area0.center());
1903 QCOMPARE(filter.d.value(deviceTwo).points.at(0).ellipseDiameters(), area0.size());
1904 QCOMPARE(filter.d.value(deviceTwo).points.at(0).state(), pointsTwo[0].state);
1905 QCOMPARE(filter.d.value(deviceTwo).points.at(1).screenPos(), area1.center());
1906 QCOMPARE(filter.d.value(deviceTwo).points.at(1).state(), pointsTwo[1].state);
1907}
1908
1909QTEST_MAIN(tst_QTouchEvent)
1910
1911#include "tst_qtouchevent.moc"
1912

source code of qtbase/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp