webengine/webkitutils/rt_gesturehelper/src/gesturehelperimpl.cpp
changeset 42 d39add9822e2
parent 38 6297cdf66332
child 46 ea4b2e4f7cac
child 47 9377e2ba0634
child 65 5bfc169077b2
--- 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 <e32base.h>
-#include <w32std.h>
-
-#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<CGestureHelperImpl*>( 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<CGesture&>(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;
-        }
-    }