diff -r 6297cdf66332 -r d39add9822e2 webengine/webkitutils/rt_gesturehelper/src/gesturehelperimpl.cpp --- a/webengine/webkitutils/rt_gesturehelper/src/gesturehelperimpl.cpp Mon Jan 18 21:20:18 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,631 +0,0 @@ -/* -* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). -* All rights reserved. -* This component and the accompanying materials are made available -* under the terms of the License "Eclipse Public License v1.0" -* which accompanies this distribution, and is available -* at the URL "http://www.eclipse.org/legal/epl-v10.html". -* -* Initial Contributors: -* Nokia Corporation - initial contribution. -* -* Contributors: -* -* Description: Gesture helper implementation -* -*/ - - -#include "gesturehelperimpl.h" - -#include -#include - -#include "gesture.h" -#include "gesturedefs.h" -#include "utils.h" -#include "gestureeventfilter.h" -#include "gesturehelpereventsender.h" -#include "flogger.h" - -using namespace RT_GestureHelper; - -namespace RT_GestureHelper -{ - -/// type of function in gesture helper to be called by the timer -/// when timer triggers -typedef void (CGestureHelperImpl::*CallbackFunctionL)(); - -NONSHARABLE_CLASS( CCallbackTimer ) : public CTimer - { -public: - /** Two-phase constructor */ - static CCallbackTimer* NewL( CGestureHelperImpl& aHelper, - CallbackFunctionL aCallbackFunctionL, TInt aDelay, TBool aIsEnabled ) - { - CCallbackTimer* self = new ( ELeave ) CCallbackTimer( aHelper, - aCallbackFunctionL, aDelay, aIsEnabled ); - CleanupStack::PushL( self ); - self->ConstructL(); // construct base class - CActiveScheduler::Add( self ); - CleanupStack::Pop( self ); - return self; - } - - /** Destructor */ - ~CCallbackTimer() - { - Cancel(); - } - - /** Set whether sending holding events is currently enabled */ - void SetEnabled( TBool aEnabled ) - { - iIsEnabled = aEnabled; - // cancel in case hold timer is already running - Cancel(); - } - - /** @return whether sending holding events is currently enabled */ - TBool IsEnabled() const - { - return iIsEnabled; - } - - /** Start the timer. Calls CGestureHelperImpl::StartHoldingL upon completion */ - void Start() - { - // if sending hold events is disabled, do not ever start the hold timer, and - // hence hold events will never be triggered - if ( iIsEnabled ) - { - Cancel(); - After( iDelay ); - } - } - void SetDelay(TInt aDelay) { iDelay = aDelay; } - TInt GetDelay() { return iDelay; } - -private: - /** Constructor */ - CCallbackTimer( CGestureHelperImpl& aHelper, - CallbackFunctionL aCallbackFunctionL, TInt aDelay, TBool aIsEnabled ) - : CTimer( EPriorityUserInput - 1 ), // give higher priority to new pointer events with - 1 - iHelper( aHelper ), iCallbackFunctionL( aCallbackFunctionL ), - iDelay( aDelay ), iIsEnabled( aIsEnabled ) - { - } - - void RunL() // From CActive - { - (iHelper.*iCallbackFunctionL)(); - } - -private: - /// helper object that will be called back when timer is triggered - CGestureHelperImpl& iHelper; - /// Function in the iHelper object call - CallbackFunctionL iCallbackFunctionL; - /// How long a time to wait befor calling back after Start() - TInt iDelay; - /// whether sending holding events is currently enabled - TBool iIsEnabled; - }; - -} // namespace GestureHelper - -/** - * @return position from event. Use this instead of using aEvent direction to - * avoid accidentally using TPointerEvent::iPosition - */ -inline TPoint Position( const TPointerEvent& aEvent ) - { - // use parent position, since the capturer is using full screen area, - // and because the (Alfred) drag events are not local to visual even when - // coming from the client - - return aEvent.iPosition; - } - -// ---------------------------------------------------------------------------- -// Two-phase constructor -// ---------------------------------------------------------------------------- -// -CGestureHelperImpl* CGestureHelperImpl::NewL( MGestureObserver& aObserver ) - { - CGestureHelperImpl* self = new ( ELeave ) CGestureHelperImpl( aObserver ); - CleanupStack::PushL( self ); - self->iEventSender = CGestureEventSender::NewL( aObserver ); - self->iDoubleTapTimer = CCallbackTimer::NewL( *self, EmitFirstTapEvent, - KMaxTapDuration, EFalse ); // double tap is disabled by default - self->iHoldingTimer = CCallbackTimer::NewL( *self, StartHoldingL, - KHoldDuration, EFalse ); // holding is enabled by default - - self->iLongTouchTimer = CCallbackTimer::NewL( *self, HandleLongTouch, - KLongTapDuration, ETrue ); // holding is enabled by default - - self->iGesture = new ( ELeave ) CGesture(); - self->iUnusedGesture = new ( ELeave ) CGesture(); - TInt tapLimit = Mm2Pixels(KFingerSize_mm) / 2; - self->iEventFilter = new (ELeave) CGestureEventFilter(tapLimit); - CleanupStack::Pop( self ); - return self; - } - -// ---------------------------------------------------------------------------- -// Constructor -// ---------------------------------------------------------------------------- -// -CGestureHelperImpl::CGestureHelperImpl( MGestureObserver& aObserver ) - : iObserver( aObserver ) - { - } - -// ---------------------------------------------------------------------------- -// Destructor -// ---------------------------------------------------------------------------- -// -CGestureHelperImpl::~CGestureHelperImpl() - { - delete iDoubleTapTimer; - delete iHoldingTimer; - delete iGesture; - delete iPreviousTapGesture; - delete iUnusedGesture; - delete iLongTouchTimer; - delete iEventFilter; - delete iEventSender; - } - - -// ---------------------------------------------------------------------------- -// SetHoldingEnabled -// ---------------------------------------------------------------------------- -// -void CGestureHelperImpl::SetHoldingEnabled( TBool aEnabled ) - { - iHoldingTimer->SetEnabled( aEnabled ); - } - -// ---------------------------------------------------------------------------- -// IsHoldingEnabled -// ---------------------------------------------------------------------------- -// -TBool CGestureHelperImpl::IsHoldingEnabled() const - { - return iHoldingTimer->IsEnabled(); - } - -// ---------------------------------------------------------------------------- -// SetHoldingEnabled -// ---------------------------------------------------------------------------- -// -void CGestureHelperImpl::SetDoubleTapEnabled( TBool aEnabled ) - { - iDoubleTapTimer->SetEnabled( aEnabled ); - } - -// ---------------------------------------------------------------------------- -// IsHoldingEnabled -// ---------------------------------------------------------------------------- -// -TBool CGestureHelperImpl::IsDoubleTapEnabled() const - { - return iDoubleTapTimer->IsEnabled(); - } - - - -// ---------------------------------------------------------------------------- -// Reset state -// ---------------------------------------------------------------------------- -// -void CGestureHelperImpl::Reset() - { - iHoldingTimer->Cancel(); - iLongTouchTimer->Cancel(); - iGesture->Reset(); - } - -/** - * Helper function that calls Reset on the pointer to CGestureHelperImpl - */ -static void ResetHelper( TAny* aHelper ) - { - static_cast< CGestureHelperImpl* >( aHelper )->Reset(); - } - -// ---------------------------------------------------------------------------- -// Handle a pointer event -// ---------------------------------------------------------------------------- -// -TBool CGestureHelperImpl::HandlePointerEventL( const TPointerEvent& aEvent ) - { - TInt filterReason; - SetLastEventTime(); - if (!iEventFilter->FilterDrag(aEvent, iLastEventTime, filterReason)) - { - return noneAlf_HandlePointerEventL( aEvent ); - } - else - { - /* - TBuf<10> num; - num.Num( filterReason ); - TBuf<128> str; - str.AppendFormat(_L("Filter reason: %d"), filterReason); - RFileLogger::Write( _L("gh"), _L("gh.txt"), EFileLoggingModeAppend, str); - */ - return EFalse; - } - } - - -TBool CGestureHelperImpl::noneAlf_HandlePointerEventL( const TPointerEvent& aEvent) - { - switch ( aEvent.iType ) - { - case TPointerEvent::EButton1Down: - { - HandleTouchDownL(aEvent); - break; - } - case TPointerEvent::EDrag: - { - HandleMoveL(aEvent); - break; - } - case TPointerEvent::EButton1Up: - { - if (KErrNone == AddPoint( aEvent )) - { - HandleTouchUp(aEvent); - } - else - { - EmitCancelEvent(); - } - Reset(); - break; - } - default: - break; - } - return ETrue; - } - -TBool CGestureHelperImpl::IsMovementGesture(TGestureCode aCode) - { - return (aCode == EGestureDrag || aCode == EGestureFlick || aCode == EGestureSwipeUp || - aCode == EGestureSwipeDown || aCode == EGestureSwipeRight || aCode == EGestureSwipeLeft); - } - -void CGestureHelperImpl::HandleLongTouch() - { - iDoubleTapTimer->Cancel(); - iGesture->SetLongTap(ETrue); - iGesture->SetComplete(); - TPoint startPos = iGesture->StartPos(); - EmitEvent(*iGesture); - iGesture->Reset(); - iGesture->AddPoint( startPos, GetLastEventTime() ); - } - -void CGestureHelperImpl::HandleTouchDownL(const TPointerEvent& aEvent) - { - TGestureCode prevCode = iGesture->PreviousGestureCode(); - if (prevCode == EGestureStart) return; - if (prevCode == EGestureDrag) - { - iGesture->Reset(); - } - AddPointL( aEvent ); - - if (!iLongTouchTimer->IsActive()) - { - iLongTouchTimer->Start(); - } - if (!iDoubleTapTimer->IsActive()) - { - EmitEvent( *iGesture ); - } - } - -void CGestureHelperImpl::HandleMoveL(const TPointerEvent& aEvent) - { - if (iGesture->IsLatestPoint( Position(aEvent))) return; // I'm not sure we need this - //Cancel double tap time - it's neither tap nor double tap - iDoubleTapTimer->Cancel(); - iLongTouchTimer->Cancel(); - - TBool isFirstPoint = IsIdle(); - - AddPointL( aEvent ); - - if (iPreviousTapGesture) - { - RecycleGesture(iPreviousTapGesture); - } - - if (!isFirstPoint) - { - EmitEvent( *iGesture ); - } - } - -void CGestureHelperImpl::HandleTouchUp(const TPointerEvent& /*aEvent*/) - { - TGestureCode prevCode = iGesture->PreviousGestureCode(); - iLongTouchTimer->Cancel(); - iDoubleTapTimer->Cancel(); - TInt64 fromLastTouchUp = iLastEventTime.MicroSecondsFrom(iLastTouchUpTime).Int64(); - TInt64 fromLastDoubleTap = iLastEventTime.MicroSecondsFrom(iLastDoubleTapTime).Int64(); - /* - TBuf<1024> str; - str.AppendFormat(_L("fromLastTouchUp: %d, "), fromLastTouchUp); - str.AppendFormat(_L("fromLastDoubleTap: %d, "), fromLastTouchUp); - str.AppendFormat(_L("iPreviousTapGesture: %d, "), iPreviousTapGesture); - RFileLogger::Write( _L("gh"), _L("gh.txt"), EFileLoggingModeAppend, str); - */ - if ( prevCode == EGestureLongTap ) - { - EmitReleasedEvent(); - } - else if (IsMovementGesture(prevCode) || - !iDoubleTapTimer->IsEnabled() /* || !iGesture->IsTap()*/ ) - { - iGesture->SetComplete(); - EmitEvent(*iGesture); - } - - else - { - if ( iPreviousTapGesture && - (fromLastTouchUp > KDoubleTapMinActivationInterval) && - (fromLastTouchUp < KDoubleTapMaxActivationInterval) && - (fromLastDoubleTap > KDoubleTapIdleInterval)) - { - // it's a double tap - iLastTouchUpTime = iLastEventTime; - iLastDoubleTapTime = iLastEventTime; - EmitDoubleTapEvent(); - } - else - { - // it's a first tap - iLastTouchUpTime = iLastEventTime; - if (iPreviousTapGesture) - { - RecycleGesture(iPreviousTapGesture); - } - - iPreviousTapGesture = iGesture; - iGesture = NewGesture(); - iDoubleTapTimer->Start(); - } - } - } - - - -void CGestureHelperImpl::EmitDoubleTapEvent() - { - iPreviousTapGesture->SetDoubleTap(); - EmitFirstTapEvent(); - } - - -void CGestureHelperImpl::EmitReleasedEvent() - { - iGesture->SetComplete(); - iGesture->SetReleased(); - EmitEvent(*iGesture); - } - - -// ---------------------------------------------------------------------------- -// Is the helper idle? -// inline ok in cpp file for a private member function -// ---------------------------------------------------------------------------- -// -inline TBool CGestureHelperImpl::IsIdle() const - { - return iGesture->IsEmpty(); - } - -// ---------------------------------------------------------------------------- -// Add a point to the sequence of points that together make up the gesture -// inline ok in cpp file for a private member function -// ---------------------------------------------------------------------------- -// -inline void CGestureHelperImpl::AddPointL( const TPointerEvent& aEvent ) - { - User::LeaveIfError( AddPoint( aEvent ) ); - } - -// ---------------------------------------------------------------------------- -// Add a point to the sequence of points that together make up the gesture -// inline ok in cpp file for a private member function -// ---------------------------------------------------------------------------- -// -inline TInt CGestureHelperImpl::AddPoint( const TPointerEvent& aEvent ) - { - TPoint pos = Position ( aEvent ); - return iGesture->AddPoint( pos, GetLastEventTime() ); - } - -// ---------------------------------------------------------------------------- -// StartHoldingTimer -// ---------------------------------------------------------------------------- -// -void CGestureHelperImpl::StartHoldingTimer( const TPointerEvent& aNewEvent ) - { - if ( !( iGesture->IsHolding() || - iGesture->IsNearHoldingPoint( Position( aNewEvent ) ) ) ) - { - // restart hold timer, since pointer has moved - iHoldingTimer->Start(); - // Remember the point in which holding was started - iGesture->SetHoldingPoint(); - } - } - -/** - * Helper function that calls ContinueHolding on the pointer to TGesture - */ -static void ContinueHolding( TAny* aGesture ) - { - static_cast< CGesture* >( aGesture )->ContinueHolding(); - } - -// ---------------------------------------------------------------------------- -// Add a point to the sequence of points that together make up the gesture -// ---------------------------------------------------------------------------- -// -void CGestureHelperImpl::StartHoldingL() - { - // hold & tap event is specifically filtered out. Use case: in list fast - // scrolling activation (e.g. enhanced coverflow), tap & hold should not - // start fast scroll. In addition, after long tap on start position, - // drag and drag & hold swiping should emit normal swipe and swipe&hold - // events. Therefore, tap & hold is not supported. - __ASSERT_DEBUG( !iGesture->IsTap() && !iPreviousTapGesture, Panic( EGesturePanicIllegalLogic ) ); - - // holding has just started, and gesture code should be provided to client. - // set gesture state so that it produces a gesture code (other than drag) - iGesture->StartHolding(); - - // create an item in the cleanup stack that will set the gesture state - // to holding-was-started-earlier state. NotifyL may leave, but the - // holding-was-started-earlier state must still be successfully set, - // otherwise, the holding gesture code will be sent twice - CleanupStack::PushL( TCleanupItem( &ContinueHolding, iGesture ) ); - - EmitEvent( *iGesture ); - - // set holding state to "post holding" - CleanupStack::PopAndDestroy( iGesture ); - } - -// ---------------------------------------------------------------------------- -// RecyclePreviousTapGesture -// ---------------------------------------------------------------------------- -// -void CGestureHelperImpl::RecyclePreviousTapGesture( TAny* aSelf ) - { - CGestureHelperImpl& self = *reinterpret_cast( aSelf ); - self.RecycleGesture( self.iPreviousTapGesture ); - } - -// ---------------------------------------------------------------------------- -// Emit the remainder of the previous tap event (tap + released) -// ---------------------------------------------------------------------------- -// -void CGestureHelperImpl::EmitFirstTapEvent() - { - // when this function is called, a tap has turned out to _not_ be a double tap - __ASSERT_DEBUG( IsDoubleTapEnabled(), Panic( EGesturePanicIllegalLogic ) ); - __ASSERT_DEBUG( iPreviousTapGesture, Panic( EGesturePanicIllegalLogic ) ); - - iDoubleTapTimer->Cancel(); - CompleteAndEmit( *iPreviousTapGesture ); - RecycleGesture(iPreviousTapGesture); - - } - -// ---------------------------------------------------------------------------- -// EmitStartEventL -// ---------------------------------------------------------------------------- -// -void CGestureHelperImpl::EmitStartEventL( const CGesture& aGesture ) - { - CGesture* startGesture = aGesture.AsStartEventLC(); - EmitEvent( *startGesture ); - CleanupStack::PopAndDestroy( startGesture ); - } - -// ---------------------------------------------------------------------------- -// EmitCompletionEventsL -// ---------------------------------------------------------------------------- -// -void CGestureHelperImpl::CompleteAndEmit( CGesture& aGesture ) - { - aGesture.SetComplete(); - // send gesture code if holding has not been started. If holding has - // been started, client has already received a "hold swipe left" e.g. event, in which - // case don't another "swipe left" event - if ( !aGesture.IsHolding() ) - { - // if client leaves, the state is automatically reset. - // In this case the client will not get the released event - EmitEvent( aGesture ); - } - - // send an event that stylus was lifted - aGesture.SetReleased(); - EmitEvent( aGesture ); - } - -// ---------------------------------------------------------------------------- -// EmitCancelEventL -// ---------------------------------------------------------------------------- -// -void CGestureHelperImpl::EmitCancelEvent() - { - iDoubleTapTimer->Cancel(); - - - CGesture& gestureToCancel = iPreviousTapGesture ? *iPreviousTapGesture : *iGesture; - gestureToCancel.SetCancelled(); - EmitEvent( gestureToCancel ); - RecycleGesture(iPreviousTapGesture); - - } - -// ---------------------------------------------------------------------------- -// Notify observer -// ---------------------------------------------------------------------------- -// -void CGestureHelperImpl::EmitEvent( const CGesture& aGesture ) - { - // deallocation of the event is happening in CGestureEventSender::RunL() - TGestureEvent event; - event.SetCode(const_cast(aGesture).Code(EAxisBoth)); - event.SetCurrentPos(aGesture.CurrentPos()); - event.SetDistance(aGesture.Distance()); - event.SetStartPos(aGesture.StartPos()); - event.SetIsHolding(aGesture.IsHolding()); - event.SetSpeed(aGesture.Speed()); - iEventSender->AddEvent(event); - } - -// ---------------------------------------------------------------------------- -// Return a fresh gesture from the gesture pool (pool of one gesture) -// ---------------------------------------------------------------------------- -// -CGesture* CGestureHelperImpl::NewGesture() - { - __ASSERT_DEBUG( iUnusedGesture, Panic( EGesturePanicIllegalLogic ) ); // pool should no be empty - - iUnusedGesture->Reset(); - CGesture* freshGesture = iUnusedGesture; - iUnusedGesture = NULL; - return freshGesture; - } - -// ---------------------------------------------------------------------------- -// Return a fresh gesture from the gesture pool (pool of one gesture) -// ---------------------------------------------------------------------------- -// -void CGestureHelperImpl::RecycleGesture( CGesture*& aGesturePointer ) - { - // only one object fits into the pool, and that should currently be enough - // one pointer must be null, one non-null - __ASSERT_DEBUG( !iUnusedGesture != !aGesturePointer, Panic( EGesturePanicIllegalLogic ) ); - if ( aGesturePointer ) - { - iUnusedGesture = aGesturePointer; - aGesturePointer = NULL; - } - }