From c4f08c09359cd01763f02f5a18e640428cda4f53 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Mon, 15 Aug 2022 15:55:48 +0200 Subject: [PATCH] iOS: use NSProcessInfo to resolve timestamps in simulator builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently build Qt for simulator using X86_64, even on ARM based macs. This results in the simulator running on ARM, while the app is running inside it using Rosetta. And with this combination, the event.timestamp, which is documented to be in seconds, looks to be something else, and is not progressing in sync with a normal clock. Sending out mouse events with a timestamp that doesn't follow normal clock time will cause problems for mouse-, and pointer handlers that uses them to e.g calculate the time between a press and release, and to decide if the user is performing a tap or a drag. For that reason, we choose to ignore UIEvent.timestamp under the mentioned condition, and instead rely on NSProcessInfo. Note that if we force the whole simulator to use Rosetta (and not only the Qt app), the timestamps will progress normally. Fixes: QTBUG-105810 Change-Id: Ib4e60593cac3230567ebc53d634f434fcefc98d0 Reviewed-by: Tor Arne Vestbø (cherry picked from commit 0250f9364fbf31950601bf27c2a93c520c4abd80) Reviewed-by: Qt Cherry-pick Bot --- src/plugins/platforms/ios/quiview.mm | 36 ++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index 0752f70efe2..c976c8a276e 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -23,6 +23,32 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") +namespace { +inline ulong getTimeStamp(UIEvent *event) +{ +#if TARGET_OS_SIMULATOR == 1 + // We currently build Qt for simulator using X86_64, even on ARM based macs. + // This results in the simulator running on ARM, while the app is running + // inside it using Rosetta. And with this combination, the event.timestamp, which is + // documented to be in seconds, looks to be something else, and is not progressing + // in sync with a normal clock. + // Sending out mouse events with a timestamp that doesn't follow normal clock time + // will cause problems for mouse-, and pointer handlers that uses them to e.g calculate + // the time between a press and release, and to decide if the user is performing a tap + // or a drag. + // For that reason, we choose to ignore UIEvent.timestamp under the mentioned condition, and + // instead rely on NSProcessInfo. Note that if we force the whole simulator to use Rosetta + // (and not only the Qt app), the timestamps will progress normally. +#if defined(Q_PROCESSOR_ARM) + #warning The timestamp work-around for x86_64 can (probably) be removed when building for ARM +#endif + return ulong(NSProcessInfo.processInfo.systemUptime * 1000); +#endif + + return ulong(event.timestamp * 1000); +} +} + @implementation QUIView { QHash m_activeTouches; UITouch *m_activePencilTouch; @@ -470,17 +496,17 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") topLevel->requestActivateWindow(); } - [self handleTouches:touches withEvent:event withState:QEventPoint::State::Pressed withTimestamp:ulong(event.timestamp * 1000)]; + [self handleTouches:touches withEvent:event withState:QEventPoint::State::Pressed withTimestamp:getTimeStamp(event)]; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - [self handleTouches:touches withEvent:event withState:QEventPoint::State::Updated withTimestamp:ulong(event.timestamp * 1000)]; + [self handleTouches:touches withEvent:event withState:QEventPoint::State::Updated withTimestamp:getTimeStamp(event)]; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - [self handleTouches:touches withEvent:event withState:QEventPoint::State::Released withTimestamp:ulong(event.timestamp * 1000)]; + [self handleTouches:touches withEvent:event withState:QEventPoint::State::Released withTimestamp:getTimeStamp(event)]; // Remove ended touch points from the active set: #ifndef Q_OS_TVOS @@ -536,7 +562,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") m_nextTouchId = 0; m_activePencilTouch = nil; - NSTimeInterval timestamp = event ? event.timestamp : [[NSProcessInfo processInfo] systemUptime]; + ulong timestamp = event ? getTimeStamp(event) : ([[NSProcessInfo processInfo] systemUptime] * 1000); QIOSIntegration *iosIntegration = static_cast(QGuiApplicationPrivate::platformIntegration()); @@ -544,7 +570,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") // event loop in response to the touch event (a dialog e.g.), which will deadlock // the UIKit event delivery system (QTBUG-98651). QWindowSystemInterface::handleTouchCancelEvent( - self.platformWindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice()); + self.platformWindow->window(), timestamp, iosIntegration->touchDevice()); } - (int)mapPressTypeToKey:(UIPress*)press withModifiers:(Qt::KeyboardModifiers)qtModifiers text:(QString &)text