17 #include "TouchGate.h"
19 #include <QCoreApplication>
22 #include <TouchOwnershipEvent.h>
23 #include <TouchRegistry.h>
25 #pragma GCC diagnostic push
26 #pragma GCC diagnostic ignored "-pedantic"
27 #include <private/qquickitem_p.h>
28 #pragma GCC diagnostic pop
31 #include <DebugHelpers.h>
35 bool TouchGate::event(QEvent *e)
37 if (e->type() == TouchOwnershipEvent::touchOwnershipEventType()) {
38 touchOwnershipEvent(static_cast<TouchOwnershipEvent *>(e));
41 return QQuickItem::event(e);
45 void TouchGate::touchEvent(QTouchEvent *event)
48 qDebug() <<
"[TouchGate] got touch event" << qPrintable(touchEventToString(event));
52 const QList<QTouchEvent::TouchPoint> &touchPoints =
event->touchPoints();
54 for (
int i = 0; i < touchPoints.count(); ++i) {
55 const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
57 if (touchPoint.state() == Qt::TouchPointPressed) {
58 Q_ASSERT(!m_touchInfoMap.contains(touchPoint.id()));
59 m_touchInfoMap[touchPoint.id()].ownership = OwnershipRequested;
60 m_touchInfoMap[touchPoint.id()].ended =
false;
61 TouchRegistry::instance()->requestTouchOwnership(touchPoint.id(),
this);
64 goodToGo &= m_touchInfoMap.contains(touchPoint.id())
65 && m_touchInfoMap[touchPoint.id()].ownership == OwnershipGranted;
67 if (touchPoint.state() == Qt::TouchPointReleased && m_touchInfoMap.contains(touchPoint.id())) {
68 m_touchInfoMap[touchPoint.id()].ended =
true;
74 if (m_storedEvents.isEmpty()) {
76 dispatchTouchEventToTarget(event);
81 qDebug(
"[TouchGate] Storing event because thouches %s are still pending ownership.",
82 qPrintable(oldestPendingTouchIdsString()));
84 storeTouchEvent(event);
88 storeTouchEvent(event);
92 void TouchGate::touchOwnershipEvent(TouchOwnershipEvent *event)
97 Q_ASSERT(m_touchInfoMap.contains(event->touchId()));
99 TouchInfo &touchInfo = m_touchInfoMap[
event->touchId()];
101 if (event->gained()) {
103 qDebug() <<
"[TouchGate] Got ownership of touch " <<
event->touchId();
105 touchInfo.ownership = OwnershipGranted;
108 qDebug() <<
"[TouchGate] Lost ownership of touch " <<
event->touchId();
110 m_touchInfoMap.remove(event->touchId());
111 removeTouchFromStoredEvents(event->touchId());
114 dispatchFullyOwnedEvents();
117 bool TouchGate::isTouchPointOwned(
int touchId)
const
119 return m_touchInfoMap[touchId].ownership == OwnershipGranted;
122 void TouchGate::storeTouchEvent(
const QTouchEvent *event)
125 qDebug() <<
"[TouchGate] Storing" << qPrintable(touchEventToString(event));
128 TouchEvent clonedEvent(event);
129 m_storedEvents.append(std::move(clonedEvent));
132 void TouchGate::removeTouchFromStoredEvents(
int touchId)
135 while (i < m_storedEvents.count()) {
136 TouchEvent &
event = m_storedEvents[i];
137 bool removed =
event.removeTouch(touchId);
139 if (removed && event.touchPoints.isEmpty()) {
140 m_storedEvents.removeAt(i);
147 void TouchGate::dispatchFullyOwnedEvents()
149 while (!m_storedEvents.isEmpty() && eventIsFullyOwned(m_storedEvents.first())) {
150 TouchEvent
event = m_storedEvents.takeFirst();
151 dispatchTouchEventToTarget(event);
156 QString TouchGate::oldestPendingTouchIdsString()
158 Q_ASSERT(!m_storedEvents.isEmpty());
162 const auto &touchPoints = m_storedEvents.first().touchPoints;
163 for (
int i = 0; i < touchPoints.count(); ++i) {
164 if (!isTouchPointOwned(touchPoints[i].
id())) {
165 if (!str.isEmpty()) {
168 str.append(QString::number(touchPoints[i].
id()));
176 bool TouchGate::eventIsFullyOwned(
const TouchGate::TouchEvent &event)
const
178 for (
int i = 0; i <
event.touchPoints.count(); ++i) {
179 if (!isTouchPointOwned(event.touchPoints[i].id())) {
187 void TouchGate::setTargetItem(QQuickItem *item)
192 if (item == m_targetItem.data())
196 Q_EMIT targetItemChanged(item);
199 void TouchGate::dispatchTouchEventToTarget(
const TouchEvent &event)
201 dispatchTouchEventToTarget(event.eventType,
210 void TouchGate::dispatchTouchEventToTarget(QTouchEvent* event)
212 dispatchTouchEventToTarget(event->type(),
215 event->touchPoints(),
221 void TouchGate::dispatchTouchEventToTarget(QEvent::Type eventType,
222 QTouchDevice *device,
223 Qt::KeyboardModifiers modifiers,
224 const QList<QTouchEvent::TouchPoint> &touchPoints,
229 removeTouchInfoForEndedTouches(touchPoints);
231 if (m_targetItem.isNull()) {
232 qWarning(
"[TouchGate] Cannot dispatch touch event because target item is null");
236 QQuickItem *targetItem = m_targetItem.data();
238 if (!targetItem->isEnabled() || !targetItem->isVisible()) {
240 qDebug() <<
"[TouchGate] Cannot dispatch touch event to" << targetItem
241 <<
"because it's disabled or invisible.";
247 QList<QTouchEvent::TouchPoint> targetTouchPoints = touchPoints;
248 transformTouchPoints(targetTouchPoints, QQuickItemPrivate::get(targetItem)->windowToItemTransform());
249 QTouchEvent *eventForTargetItem = createQTouchEvent(eventType, device, modifiers, targetTouchPoints,
250 target, window, timestamp);
253 qDebug() <<
"[TouchGate] dispatching" << qPrintable(touchEventToString(eventForTargetItem))
254 <<
"to" << targetItem;
257 QCoreApplication::sendEvent(targetItem, eventForTargetItem);
259 delete eventForTargetItem;
263 void TouchGate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints,
const QTransform &transform)
265 QMatrix4x4 transformMatrix(transform);
266 for (
int i=0; i<touchPoints.count(); i++) {
267 QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
268 touchPoint.setRect(transform.mapRect(touchPoint.sceneRect()));
269 touchPoint.setStartPos(transform.map(touchPoint.startScenePos()));
270 touchPoint.setLastPos(transform.map(touchPoint.lastScenePos()));
271 touchPoint.setVelocity(transformMatrix.mapVector(touchPoint.velocity()).toVector2D());
275 QTouchEvent *TouchGate::createQTouchEvent(QEvent::Type eventType,
276 QTouchDevice *device,
277 Qt::KeyboardModifiers modifiers,
278 const QList<QTouchEvent::TouchPoint> &touchPoints,
283 Qt::TouchPointStates eventStates = 0;
284 for (
int i = 0; i < touchPoints.count(); i++)
285 eventStates |= touchPoints[i].state();
287 switch (eventStates) {
288 case Qt::TouchPointPressed:
289 eventType = QEvent::TouchBegin;
291 case Qt::TouchPointReleased:
292 eventType = QEvent::TouchEnd;
295 eventType = QEvent::TouchUpdate;
299 QTouchEvent *touchEvent =
new QTouchEvent(eventType);
300 touchEvent->setWindow(window);
301 touchEvent->setTarget(target);
302 touchEvent->setDevice(device);
303 touchEvent->setModifiers(modifiers);
304 touchEvent->setTouchPoints(touchPoints);
305 touchEvent->setTouchPointStates(eventStates);
306 touchEvent->setTimestamp(timestamp);
307 touchEvent->accept();
311 void TouchGate::removeTouchInfoForEndedTouches(
const QList<QTouchEvent::TouchPoint> &touchPoints)
313 for (
int i = 0; i < touchPoints.size(); ++i) {\
314 const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
316 if (touchPoint.state() == Qt::TouchPointReleased) {
317 Q_ASSERT(m_touchInfoMap.contains(touchPoint.id()));
318 Q_ASSERT(m_touchInfoMap[touchPoint.id()].ended);
319 Q_ASSERT(m_touchInfoMap[touchPoint.id()].ownership == OwnershipGranted);
320 m_touchInfoMap.remove(touchPoint.id());
325 TouchGate::TouchEvent::TouchEvent(
const QTouchEvent *event)
326 : eventType(event->type())
327 , device(event->device())
328 , modifiers(event->modifiers())
329 , touchPoints(event->touchPoints())
330 , target(event->target())
331 , window(event->window())
332 , timestamp(event->timestamp())
336 bool TouchGate::TouchEvent::removeTouch(
int touchId)
338 bool removed =
false;
339 for (
int i = 0; i < touchPoints.count() && !removed; ++i) {
340 if (touchPoints[i].
id() == touchId) {
341 touchPoints.removeAt(i);