diff options
author | Morten Johan Sørvig <morten.sorvig@digia.com> | 2013-01-22 12:00:19 +0100 |
---|---|---|
committer | Tor Arne Vestbø <tor.arne.vestbo@digia.com> | 2013-02-27 23:56:06 +0100 |
commit | f2c52d65608d238ad35ca91099a8751e0c37ef52 (patch) | |
tree | 72e9c2a7f6181174fea7562c1f145222cd3dfd46 /src/plugins/platforms/ios | |
parent | 0a9a4e826fc0a3909481f40d77708a86be55a345 (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/ios')
-rw-r--r-- | src/plugins/platforms/ios/qiosintegration.h | 3 | ||||
-rw-r--r-- | src/plugins/platforms/ios/qiosintegration.mm | 11 | ||||
-rw-r--r-- | src/plugins/platforms/ios/qioswindow.h | 9 | ||||
-rw-r--r-- | src/plugins/platforms/ios/qioswindow.mm | 106 |
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) { |