summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
authorMorten Johan Sørvig <morten.sorvig@digia.com>2013-01-22 12:00:19 +0100
committerTor Arne Vestbø <tor.arne.vestbo@digia.com>2013-02-27 23:56:06 +0100
commitf2c52d65608d238ad35ca91099a8751e0c37ef52 (patch)
tree72e9c2a7f6181174fea7562c1f145222cd3dfd46 /src/plugins/platforms
parent0a9a4e826fc0a3909481f40d77708a86be55a345 (diff)
iOS: Implement touch events.
Track touch events during the standard [Began -> Moved -> Ended] event sequence based on the UITouch pointer which stays constant. Enable multiTouch on Qt's UIView. Mouse events should now be automatically created from (unhanded) touch events by QGuiApplication. Reviewed by: Ada Sørvig (fingerpaint app approved) Change-Id: I2aeb48c962c697d8b8337f8ceab062070c2a4240 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@digia.com>
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/ios/qiosintegration.h3
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm11
-rw-r--r--src/plugins/platforms/ios/qioswindow.h9
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm106
4 files changed, 118 insertions, 11 deletions
diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h
index 5ba97bff6e..054933ea44 100644
--- a/src/plugins/platforms/ios/qiosintegration.h
+++ b/src/plugins/platforms/ios/qiosintegration.h
@@ -44,6 +44,7 @@
#include <qpa/qplatformintegration.h>
#include <qpa/qplatformnativeinterface.h>
+#include <qpa/qwindowsysteminterface.h>
QT_BEGIN_NAMESPACE
@@ -71,10 +72,12 @@ public:
void *nativeResourceForWindow(const QByteArray &resource, QWindow *window);
+ QTouchDevice *touchDevice();
private:
QPlatformFontDatabase *m_fontDatabase;
QPlatformInputContext *m_inputContext;
QPlatformScreen *m_screen;
+ QTouchDevice *m_touchDevice;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index 8008c5c0b0..cbe2717c34 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -72,10 +72,16 @@ QIOSIntegration::QIOSIntegration()
}
screenAdded(m_screen);
+
+ m_touchDevice = new QTouchDevice;
+ m_touchDevice->setType(QTouchDevice::TouchScreen);
+ m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::NormalizedPosition);
+ QWindowSystemInterface::registerTouchDevice(m_touchDevice);
}
QIOSIntegration::~QIOSIntegration()
{
+ delete m_touchDevice;
}
QPlatformWindow *QIOSIntegration::createPlatformWindow(QWindow *window) const
@@ -157,4 +163,9 @@ void *QIOSIntegration::nativeResourceForWindow(const QByteArray &resource, QWind
return 0;
}
+QTouchDevice *QIOSIntegration::touchDevice()
+{
+ return m_touchDevice;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h
index 01c1978a56..b3a94a8d0e 100644
--- a/src/plugins/platforms/ios/qioswindow.h
+++ b/src/plugins/platforms/ios/qioswindow.h
@@ -43,6 +43,7 @@
#define QIOSWINDOW_H
#include <qpa/qplatformwindow.h>
+#include <qpa/qwindowsysteminterface.h>
#import <UIKit/UIKit.h>
@@ -77,8 +78,16 @@ public:
UIView *nativeView() const { return 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;
qreal m_devicePixelRatio;
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index c5d9cbe323..91e75bc660 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -46,6 +46,7 @@
#include "qiosscreen.h"
#include "qiosapplicationdelegate.h"
#include "qiosviewcontroller.h"
+#include "qiosintegration.h"
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
@@ -115,6 +116,8 @@
if (isQtApplication())
self.hidden = YES;
+
+ self.multipleTouchEnabled = YES;
}
return self;
@@ -142,39 +145,119 @@
[super layoutSubviews];
}
-- (void)sendMouseEventForTouches:(NSSet *)touches withEvent:(UIEvent *)event fakeButtons:(Qt::MouseButtons)buttons
+/*
+ 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
{
- UITouch *touch = [touches anyObject];
- CGPoint locationInView = [touch locationInView:self];
- QPoint p(locationInView.x , locationInView.y);
+ 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
+ CGPoint location = [touch locationInView:self];
+ touchPoint.area = QRectF(location.x, location.y, 0, 0);
+ QSize viewSize = fromCGRect(self.frame).size();
+ touchPoint.normalPosition = QPointF(location.x / viewSize.width(), location.y / viewSize.height());
+ }
+}
- // TODO handle global touch point? for status bar?
- QWindowSystemInterface::handleMouseEvent(m_qioswindow->window(), (ulong)(event.timestamp*1000), p, p, buttons);
+- (void) sendTouchEventWithTimestamp:(ulong)timeStamp
+{
+ // Send touch event synchronously
+ QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ QWindowSystemInterface::handleTouchEvent(m_qioswindow->window(), timeStamp,
+ iosIntegration->touchDevice(), m_qioswindow->touchPoints());
+ QWindowSystemInterface::flushWindowSystemEvents();
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
- // Transfer focus to the touched window:
QWindow *window = m_qioswindow->window();
+
+ // Transfer focus to the touched window:
if (window != QGuiApplication::focusWindow())
m_qioswindow->requestActivateWindow();
- [self sendMouseEventForTouches:touches withEvent:event fakeButtons:Qt::LeftButton];
+ // 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);
+ }
+
+ [self updateTouchList:touches withState:Qt::TouchPointPressed];
+ [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
- [self sendMouseEventForTouches:touches withEvent:event fakeButtons:Qt::LeftButton];
+ [self updateTouchList:touches withState:Qt::TouchPointMoved];
+ [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
- [self sendMouseEventForTouches:touches withEvent:event fakeButtons:Qt::NoButton];
+ [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;
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
- [self sendMouseEventForTouches:touches withEvent:event fakeButtons:Qt::NoButton];
+ Q_UNUSED(touches) // ### can a subset of the active touches be cancelled?
+
+ // Clear current touch points
+ m_qioswindow->activeTouches().clear();
+ m_qioswindow->touchId() = 0;
+
+ // Send cancel touch event synchronously
+ QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ QWindowSystemInterface::handleTouchCancelEvent(m_qioswindow->window(), ulong(event.timestamp * 1000), iosIntegration->touchDevice());
+ QWindowSystemInterface::flushWindowSystemEvents();
}
@synthesize autocapitalizationType;
@@ -236,6 +319,7 @@ QT_BEGIN_NAMESPACE
QIOSWindow::QIOSWindow(QWindow *window)
: QPlatformWindow(window)
, m_view([[EAGLView alloc] initWithQIOSWindow:this])
+ , m_touchId(0)
, m_requestedGeometry(QPlatformWindow::geometry())
, m_devicePixelRatio(1.0)
{