diff --git a/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp b/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp index f02ed9377c..26da0ab8e8 100644 --- a/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp +++ b/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp @@ -24,6 +24,7 @@ public: } void OnTap(m2::PointD const & pt, bool isLong) override {} + void OnForceTap(m2::PointD const & pt) override {} void OnDoubleTap(m2::PointD const & pt) override {} void OnTwoFingersTap() override {} bool OnSingleTouchFiltrate(m2::PointD const & pt, df::TouchEvent::ETouchType type) override { return m_filtrate; } diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index c74d9ca944..4d6b044d9e 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -757,6 +757,12 @@ void FrontendRenderer::OnTap(m2::PointD const & pt, bool isLongTap) m_tapEventInfoFn(pt, isLongTap, isMyPosition, GetVisiblePOI(selectRect)); } +void FrontendRenderer::OnForceTap(m2::PointD const & pt) +{ + // Emulate long tap on force tap. + OnTap(pt, true /* isLongTap */); +} + void FrontendRenderer::OnDoubleTap(m2::PointD const & pt) { m_userEventStream.AddEvent(ScaleEvent(2.0 /* scale factor */, pt, true /* animated */)); diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index cc4b0ec549..9ffedffbca 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -150,6 +150,7 @@ private: void ResolveZoomLevel(ScreenBase const & screen); void OnTap(m2::PointD const & pt, bool isLong) override; + void OnForceTap(m2::PointD const & pt) override; void OnDoubleTap(m2::PointD const & pt) override; void OnTwoFingersTap() override; bool OnSingleTouchFiltrate(m2::PointD const & pt, TouchEvent::ETouchType type) override; diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index e9af4a4682..f2e1c9397e 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -22,6 +22,8 @@ uint64_t const kKineticDelayMs = 500; double const kMaxAnimationTimeSec = 1.5; // in seconds +float const kForceTapThreshold = 0.75; + size_t GetValidTouchesCount(array const & touches) { size_t result = 0; @@ -742,25 +744,32 @@ void UserEventStream::BeginTapDetector() void UserEventStream::DetectShortTap(Touch const & touch) { + if (DetectForceTap(touch)) + return; + uint64_t const ms = m_touchTimer.TimeElapsedAs().count(); if (ms > kDoubleTapPauseMs) { m_state = STATE_EMPTY; if (m_listener) - m_listener->OnTap(touch.m_location, false); + m_listener->OnTap(touch.m_location, false /* isLongTap */); } } void UserEventStream::DetectLongTap(Touch const & touch) { ASSERT_EQUAL(m_state, STATE_TAP_DETECTION, ()); + + if (DetectForceTap(touch)) + return; + uint64_t const ms = m_touchTimer.TimeElapsedAs().count(); if (ms > kLongTouchMs) { TEST_CALL(LONG_TAP_DETECTED); m_state = STATE_EMPTY; if (m_listener) - m_listener->OnTap(touch.m_location, true); + m_listener->OnTap(touch.m_location, true /* isLongTap */); } } @@ -777,6 +786,19 @@ bool UserEventStream::DetectDoubleTap(Touch const & touch) return true; } +bool UserEventStream::DetectForceTap(Touch const & touch) +{ + if (touch.m_force >= kForceTapThreshold) + { + m_state = STATE_EMPTY; + if (m_listener) + m_listener->OnForceTap(touch.m_location); + return true; + } + + return false; +} + void UserEventStream::EndTapDetector(Touch const & touch) { TEST_CALL(SHORT_TAP_DETECTED); diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index 541d84f2b1..eccf82861c 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -25,6 +25,7 @@ struct Touch { m2::PointF m_location = m2::PointF::Zero(); int64_t m_id = -1; // if id == -1 then touch is invalid + float m_force = 0.0; // relative force of touch [0.0 - 1.0] }; struct TouchEvent @@ -204,6 +205,7 @@ public: virtual ~Listener() {} virtual void OnTap(m2::PointD const & pt, bool isLong) = 0; + virtual void OnForceTap(m2::PointD const & pt) = 0; virtual void OnDoubleTap(m2::PointD const & pt) = 0; virtual void OnTwoFingersTap() = 0; virtual bool OnSingleTouchFiltrate(m2::PointD const & pt, TouchEvent::ETouchType type) = 0; @@ -283,6 +285,7 @@ private: void DetectShortTap(Touch const & touch); void DetectLongTap(Touch const & touch); bool DetectDoubleTap(Touch const & touch); + bool DetectForceTap(Touch const & touch); void EndTapDetector(Touch const & touch); void CancelTapDetector(); diff --git a/iphone/Maps/Classes/MapViewController.mm b/iphone/Maps/Classes/MapViewController.mm index 3868c560b9..ef71923be5 100644 --- a/iphone/Maps/Classes/MapViewController.mm +++ b/iphone/Maps/Classes/MapViewController.mm @@ -270,12 +270,16 @@ typedef NS_ENUM(NSUInteger, UserTouchesAction) e.m_type = type; e.m_touches[0].m_id = reinterpret_cast(touch); e.m_touches[0].m_location = m2::PointD(pt.x * scaleFactor, pt.y * scaleFactor); + if ([self hasForceTouch]) + e.m_touches[0].m_force = touch.force / touch.maximumPossibleForce; if (allTouches.count > 1) { UITouch * touch = [allTouches objectAtIndex:1]; CGPoint const pt = [touch locationInView:v]; e.m_touches[1].m_id = reinterpret_cast(touch); e.m_touches[1].m_location = m2::PointD(pt.x * scaleFactor, pt.y * scaleFactor); + if ([self hasForceTouch]) + e.m_touches[1].m_force = touch.force / touch.maximumPossibleForce; } NSArray * toggledTouches = [touches allObjects];