2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/integration-api/events/touch-event-combiner.h>
25 #include <dali/integration-api/events/touch-event-integ.h>
26 #include <dali/integration-api/events/hover-event-integ.h>
27 #include <dali/public-api/common/dali-common.h>
37 const unsigned long DEFAULT_MINIMUM_MOTION_TIME( 1u );
38 const Vector2 DEFAULT_MINIMUM_MOTION_DISTANCE( 1.0f, 1.0f );
39 } // unnamed namespace
41 struct TouchEventCombiner::PointInfo
47 * @param[in] touchPoint The point to add.
48 * @param[in] pointTime The time of the point event.
50 PointInfo( const TouchPoint& touchPoint, unsigned long pointTime )
51 : point( touchPoint ),
58 TouchPoint point; ///< The point.
59 unsigned long time; ///< The time the point event took place.
62 TouchEventCombiner::TouchEventCombiner()
63 : mMinMotionTime( DEFAULT_MINIMUM_MOTION_TIME ),
64 mMinMotionDistance( DEFAULT_MINIMUM_MOTION_DISTANCE )
68 TouchEventCombiner::TouchEventCombiner( unsigned long minMotionTime, float minMotionXDistance, float minMotionYDistance )
69 : mMinMotionTime( minMotionTime ),
70 mMinMotionDistance( minMotionXDistance, minMotionYDistance )
72 DALI_ASSERT_ALWAYS( minMotionXDistance >= 0.0f && minMotionYDistance >= 0.0f && "Negative values not allowed\n" );
75 TouchEventCombiner::TouchEventCombiner( unsigned long minMotionTime, Vector2 minMotionDistance )
76 : mMinMotionTime( minMotionTime ),
77 mMinMotionDistance( minMotionDistance )
79 DALI_ASSERT_ALWAYS( minMotionDistance.x >= 0.0f && minMotionDistance.y >= 0.0f && "Negative values not allowed\n" );
82 TouchEventCombiner::~TouchEventCombiner()
86 TouchEventCombiner::EventDispatchType TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned long time, TouchEvent& touchEvent, HoverEvent& hoverEvent )
88 TouchEventCombiner::EventDispatchType dispatchEvent( TouchEventCombiner::DispatchNone );
90 switch ( point.state )
92 case TouchPoint::Started:
94 touchEvent.time = time;
95 bool addToContainer( true );
97 // Iterate through already stored touch points and add to TouchEvent
98 for ( PointInfoContainer::iterator iter = mPressedPoints.begin(), endIter = mPressedPoints.end(); iter != endIter; ++iter )
100 if ( iter->point.deviceId != point.deviceId )
102 iter->point.state = TouchPoint::Stationary;
106 // System has sent us two down points for the same point ID, update our stored data to latest.
107 // We do not want to emit another down event for this Point Device ID.
109 addToContainer = false;
113 touchEvent.AddPoint( iter->point );
116 // Add new touch point to the list and to the TouchEvent
119 mPressedPoints.push_back( PointInfo( point, time ) );
120 touchEvent.AddPoint( point );
121 dispatchEvent = TouchEventCombiner::DispatchTouch; // Only dispatch touch event if just added to container
123 // Check whether hover event was dispatched previously
124 if ( !mHoveredPoints.empty() )
126 hoverEvent.time = time;
128 PointInfoContainer::iterator match( mHoveredPoints.end() );
129 for ( PointInfoContainer::iterator iter = mHoveredPoints.begin(), endIter = mHoveredPoints.end(); iter != endIter; ++iter )
131 if ( point.deviceId == iter->point.deviceId )
134 // Add new point to the HoverEvent
135 iter->point.state = TouchPoint::Finished;
136 hoverEvent.AddPoint( iter->point );
140 iter->point.state = TouchPoint::Stationary;
141 hoverEvent.AddPoint( iter->point );
145 if ( match != mHoveredPoints.end() )
147 mHoveredPoints.erase( match );
148 dispatchEvent = TouchEventCombiner::DispatchBoth; // We should only dispatch hover events if the point was actually hovered in this window
156 case TouchPoint::Finished:
158 touchEvent.time = time;
160 // Find pressed touch point in local list (while also adding the stored points to the touchEvent)
161 PointInfoContainer::iterator match( mPressedPoints.end() );
162 for ( PointInfoContainer::iterator iter = mPressedPoints.begin(), endIter = mPressedPoints.end(); iter != endIter; ++iter )
164 if ( point.deviceId == iter->point.deviceId )
168 // Add new point to the TouchEvent
169 touchEvent.AddPoint( point );
173 iter->point.state = TouchPoint::Stationary;
174 touchEvent.AddPoint( iter->point );
178 if ( match != mPressedPoints.end() )
180 mPressedPoints.erase( match );
181 dispatchEvent = TouchEventCombiner::DispatchTouch; // We should only dispatch touch events if the point was actually pressed in this window
183 // Iterate through already stored touch points for HoverEvent and delete them
184 for ( PointInfoContainer::iterator iter = mHoveredPoints.begin(), endIter = mHoveredPoints.end(); iter != endIter; ++iter )
186 if ( iter->point.deviceId == point.deviceId )
188 iter = mHoveredPoints.erase( iter );
195 case TouchPoint::Motion:
197 bool fromNewDeviceId = false;
199 if ( !mPressedPoints.empty() )
201 touchEvent.time = time;
204 PointInfoContainer::iterator match = mPressedPoints.end();
205 for ( PointInfoContainer::iterator iter = mPressedPoints.begin(), endIter = mPressedPoints.end(); iter != endIter; ++iter )
207 if ( point.deviceId == iter->point.deviceId )
209 unsigned long timeDiff( time - iter->time );
211 if ( timeDiff < mMinMotionTime )
213 // Motion event sent too soon after previous event so ignore
218 if ( ( abs( point.screen.x - iter->point.screen.x ) < mMinMotionDistance.x ) &&
219 ( abs( point.screen.y - iter->point.screen.y ) < mMinMotionDistance.y ) )
221 // Not enough positional change from last event so ignore
228 // Add new touch point to the TouchEvent
229 touchEvent.AddPoint( point );
233 iter->point.state = TouchPoint::Stationary;
234 touchEvent.AddPoint( iter->point );
238 if ( match != mPressedPoints.end() )
240 PointInfo matchedPoint( point, time );
241 std::swap( *match, matchedPoint );
243 dispatchEvent = TouchEventCombiner::DispatchTouch; // Dispatch touch event
247 fromNewDeviceId = true;
251 // Dispatch hover event if no previous down event received or the motion event comes from a new device ID
252 if(mPressedPoints.empty() || fromNewDeviceId)
254 hoverEvent.time = time;
256 // Iterate through already stored touch points and add to HoverEvent
258 PointInfoContainer::iterator match = mHoveredPoints.end();
259 for ( PointInfoContainer::iterator iter = mHoveredPoints.begin(), endIter = mHoveredPoints.end(); iter != endIter; ++iter )
261 if ( iter->point.deviceId == point.deviceId )
263 unsigned long timeDiff( time - iter->time );
265 if ( timeDiff < mMinMotionTime )
267 // Motion event sent too soon after previous event so ignore
272 if ( ( abs( point.screen.x - iter->point.screen.x ) < mMinMotionDistance.x ) &&
273 ( abs( point.screen.y - iter->point.screen.y ) < mMinMotionDistance.y ) )
275 // Not enough positional change from last event so ignore
282 // Add new touch point to the HoverEvent
283 hoverEvent.AddPoint( point );
287 iter->point.state = TouchPoint::Stationary;
288 hoverEvent.AddPoint( iter->point );
292 // Add new hover point to the list and to the HoverEvent
293 if ( !ignore ) // Only dispatch hover event when it should not be ignored
295 if( match == mHoveredPoints.end() )
297 TouchPoint hoverPoint(point);
298 hoverPoint.state = TouchPoint::Started; // The first hover event received
299 mHoveredPoints.push_back( PointInfo( hoverPoint, time ) );
300 hoverEvent.AddPoint( hoverPoint );
304 PointInfo matchedPoint( point, time );
305 std::swap( *match, matchedPoint );
308 if(dispatchEvent == TouchEventCombiner::DispatchTouch)
310 dispatchEvent = TouchEventCombiner::DispatchBoth;
314 dispatchEvent = TouchEventCombiner::DispatchHover;
321 case TouchPoint::Interrupted:
325 // We should still tell core about the interruption.
326 touchEvent.AddPoint( point );
327 hoverEvent.AddPoint( point );
328 dispatchEvent = TouchEventCombiner::DispatchBoth;
336 return dispatchEvent;
339 void TouchEventCombiner::SetMinimumMotionTimeThreshold( unsigned long minTime )
341 mMinMotionTime = minTime;
344 void TouchEventCombiner::SetMinimumMotionDistanceThreshold( float minDistance )
346 DALI_ASSERT_ALWAYS( minDistance >= 0.0f && "Negative values not allowed\n" );
348 mMinMotionDistance.x = mMinMotionDistance.y = minDistance;
351 void TouchEventCombiner::SetMinimumMotionDistanceThreshold( float minXDistance, float minYDistance )
353 DALI_ASSERT_ALWAYS( minXDistance >= 0.0f && minYDistance >= 0.0f && "Negative values not allowed\n" );
355 mMinMotionDistance.x = minXDistance;
356 mMinMotionDistance.y = minYDistance;
359 void TouchEventCombiner::SetMinimumMotionDistanceThreshold( Vector2 minDistance )
361 DALI_ASSERT_ALWAYS( minDistance.x >= 0.0f && minDistance.y >= 0.0f && "Negative values not allowed\n" );
363 mMinMotionDistance = minDistance;
366 unsigned long TouchEventCombiner::GetMinimumMotionTimeThreshold() const
368 return mMinMotionTime;
371 Vector2 TouchEventCombiner::GetMinimumMotionDistanceThreshold() const
373 return mMinMotionDistance;
376 void TouchEventCombiner::Reset()
378 mPressedPoints.clear();
379 mHoveredPoints.clear();
382 } // namespace Integration