19#include <QCoreApplication>
21#include <QQuickWindow>
23#include <LomiriGestures/private/touchownershipevent_p.h>
24#include <LomiriGestures/private/touchregistry_p.h>
27#define ugDebug(params) qDebug().nospace() << "[TouchGate(" << (void*)this << ")] " << params
28#include <LomiriGestures/private/debughelpers_p.h>
30#define ugDebug(params) ((void)0)
35TouchGate::TouchGate(QQuickItem *parent)
38 connect(
this, &QQuickItem::enabledChanged,
39 this, &TouchGate::onEnabledChanged);
42bool TouchGate::event(QEvent *e)
44 if (e->type() == TouchOwnershipEvent::touchOwnershipEventType()) {
45 touchOwnershipEvent(
static_cast<TouchOwnershipEvent*
>(e));
48 return QQuickItem::event(e);
52void TouchGate::touchEvent(QTouchEvent *event)
54 ugDebug(
"got touch event" << qPrintable(touchEventToString(event)));
57 const QList<QTouchEvent::TouchPoint> &touchPoints =
event->touchPoints();
58 QList<QTouchEvent::TouchPoint> validTouchPoints;
59 bool ownsAllTouches =
true;
60 for (
int i = 0; i < touchPoints.count(); ++i) {
61 const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
63 if (touchPoint.state() == Qt::TouchPointPressed) {
68 m_touchInfoMap[touchPoint.id()].ownership = OwnershipRequested;
69 m_touchInfoMap[touchPoint.id()].ended =
false;
70 TouchRegistry::instance()->requestTouchOwnership(touchPoint.id(),
this);
73 if (m_touchInfoMap.contains(touchPoint.id())) {
74 validTouchPoints.append(touchPoint);
76 ownsAllTouches &= m_touchInfoMap[touchPoint.id()].ownership == OwnershipGranted;
78 if (touchPoint.state() == Qt::TouchPointReleased) {
79 m_touchInfoMap[touchPoint.id()].ended =
true;
85 if (validTouchPoints.isEmpty()) {
91 if (m_storedEvents.isEmpty()) {
93 removeTouchInfoForEndedTouches(validTouchPoints);
94 m_dispatcher.dispatch(event->device(), event->modifiers(), validTouchPoints,
95 event->window(), event->timestamp());
99 ugDebug(
"Storing event because thouches " << qPrintable(oldestPendingTouchIdsString())
100 <<
" are still pending ownership.");
101 storeTouchEvent(event->device(), event->modifiers(), validTouchPoints,
102 event->window(), event->timestamp());
106 storeTouchEvent(event->device(), event->modifiers(), validTouchPoints,
107 event->window(), event->timestamp());
111void TouchGate::itemChange(ItemChange change,
const ItemChangeData &value)
113 if (change == QQuickItem::ItemSceneChange) {
114 if (value.window !=
nullptr) {
115 value.window->installEventFilter(TouchRegistry::instance());
120void TouchGate::touchOwnershipEvent(TouchOwnershipEvent *event)
125 if (m_touchInfoMap.contains(event->touchId())) {
126 TouchInfo &touchInfo = m_touchInfoMap[
event->touchId()];
128 if (event->gained()) {
129 ugDebug(
"Got ownership of touch " << event->touchId());
130 touchInfo.ownership = OwnershipGranted;
132 ugDebug(
"Lost ownership of touch " << event->touchId());
133 m_touchInfoMap.remove(event->touchId());
134 removeTouchFromStoredEvents(event->touchId());
137 dispatchFullyOwnedEvents();
144bool TouchGate::isTouchPointOwned(
int touchId)
const
146 return m_touchInfoMap[touchId].ownership == OwnershipGranted;
149void TouchGate::storeTouchEvent(QTouchDevice *device,
150 Qt::KeyboardModifiers modifiers,
151 const QList<QTouchEvent::TouchPoint> &touchPoints,
155 ugDebug(
"Storing" << touchPoints);
156 TouchEvent event(device, modifiers, touchPoints, window, timestamp);
157 m_storedEvents.append(std::move(event));
160void TouchGate::removeTouchFromStoredEvents(
int touchId)
163 while (i < m_storedEvents.count()) {
164 TouchEvent &
event = m_storedEvents[i];
165 bool removed =
event.removeTouch(touchId);
167 if (removed && event.touchPoints.isEmpty()) {
168 m_storedEvents.removeAt(i);
175void TouchGate::dispatchFullyOwnedEvents()
177 while (!m_storedEvents.isEmpty() && eventIsFullyOwned(m_storedEvents.first())) {
178 TouchEvent
event = m_storedEvents.takeFirst();
179 dispatchTouchEventToTarget(event);
184QString TouchGate::oldestPendingTouchIdsString()
186 Q_ASSERT(!m_storedEvents.isEmpty());
190 const auto &touchPoints = m_storedEvents.first().touchPoints;
191 for (
int i = 0; i < touchPoints.count(); ++i) {
192 if (!isTouchPointOwned(touchPoints[i].
id())) {
193 if (!str.isEmpty()) {
196 str.append(QString::number(touchPoints[i].
id()));
204bool TouchGate::eventIsFullyOwned(
const TouchGate::TouchEvent &event)
const
206 for (
int i = 0; i <
event.touchPoints.count(); ++i) {
207 if (!isTouchPointOwned(event.touchPoints[i].id())) {
215void TouchGate::setTargetItem(QQuickItem *item)
220 if (item == m_dispatcher.targetItem())
223 m_dispatcher.setTargetItem(item);
224 Q_EMIT targetItemChanged(item);
227void TouchGate::dispatchTouchEventToTarget(
const TouchEvent &event)
229 removeTouchInfoForEndedTouches(event.touchPoints);
230 m_dispatcher.dispatch(event.device,
237void TouchGate::removeTouchInfoForEndedTouches(
const QList<QTouchEvent::TouchPoint> &touchPoints)
239 for (
int i = 0; i < touchPoints.size(); ++i) {\
240 const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
242 if (touchPoint.state() == Qt::TouchPointReleased) {
243 Q_ASSERT(m_touchInfoMap.contains(touchPoint.id()));
244 Q_ASSERT(m_touchInfoMap[touchPoint.id()].ended);
245 Q_ASSERT(m_touchInfoMap[touchPoint.id()].ownership == OwnershipGranted);
246 m_touchInfoMap.remove(touchPoint.id());
251void TouchGate::onEnabledChanged()
253 ugDebug(
" enabled = " << isEnabled());
259void TouchGate::reset()
261 m_storedEvents.clear();
262 m_touchInfoMap.clear();
263 m_dispatcher.reset();
266TouchGate::TouchEvent::TouchEvent(QTouchDevice *device,
267 Qt::KeyboardModifiers modifiers,
268 const QList<QTouchEvent::TouchPoint> &touchPoints,
272 , modifiers(modifiers)
273 , touchPoints(touchPoints)
275 , timestamp(timestamp)
279bool TouchGate::TouchEvent::removeTouch(
int touchId)
281 bool removed =
false;
282 for (
int i = 0; i < touchPoints.count() && !removed; ++i) {
283 if (touchPoints[i].
id() == touchId) {
284 touchPoints.removeAt(i);