summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@digia.com>2013-04-24 13:05:37 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-05-07 22:43:14 +0200
commit758f064558f26eb32a74d4bf426ee443fe6e8f4b (patch)
tree26cc2c6951c5c82402d22492a93fb24b8639b146
parent53e01c4329ffbe4491ef7ef07662624f416f4a50 (diff)
iOS: don't send ended touch events to QPA
The current implementation kept a list of TouchPoints that was reused when sending active touces to QPA. This list was never cleaned up, so if you pressed three fingers, and released one, we would still continue to sendt three touches to QPA. Especially, since this list was not cleaned up when receiving a touch cancel, mouse events sometimes stopped working when trigging a system gesture (like a four finger swipe). This can be seen by using the fingerpaint example. Since we cannot rely on TouchPoints having IDs that corresponds to their index in the touch point list, it ends up being simpler (and results in less code) to rewrite the implementation to use a hash table of UITouch to TouchPoints instead. Change-Id: I5b32f57a8d72a0b8759a64ac7cdfa6700109d2b3 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@digia.com>
-rw-r--r--src/plugins/platforms/ios/qioswindow.h7
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm103
2 files changed, 35 insertions, 75 deletions
diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h
index b86dbf7d46..20f0aa59b6 100644
--- a/src/plugins/platforms/ios/qioswindow.h
+++ b/src/plugins/platforms/ios/qioswindow.h
@@ -82,15 +82,8 @@ public:
WId winId() const { return WId(m_view); };
- QList<QWindowSystemInterface::TouchPoint> &touchPoints() { return m_touchPoints; }
- QHash<UITouch *, int> &activeTouches() { return m_activeTouches; }
- int &touchId() { return m_touchId; }
-
private:
UIView *m_view;
- QList<QWindowSystemInterface::TouchPoint> m_touchPoints;
- QHash<UITouch *, int> m_activeTouches;
- int m_touchId;
QRect m_requestedGeometry;
int m_windowLevel;
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index b173fb786f..cd2e5f9cb9 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -68,6 +68,8 @@
UIReturnKeyType returnKeyType;
BOOL secureTextEntry;
QIOSWindow *m_qioswindow;
+ QHash<UITouch *, QWindowSystemInterface::TouchPoint> m_activeTouches;
+ int m_nextTouchId;
}
@property(nonatomic) UITextAutocapitalizationType autocapitalizationType;
@@ -113,6 +115,7 @@
keyboardType = UIKeyboardTypeDefault;
returnKeyType = UIReturnKeyDone;
secureTextEntry = NO;
+ m_nextTouchId = 0;
if (isQtApplication())
self.hidden = YES;
@@ -145,45 +148,25 @@
[super layoutSubviews];
}
-/*
- Touch handling:
-
- UIKit generates [Began -> Moved -> Ended] event sequences for
- each touch point. The iOS plugin tracks each individual
- touch and assigns it an id for use by Qt. The id counter is
- incremented on each began and decrement as follows:
- 1) by one when the most recent touch ends.
- 2) to zero when all touches ends.
-
- The TouchPoint list is reused between events.
-*/
- (void)updateTouchList:(NSSet *)touches withState:(Qt::TouchPointState)state
{
- QList<QWindowSystemInterface::TouchPoint> &touchPoints = m_qioswindow->touchPoints();
- QHash<UITouch *, int> &activeTouches = m_qioswindow->activeTouches();
-
- // Mark all touch points as stationary
- for (QList<QWindowSystemInterface::TouchPoint>::iterator it = touchPoints.begin(); it != touchPoints.end(); ++it)
- it->state = Qt::TouchPointStationary;
-
- // Update changed touch points with the new state
- for (UITouch *touch in touches) {
- const int touchId = activeTouches.value(touch);
- QWindowSystemInterface::TouchPoint &touchPoint = touchPoints[touchId];
- touchPoint.state = state;
- if (state == Qt::TouchPointPressed)
- touchPoint.pressure = 1.0;
- else if (state == Qt::TouchPointReleased)
- touchPoint.pressure = 0.0;
-
- // Set position
- QRect viewGeometry = fromCGRect(self.frame);
- QPoint touchViewLocation = fromCGPoint([touch locationInView:self]);
- QPoint touchScreenLocation = touchViewLocation + viewGeometry.topLeft();
- touchPoint.area = QRectF(touchScreenLocation , QSize(0, 0));
-
- CGSize fullscreenSize = self.window.rootViewController.view.bounds.size;
- touchPoint.normalPosition = QPointF(touchScreenLocation.x() / fullscreenSize.width, touchScreenLocation.y() / fullscreenSize.height);
+ foreach (UITouch *uiTouch, m_activeTouches.keys()) {
+ QWindowSystemInterface::TouchPoint &touchPoint = m_activeTouches[uiTouch];
+ if (![touches containsObject:uiTouch]) {
+ touchPoint.state = Qt::TouchPointStationary;
+ } else {
+ touchPoint.state = state;
+ touchPoint.pressure = (state == Qt::TouchPointReleased) ? 0.0 : 1.0;
+
+ // Set position
+ QRect viewGeometry = fromCGRect(self.frame);
+ QPoint touchViewLocation = fromCGPoint([uiTouch locationInView:self]);
+ QPoint touchScreenLocation = touchViewLocation + viewGeometry.topLeft();
+ touchPoint.area = QRectF(touchScreenLocation , QSize(0, 0));
+
+ CGSize fullscreenSize = self.window.rootViewController.view.bounds.size;
+ touchPoint.normalPosition = QPointF(touchScreenLocation.x() / fullscreenSize.width, touchScreenLocation.y() / fullscreenSize.height);
+ }
}
}
@@ -191,8 +174,7 @@
{
// Send touch event synchronously
QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration());
- QWindowSystemInterface::handleTouchEvent(m_qioswindow->window(), timeStamp,
- iosIntegration->touchDevice(), m_qioswindow->touchPoints());
+ QWindowSystemInterface::handleTouchEvent(m_qioswindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values());
QWindowSystemInterface::flushWindowSystemEvents();
}
@@ -204,19 +186,13 @@
if (window != QGuiApplication::focusWindow())
m_qioswindow->requestActivateWindow();
- // Track Cocoa touch id to Qt touch id. The UITouch pointer is constant
- // for the touch duration.
- QHash<UITouch *, int> &activeTouches = m_qioswindow->activeTouches();
- QList<QWindowSystemInterface::TouchPoint> &touchPoints = m_qioswindow->touchPoints();
- for (UITouch *touch in touches)
- activeTouches.insert(touch, m_qioswindow->touchId()++);
-
- // Create new touch points if needed.
- int newTouchPointsNeeded = m_qioswindow->touchId() - touchPoints.count();
- for (int i = 0; i < newTouchPointsNeeded; ++i) {
- QWindowSystemInterface::TouchPoint touchPoint;
- touchPoint.id = touchPoints.count(); // id is the index in the touchPoints list.
- touchPoints.append(touchPoint);
+ // UIKit generates [Began -> Moved -> Ended] event sequences for
+ // each touch point. Internally we keep a hashmap of active UITouch
+ // points to QWindowSystemInterface::TouchPoints, and assigns each TouchPoint
+ // an id for use by Qt.
+ for (UITouch *touch in touches) {
+ Q_ASSERT(!m_activeTouches.contains(touch));
+ m_activeTouches[touch].id = m_nextTouchId++;
}
[self updateTouchList:touches withState:Qt::TouchPointPressed];
@@ -234,19 +210,11 @@
[self updateTouchList:touches withState:Qt::TouchPointReleased];
[self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)];
- // Remove ended touch points from the active set (event processing has completed at this point)
- QHash<UITouch *, int> &activeTouches = m_qioswindow->activeTouches();
- for (UITouch *touch in touches) {
- int id = activeTouches.take(touch);
-
- // If this touch is the most recent touch we can reuse its id
- if (id == m_qioswindow->touchId() - 1)
- --m_qioswindow->touchId();
- }
-
- // Reset the touch id when there are no more active touches
- if (activeTouches.isEmpty())
- m_qioswindow->touchId() = 0;
+ // Remove ended touch points from the active set:
+ for (UITouch *touch in touches)
+ m_activeTouches.remove(touch);
+ if (m_activeTouches.isEmpty())
+ m_nextTouchId = 0;
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
@@ -254,8 +222,8 @@
Q_UNUSED(touches) // ### can a subset of the active touches be cancelled?
// Clear current touch points
- m_qioswindow->activeTouches().clear();
- m_qioswindow->touchId() = 0;
+ m_activeTouches.clear();
+ m_nextTouchId = 0;
// Send cancel touch event synchronously
QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration());
@@ -322,7 +290,6 @@ QT_BEGIN_NAMESPACE
QIOSWindow::QIOSWindow(QWindow *window)
: QPlatformWindow(window)
, m_view([[EAGLView alloc] initWithQIOSWindow:this])
- , m_touchId(0)
, m_requestedGeometry(QPlatformWindow::geometry())
, m_windowLevel(0)
, m_devicePixelRatio(1.0)