mulwidgets/gesturehelper/src/gesturehelperimpl.cpp
changeset 0 e83bab7cf002
child 3 4526337fb576
equal deleted inserted replaced
-1:000000000000 0:e83bab7cf002
       
     1 /*
       
     2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Gesture helper implementation
       
    15 *
       
    16 */
       
    17 
       
    18 #include "gesturehelperimpl.h"
       
    19 
       
    20 #include <alf/alfevent.h>
       
    21 #include <e32base.h>
       
    22 #include <w32std.h>
       
    23 
       
    24 #include "gesture.h"
       
    25 #include "gesturedefs.h"
       
    26 
       
    27 #include "pointercapturer.h"
       
    28 
       
    29 using namespace GestureHelper;
       
    30 
       
    31 namespace GestureHelper
       
    32 {
       
    33 
       
    34 /// type of function in gesture helper to be called by the timer
       
    35 /// when timer triggers
       
    36 typedef void (CGestureHelperImpl::*CallbackFunctionL)();
       
    37 
       
    38 NONSHARABLE_CLASS( CCallbackTimer ) : public CTimer
       
    39     {
       
    40 public:
       
    41     /** Two-phase constructor */
       
    42     static CCallbackTimer* NewL( CGestureHelperImpl& aHelper, 
       
    43             CallbackFunctionL aCallbackFunctionL, TInt aDelay, TBool aIsEnabled )
       
    44         {
       
    45         CCallbackTimer* self = new ( ELeave ) CCallbackTimer( aHelper, 
       
    46             aCallbackFunctionL, aDelay, aIsEnabled );
       
    47         CleanupStack::PushL( self );
       
    48         self->ConstructL(); // construct base class
       
    49         CActiveScheduler::Add( self );
       
    50         CleanupStack::Pop( self );
       
    51         return self;
       
    52         }
       
    53         
       
    54     /** Destructor */
       
    55     ~CCallbackTimer()
       
    56         {
       
    57         Cancel();
       
    58         }
       
    59         
       
    60     /** Set whether sending holding events is currently enabled */
       
    61     void SetEnabled( TBool aEnabled )
       
    62         {
       
    63         iIsEnabled = aEnabled;
       
    64         // cancel in case hold timer is already running
       
    65         Cancel();
       
    66         }
       
    67         
       
    68     /** @return whether sending holding events is currently enabled */
       
    69     TBool IsEnabled() const
       
    70         {
       
    71         return iIsEnabled;
       
    72         }
       
    73         
       
    74     /** Start the timer. Calls CGestureHelperImpl::StartHoldingL upon completion */
       
    75     void Start()
       
    76         {
       
    77         // if sending hold events is disabled, do not ever start the hold timer, and 
       
    78         // hence hold events will never be triggered
       
    79         if ( iIsEnabled ) 
       
    80             {
       
    81             Cancel();
       
    82             After( iDelay );
       
    83             }
       
    84         }    
       
    85     
       
    86 private:    
       
    87     /** Constructor */
       
    88     CCallbackTimer( CGestureHelperImpl& aHelper,
       
    89         CallbackFunctionL aCallbackFunctionL, TInt aDelay, TBool aIsEnabled )
       
    90             : CTimer( EPriorityUserInput - 1 ), // give higher priority to new pointer events with - 1
       
    91                 iHelper( aHelper ), iCallbackFunctionL( aCallbackFunctionL ), 
       
    92                     iDelay( aDelay ), iIsEnabled( aIsEnabled ) 
       
    93         {
       
    94         }
       
    95         
       
    96     void RunL() // From CActive
       
    97         {
       
    98         (iHelper.*iCallbackFunctionL)();
       
    99         }
       
   100 
       
   101 private:
       
   102     /// helper object that will be called back when timer is triggered
       
   103     CGestureHelperImpl& iHelper;
       
   104     /// Function in the iHelper object call 
       
   105     CallbackFunctionL iCallbackFunctionL;
       
   106     /// How long a time to wait befor calling back after Start()
       
   107     TInt iDelay;
       
   108     /// whether sending holding events is currently enabled
       
   109     TBool iIsEnabled;
       
   110     };
       
   111 
       
   112 } // namespace GestureHelper
       
   113 
       
   114 /** 
       
   115  * @return position from event. Use this instead of using aEvent direction to
       
   116  *         avoid accidentally using TPointerEvent::iPosition
       
   117  */
       
   118 inline TPoint Position( const TPointerEvent& aEvent )
       
   119     {
       
   120     // use parent position, since the capturer is using full screen area,
       
   121     // and because the (Alfred) drag events are not local to visual even when
       
   122     // coming from the client
       
   123     return aEvent.iParentPosition;
       
   124     }
       
   125 
       
   126 // ----------------------------------------------------------------------------
       
   127 // Two-phase constructor
       
   128 // ----------------------------------------------------------------------------
       
   129 //
       
   130 CGestureHelperImpl* CGestureHelperImpl::NewL( MGestureObserver& aObserver )
       
   131     {
       
   132     CGestureHelperImpl* self = new ( ELeave ) CGestureHelperImpl( );
       
   133     CleanupStack::PushL( self );
       
   134     self->iDoubleTapTimer = CCallbackTimer::NewL( *self, EmitFirstTapEventL, 
       
   135         KMaxDoubleTapDuration, EFalse ); // double tap is disabled by default
       
   136     self->iHoldingTimer = CCallbackTimer::NewL( *self, StartHoldingL, 
       
   137         KHoldDuration, ETrue ); // holding is enabled by default
       
   138     self->iGesture = new ( ELeave ) CGesture();
       
   139     self->iUnusedGesture = new ( ELeave ) CGesture();
       
   140     self->iPointerCapturer = CPointerCapturer::NewL();
       
   141     self->iPointerCount = 0;
       
   142     self->iObserver = &aObserver;
       
   143     CleanupStack::Pop( self );
       
   144     return self;
       
   145     }
       
   146 
       
   147 // ----------------------------------------------------------------------------
       
   148 // Destructor
       
   149 // ----------------------------------------------------------------------------
       
   150 //
       
   151 CGestureHelperImpl::~CGestureHelperImpl()
       
   152     {
       
   153     delete iDoubleTapTimer;
       
   154     delete iHoldingTimer;
       
   155     delete iGesture;
       
   156     delete iPreviousTapGesture;
       
   157     delete iUnusedGesture;
       
   158     delete iPointerCapturer;
       
   159     }
       
   160     
       
   161 // ----------------------------------------------------------------------------
       
   162 // SetHoldingEnabled
       
   163 // ----------------------------------------------------------------------------
       
   164 //
       
   165 void CGestureHelperImpl::SetHoldingEnabled( TBool aEnabled )
       
   166     {
       
   167     iHoldingTimer->SetEnabled( aEnabled );
       
   168     }
       
   169 
       
   170 // ----------------------------------------------------------------------------
       
   171 // IsHoldingEnabled
       
   172 // ----------------------------------------------------------------------------
       
   173 //
       
   174 TBool CGestureHelperImpl::IsHoldingEnabled() const
       
   175     {
       
   176     return iHoldingTimer->IsEnabled();
       
   177     }
       
   178 
       
   179 // ----------------------------------------------------------------------------
       
   180 // SetHoldingEnabled
       
   181 // ----------------------------------------------------------------------------
       
   182 //
       
   183 void CGestureHelperImpl::SetDoubleTapEnabled( TBool aEnabled )
       
   184     {
       
   185     iDoubleTapTimer->SetEnabled( aEnabled );
       
   186     }
       
   187 
       
   188 // ----------------------------------------------------------------------------
       
   189 // IsHoldingEnabled
       
   190 // ----------------------------------------------------------------------------
       
   191 //
       
   192 TBool CGestureHelperImpl::IsDoubleTapEnabled() const
       
   193     {
       
   194     return iDoubleTapTimer->IsEnabled();
       
   195     }
       
   196     
       
   197 // ----------------------------------------------------------------------------
       
   198 // InitAlfredPointerEventCaptureL
       
   199 // ----------------------------------------------------------------------------
       
   200 //
       
   201 void CGestureHelperImpl::InitAlfredPointerCaptureL( CAlfEnv& aEnv, 
       
   202         CAlfDisplay& aDisplay, TInt aFreeControlGroupId )
       
   203     {
       
   204     iPointerCapturer->InitForAlfredL(*this, aEnv, aDisplay, aFreeControlGroupId );
       
   205     }
       
   206 
       
   207 // ----------------------------------------------------------------------------
       
   208 // Reset state
       
   209 // ----------------------------------------------------------------------------
       
   210 //
       
   211 void CGestureHelperImpl::Reset()
       
   212     {
       
   213     iHoldingTimer->Cancel();
       
   214     iGesture->Reset();
       
   215     iPointerCapturer->Stop();
       
   216     iPointerCount=0;
       
   217     iCurrentPointer = -1;
       
   218     }
       
   219 
       
   220 /** 
       
   221  * Helper function that calls Reset on the pointer to CGestureHelperImpl
       
   222  */
       
   223 static void ResetHelper( TAny* aHelper )
       
   224     {
       
   225     static_cast< CGestureHelperImpl* >( aHelper )->Reset();
       
   226     }
       
   227 
       
   228 // ----------------------------------------------------------------------------
       
   229 // Handle a pointer event
       
   230 // ----------------------------------------------------------------------------
       
   231 //
       
   232 TBool CGestureHelperImpl::HandlePointerEventL( const TPointerEvent& aEvent )
       
   233     {     
       
   234     return HandlePointerEventL( aEvent, NULL );
       
   235     }
       
   236 
       
   237 // ----------------------------------------------------------------------------
       
   238 // OfferEventL
       
   239 // ----------------------------------------------------------------------------
       
   240 //
       
   241 TBool CGestureHelperImpl::OfferEventL( const TAlfEvent& aEvent )
       
   242     {
       
   243     if ( aEvent.IsPointerEvent() )
       
   244         {
       
   245         return HandlePointerEventL( aEvent.PointerEvent(), aEvent.Visual() );
       
   246         }
       
   247     return EFalse;
       
   248     }
       
   249 
       
   250 // ----------------------------------------------------------------------------
       
   251 // Handle a pointer event
       
   252 // ----------------------------------------------------------------------------
       
   253 //
       
   254 TBool CGestureHelperImpl::HandlePointerEventL( const TPointerEvent& aEvent,
       
   255         CAlfVisual* aVisual )
       
   256     {  
       
   257     TInt pointerNumber = GestureHelper::TGestureRecogniser().PointerNumber( aEvent );
       
   258 
       
   259     if( !ValidatePointer( aEvent, pointerNumber ) )
       
   260         {
       
   261         return EFalse; // don't consume
       
   262         }
       
   263 
       
   264     switch ( aEvent.iType )
       
   265         {
       
   266         case TPointerEvent::EButton1Down:            
       
   267 		    // Error handling for recieveing a button down on the pointer which
       
   268             // is already touched down
       
   269             // Here the pointer number shouldnot be considered for validtaing.
       
   270             // We should consider which pointer is currently touched down
       
   271             // It can so happen that user has touched was doing pinch and then released his
       
   272             // 1st finger. and starts to do panning with the second finger still touched down.
       
   273             // Then again when he touches the first finger, in that case you should be validating these pointers w.r.t
       
   274             // the pointer numbers of the last touched finger
       
   275              
       
   276             // we shouldnot consider pointer number here. If pointer 1 is
       
   277             // already touched and dragging and we recieve a down of pointer 0     
       
   278                     
       
   279             if( iPointerCount == 1 )
       
   280                 {
       
   281                 if(iCurrentPointer == pointerNumber )
       
   282                     {
       
   283                     TRAP_IGNORE( EmitCancelEventL() );
       
   284                     Reset();
       
   285                     }
       
   286                 }
       
   287             else if( iPointerCount == 2 )
       
   288                 {
       
   289                 // if pointer count is already 2, then reset the array of pointer for 
       
   290                 // which a down event is recieved, and continue handling in normal way
       
   291                 iPointerCount = 1; 
       
   292                 iCurrentPointer = pointerNumber == 0 ? 1 : 0;
       
   293                 iGesture->ResetToLastPoint(pointerNumber != 0,pointerNumber != 0);
       
   294                 }
       
   295 
       
   296             if(iPointerCount == 0)
       
   297                 {
       
   298                 iPointerCount = 1;
       
   299                 iCurrentPointer = pointerNumber;
       
   300                 // single touch gesture start
       
   301                 iGesture->SetSingleTouchActive();
       
   302                 HandleSinglePointerEventL( aEvent, aVisual );
       
   303                 }
       
   304             else if(iPointerCount == 1)
       
   305                 {              
       
   306                 iPointerCount = 2;
       
   307                 iCurrentPointer = -1;
       
   308                 // add the last point of the single touch event
       
   309                 // to first array of gesture
       
   310                 iGesture->ResetToLastPoint(pointerNumber != 0,ETrue);
       
   311                 iGesture->SetMultiTouchActive();
       
   312                 // multi touch gesture start
       
   313                 HandleMultiplePointerEventL( aEvent, pointerNumber );
       
   314                 }
       
   315             else
       
   316                 {
       
   317                 
       
   318                 }
       
   319             break;
       
   320             
       
   321         case TPointerEvent::EDrag:
       
   322             if(iPointerCount == 1)
       
   323                 {
       
   324                 HandleSinglePointerEventL( aEvent, aVisual );
       
   325                 }
       
   326             else if(iPointerCount == 2)
       
   327                 {
       
   328                 HandleMultiplePointerEventL( aEvent, pointerNumber );
       
   329                 }
       
   330             else
       
   331                 {
       
   332                 // nothing to be done
       
   333                 }
       
   334             break;
       
   335             
       
   336         case TPointerEvent::EButton1Up:
       
   337             if(iPointerCount == 2)
       
   338                 { 
       
   339                 // multi touch gesture complete
       
   340                 HandleMultiplePointerEventL( aEvent, pointerNumber );
       
   341                 // should the pointer count decrese first n then
       
   342                 // handling of event or otherwise
       
   343                 iPointerCount = 1;    
       
   344                 iCurrentPointer = pointerNumber == 0 ? 1 : 0;
       
   345                 iGesture->ResetToLastPoint(ETrue,pointerNumber != 0);
       
   346                 iGesture->SetSingleTouchActive();
       
   347                 }
       
   348             else if( iPointerCount == 1 )
       
   349                 {
       
   350                 iPointerCount = 0;
       
   351                 iCurrentPointer = -1;
       
   352                 // single touch gesture complete
       
   353                 HandleSinglePointerEventL( aEvent, aVisual ); 
       
   354                 }
       
   355             else
       
   356                 {
       
   357                 // nothing to be done
       
   358                 }
       
   359             break;
       
   360             
       
   361         default:
       
   362             break;
       
   363         }
       
   364     return ETrue; // consume
       
   365     }
       
   366 // ----------------------------------------------------------------------------
       
   367 // Handle a pointer event
       
   368 // ----------------------------------------------------------------------------
       
   369 //
       
   370 TBool CGestureHelperImpl::HandleSinglePointerEventL( const TPointerEvent& aEvent,
       
   371         CAlfVisual* aVisual )
       
   372     {  
       
   373     switch ( aEvent.iType )
       
   374         {
       
   375         case TPointerEvent::EButton1Down:
       
   376             // If no up event was received during previous gesture, cancel 
       
   377             // previous event and reset state
       
   378             if ( !IsIdle() )
       
   379                 {
       
   380                 // ambiguous what is the right thing when "cancel" event leaves
       
   381                 // and "start" does not. Leaving for cancel *after* "start" could 
       
   382                 // be unexpected to client, as client would have handled start 
       
   383                 // event successfully. Assume that leaving upon cancellation 
       
   384                 // can be ignored.
       
   385                 TRAP_IGNORE( EmitCancelEventL() );
       
   386                 Reset();  
       
   387                 }
       
   388             // as long as down event of a double tap comes within the double 
       
   389             // tap timeout, it does not matter how long the user keeps the finger
       
   390             // pressed for the gesture to be a double tap. Therefore, cancel
       
   391             // the timeout, as it is no longer relevant. (Of course, this call
       
   392             // will only do something if the timer is actually running, which
       
   393             // is only if received a tap event very recently.)
       
   394             iDoubleTapTimer->Cancel();
       
   395             // adding the first point implicitly makes the state "not idle"
       
   396             AddPointL( aEvent );
       
   397             iGesture->SetVisual( aVisual );
       
   398             // if pointer capturer leaves, the remaining pointer events will
       
   399             // not be captured if stylus is dragged outside the capturing visual
       
   400             // an error note will be shown, so the potential problem is irrelevant,
       
   401             // assuming client does not (incorrectly) block the leave from reaching 
       
   402             // the framework
       
   403             iPointerCapturer->StartL();
       
   404             // Delay emitting a down event _until_ it is known that this beginning 
       
   405             // gesture is _not_ the second tap of a double tap event.
       
   406             // iPreviousTapGesture is only non-null if very recently received 
       
   407             // a tap event and double tap is enabled. 
       
   408             if ( !iPreviousTapGesture )
       
   409                 {
       
   410                 EmitEventL( *iGesture );
       
   411                 }
       
   412             // else delay emitting an event, as it might be a double tap 
       
   413             // (allow the second tap of a double tap to be anywhere, so don't check
       
   414             // for start pos here)
       
   415             break;
       
   416             
       
   417         case TPointerEvent::EDrag:
       
   418             // While stylus down, the same event is received repeatedly
       
   419             // even if stylus does not move. Filter out by checking if point 
       
   420             // is the same as the latest point
       
   421             if ( !iGesture->IsLatestPoint( Position( aEvent ) ) )
       
   422                 {
       
   423                 AddPointL( aEvent );
       
   424 
       
   425                 // as long as the starting gesture is seen as a tap, do not emit any
       
   426                 // drag events
       
   427                 if ( !iGesture->IsTap() )
       
   428                     {
       
   429                     // if there is a previous tap gesture, getting drag events means that
       
   430                     // the previous gesture is not a double tap. So emit the previous gesture.
       
   431                     if ( iPreviousTapGesture )
       
   432                         {
       
   433                         // this is a second gesture after a tap (double tap is enabled)
       
   434                         EmitFirstTapEventL();
       
   435                         // emit down event for the current gesture (since its down was delayed, until
       
   436                         // it was to be known if the event is a tap. That is known now.)
       
   437                         EmitStartEventL( *iGesture );
       
   438                         }
       
   439                     // restart holding timer every time the current stylus pos changes
       
   440                     StartHoldingTimer( aEvent );
       
   441                     // emit the drag event to client
       
   442                     EmitEventL( *iGesture );
       
   443                     }
       
   444                 // else: do not emit drag events until it is known that the gesture is not a tap
       
   445                 // (or the second tap of double tap)
       
   446                 }
       
   447             break;
       
   448 
       
   449         case TPointerEvent::EButton1Up:
       
   450             // reset in case the down event for next gesture is not received for a reason 
       
   451             // in client, and instead drag or up events are received. 
       
   452             // reset via cleanup stack to ensure Reset is run even if
       
   453             // observer leaves
       
   454             CleanupStack::PushL( TCleanupItem( &ResetHelper, this ) );
       
   455             // if adding of the point fails, notify client with a 
       
   456             // cancelled event. It would be wrong to send another
       
   457             // gesture code when the up point is not known
       
   458             if ( KErrNone == AddPoint( aEvent ) )
       
   459                 {
       
   460                 // if the gesture is a tap, the gesture is either the first tap of a _potential_
       
   461                 // double tap, or the second tap of a double tap
       
   462                 if ( iDoubleTapTimer->IsEnabled() && iGesture->IsTap() )
       
   463                     {
       
   464                     __ASSERT_DEBUG( !iGesture->IsHolding(), Panic( EGesturePanicIllegalLogic ) );
       
   465                     if ( !iPreviousTapGesture )
       
   466                         {
       
   467                         // First tap. Delay emitting its code evemt and released events until it is known
       
   468                         // whether the tap is a double tap
       
   469                         iPreviousTapGesture = iGesture;
       
   470                         iGesture = NewGesture();
       
   471                         iDoubleTapTimer->Start(); 
       
   472                         }
       
   473                     else
       
   474                         {
       
   475                         // This is a second tap of a double tap. Do not emit anything for the second
       
   476                         // tap. Only down event has been emitted for the first tap. Emit the code 
       
   477                         // event (double tap) and released for the first tap.
       
   478                         iPreviousTapGesture->SetDoubleTap();
       
   479                         EmitFirstTapEventL();
       
   480                         }
       
   481                     }
       
   482                 else 
       
   483                     {
       
   484                     // modified iGesture to be "released"
       
   485                     CompleteAndEmitSingleTouchL( *iGesture );
       
   486                     }
       
   487                 }
       
   488             else
       
   489                 { // adding a point failed
       
   490                 EmitCancelEventL();
       
   491                 }
       
   492             // reset state
       
   493             CleanupStack::PopAndDestroy( this ); 
       
   494             break;
       
   495             
       
   496         default:
       
   497             break;
       
   498         }
       
   499     return ETrue; // consume
       
   500     }
       
   501 
       
   502 // ----------------------------------------------------------------------------
       
   503 // Handle multiple pointer events
       
   504 // ----------------------------------------------------------------------------
       
   505 //
       
   506 TBool CGestureHelperImpl::HandleMultiplePointerEventL( const TPointerEvent& aEvent,
       
   507        const TInt aPointerNumber )
       
   508     { 
       
   509     switch ( aEvent.iType )
       
   510         {
       
   511         case TPointerEvent::EButton1Down:
       
   512             // adding the first point implicitly makes the state "not idle"
       
   513             AddMultiTouchPointsL( aEvent, aPointerNumber);
       
   514             EmitEventL( *iGesture );
       
   515             break;
       
   516             
       
   517         case TPointerEvent::EDrag:
       
   518             // While stylus down, the same event is received repeatedly
       
   519             // even if stylus does not move. Filter out by checking if point 
       
   520             // is the same as the latest point
       
   521             if( AddMultiTouchPointsL(aEvent, aPointerNumber ))
       
   522                 {
       
   523                 // as long as the starting gesture is seen as a tap, do not emit any
       
   524                 // drag events
       
   525                 if ( iGesture->IsPinch() )
       
   526                     {
       
   527                     // emit the pinch event to client
       
   528                     EmitEventL( *iGesture );
       
   529                     }
       
   530                 // else: do not emit any events to the client               
       
   531                 }
       
   532 
       
   533             
       
   534             break;
       
   535 
       
   536         case TPointerEvent::EButton1Up:
       
   537                         
       
   538             // if adding of the point fails, notify client with a 
       
   539             // cancelled event. It would be wrong to send another
       
   540             // gesture code when the up point is not known
       
   541             AddMultiTouchPointsL(aEvent, aPointerNumber );
       
   542             CompleteAndEmitDoubleTouchL( *iGesture );
       
   543 
       
   544             break;
       
   545             
       
   546         default:
       
   547             break;
       
   548         }   
       
   549     return ETrue; // consume
       
   550     }
       
   551 
       
   552 // ----------------------------------------------------------------------------
       
   553 // Validate AddMultiTouchPointsL events
       
   554 // Check if the point recieved is the repeavt event of previous point or a new point 
       
   555 // inline ok in cpp file for a private member function
       
   556 // ----------------------------------------------------------------------------
       
   557 //
       
   558 inline TBool CGestureHelperImpl::AddMultiTouchPointsL( const TPointerEvent& aEvent, const TInt aPointerNumber)
       
   559     {
       
   560     TBool pointAdded = EFalse;
       
   561     if ( aPointerNumber > 0 )
       
   562         {
       
   563         if ( !iGesture->IsLatestSecondaryPoint( Position( aEvent ) ) )
       
   564             {
       
   565             AddSecondaryPointL( aEvent );
       
   566             pointAdded = ETrue;
       
   567             }                 
       
   568         }
       
   569     else
       
   570         {
       
   571         if ( !iGesture->IsLatestPoint( Position( aEvent ) ) )
       
   572             {
       
   573             AddPointL( aEvent );
       
   574             pointAdded = ETrue;
       
   575             }                
       
   576         }
       
   577     return pointAdded;
       
   578     }
       
   579 
       
   580 // ----------------------------------------------------------------------------
       
   581 // Check for Stray evnet
       
   582 // ----------------------------------------------------------------------------
       
   583 //
       
   584 TBool CGestureHelperImpl::StrayEvent( const TPointerEvent& aEvent ) const
       
   585     {
       
   586      //If we are recieving a button down on pointer 0 in pointer capturer then its a stray event
       
   587     // Dont consume it
       
   588     if ( aEvent.iType == TPointerEvent::EButton1Down && IsIdle( 0) )
       
   589         {
       
   590         return ETrue; // don't consume
       
   591         }  
       
   592 	return EFalse;  
       
   593     }
       
   594 // ----------------------------------------------------------------------------
       
   595 // Validate the events
       
   596 // is it a valid event or a stray pointer form some other visuals
       
   597 // inline ok in cpp file for a private member function
       
   598 // ----------------------------------------------------------------------------
       
   599 //
       
   600 inline TBool CGestureHelperImpl::ValidatePointer( const TPointerEvent& aEvent, const TInt aPointerNumber) const
       
   601     {
       
   602     // Check if received event is valid or not.
       
   603     // In practice, event is NOT valid in the following situations:
       
   604     //
       
   605     // 1. Pointer down event is received for pointer which is already down.
       
   606     // 2. Pointer up event is received for pointer which is already up.
       
   607     // 3. Pointer drag event is received for pointer which is not down.
       
   608     // 4. Pointer numbers other than 0 and 1. We are handling only 2 pointers.
       
   609     //
       
   610     // In these situations this function returns EFalse,
       
   611     // corresponding event is ignored and recognition continues as earlier.
       
   612     //
       
   613     
       
   614     // filter all the events for which the pointer number is less than 0
       
   615     // or greater than 1. we will handle only 2 pointer events.  
       
   616     if( aPointerNumber >= 2 || aPointerNumber < 0 )
       
   617         {
       
   618         return EFalse;
       
   619         }
       
   620         
       
   621     // filter out events that do not start with button down. It is a stray
       
   622     // event from another visual    
       
   623     TInt pointerTovalidate = aPointerNumber ;
       
   624     if( iPointerCount == 1 && aPointerNumber == 1)
       
   625 	    {
       
   626 	    pointerTovalidate = 0;
       
   627 	    }
       
   628     if ( aEvent.iType != TPointerEvent::EButton1Down && IsIdle( pointerTovalidate ) )
       
   629         {
       
   630         return EFalse; // don't consume
       
   631         }
       
   632 
       
   633     
       
   634     return ETrue;
       
   635     }
       
   636 
       
   637 // ----------------------------------------------------------------------------
       
   638 // Is the helper idle?
       
   639 // Checks whether any points are already added in the array corresponding
       
   640 // to the pointer number 
       
   641 // inline ok in cpp file for a private member function
       
   642 // ----------------------------------------------------------------------------
       
   643 //
       
   644 inline TBool CGestureHelperImpl::IsIdle( TBool aPointerNumber ) const
       
   645     {
       
   646     if( aPointerNumber == 0 )
       
   647         {
       
   648         return iGesture->IsEmpty();
       
   649         }
       
   650     else if( aPointerNumber == 1 )
       
   651         {
       
   652         return iGesture->IsMultiTouch();
       
   653         }
       
   654     return ETrue;
       
   655     }
       
   656 
       
   657 // ----------------------------------------------------------------------------
       
   658 // Add a point to the sequence of points that together make up the gesture
       
   659 // inline ok in cpp file for a private member function
       
   660 // ----------------------------------------------------------------------------
       
   661 //
       
   662 inline void CGestureHelperImpl::AddPointL( const TPointerEvent& aEvent )
       
   663     {
       
   664     User::LeaveIfError( AddPoint( aEvent ) );
       
   665     }
       
   666 
       
   667 // ----------------------------------------------------------------------------
       
   668 // Add a point to the sequence of points that together make up the gesture
       
   669 // inline ok in cpp file for a private member function
       
   670 // ----------------------------------------------------------------------------
       
   671 //
       
   672 inline TInt CGestureHelperImpl::AddPoint( const TPointerEvent& aEvent )
       
   673     {
       
   674     return iGesture->AddPoint( Position ( aEvent ) );
       
   675     }
       
   676 
       
   677 // ----------------------------------------------------------------------------
       
   678 // Add a point to the sequence of points that together make up the gesture
       
   679 // inline ok in cpp file for a private member function
       
   680 // ----------------------------------------------------------------------------
       
   681 //
       
   682 inline void CGestureHelperImpl::AddSecondaryPointL( const TPointerEvent& aEvent )
       
   683     {
       
   684     User::LeaveIfError( AddSecondaryPoint( aEvent ) );
       
   685     }
       
   686 
       
   687 // ----------------------------------------------------------------------------
       
   688 // Add a point to the sequence of points that together make up the gesture
       
   689 // inline ok in cpp file for a private member function
       
   690 // ----------------------------------------------------------------------------
       
   691 //
       
   692 inline TInt CGestureHelperImpl::AddSecondaryPoint( const TPointerEvent& aEvent )
       
   693     {
       
   694     return iGesture->AddSecondaryPoint( Position ( aEvent ) );
       
   695     }
       
   696 
       
   697 // ----------------------------------------------------------------------------
       
   698 // StartHoldingTimer
       
   699 // ----------------------------------------------------------------------------
       
   700 //
       
   701 void CGestureHelperImpl::StartHoldingTimer( const TPointerEvent& aNewEvent )
       
   702     {
       
   703     if ( !( iGesture->IsHolding() ||
       
   704             iGesture->IsNearHoldingPoint( Position( aNewEvent ) ) ) )
       
   705         {
       
   706         // restart hold timer, since pointer has moved
       
   707         iHoldingTimer->Start();
       
   708         // Remember the point in which holding was started
       
   709         iGesture->SetHoldingPoint();
       
   710         }
       
   711     }
       
   712 
       
   713 /** 
       
   714  * Helper function that calls ContinueHolding on the pointer to TGesture
       
   715  */
       
   716 static void ContinueHolding( TAny* aGesture )
       
   717     {
       
   718     static_cast< CGesture* >( aGesture )->ContinueHolding();
       
   719     }
       
   720 
       
   721 // ----------------------------------------------------------------------------
       
   722 // Add a point to the sequence of points that together make up the gesture
       
   723 // ----------------------------------------------------------------------------
       
   724 //
       
   725 void CGestureHelperImpl::StartHoldingL()
       
   726     {
       
   727     // hold & tap event is specifically filtered out. Use case: in list fast 
       
   728     // scrolling activation (e.g. enhanced coverflow), tap & hold should not
       
   729     // start fast scroll. In addition, after long tap on start position,
       
   730     // drag and drag & hold swiping should emit normal swipe and swipe&hold
       
   731     // events. Therefore, tap & hold is not supported.
       
   732     __ASSERT_DEBUG( !iGesture->IsTap() && !iPreviousTapGesture, Panic( EGesturePanicIllegalLogic ) );
       
   733     
       
   734     // holding has just started, and gesture code should be provided to client.
       
   735     // set gesture state so that it produces a gesture code (other than drag)
       
   736     iGesture->StartHolding();
       
   737     
       
   738     // create an item in the cleanup stack that will set the gesture state
       
   739     // to holding-was-started-earlier state. NotifyL may leave, but the
       
   740     // holding-was-started-earlier state must still be successfully set,
       
   741     // otherwise, the holding gesture code will be sent twice
       
   742     CleanupStack::PushL( TCleanupItem( &ContinueHolding, iGesture ) );
       
   743     
       
   744     EmitEventL( *iGesture );
       
   745     
       
   746     // set holding state to "post holding"
       
   747     CleanupStack::PopAndDestroy( iGesture );
       
   748     }
       
   749 
       
   750 // ----------------------------------------------------------------------------
       
   751 // RecyclePreviousTapGesture
       
   752 // ----------------------------------------------------------------------------
       
   753 //
       
   754 void CGestureHelperImpl::RecyclePreviousTapGesture( TAny* aSelf )
       
   755     {
       
   756     CGestureHelperImpl& self = *reinterpret_cast<CGestureHelperImpl*>( aSelf );
       
   757     self.RecycleGesture( self.iPreviousTapGesture );
       
   758     }
       
   759 
       
   760 // ----------------------------------------------------------------------------
       
   761 // Emit the remainder of the previous tap event (tap + released)
       
   762 // ----------------------------------------------------------------------------
       
   763 //
       
   764 void CGestureHelperImpl::EmitFirstTapEventL()
       
   765     {
       
   766     // when this function is called, a tap has turned out to _not_ be a double tap
       
   767     __ASSERT_DEBUG( IsDoubleTapEnabled(), Panic( EGesturePanicIllegalLogic ) );
       
   768     __ASSERT_DEBUG( iPreviousTapGesture, Panic( EGesturePanicIllegalLogic ) );
       
   769     
       
   770     iDoubleTapTimer->Cancel();
       
   771     
       
   772     // ensure previous tap gesture is reset even if client leaves
       
   773     CleanupStack::PushL( TCleanupItem( &RecyclePreviousTapGesture, this ) );
       
   774     
       
   775     CompleteAndEmitSingleTouchL( *iPreviousTapGesture );
       
   776     
       
   777     // recycle the emitted gesture 
       
   778     CleanupStack::PopAndDestroy( this ); 
       
   779     }
       
   780 
       
   781 // ----------------------------------------------------------------------------
       
   782 // EmitStartEventL
       
   783 // ----------------------------------------------------------------------------
       
   784 //
       
   785 void CGestureHelperImpl::EmitStartEventL( const CGesture& aGesture )    
       
   786     {
       
   787     CGesture* startGesture = aGesture.AsStartEventLC();
       
   788     EmitEventL( *startGesture );
       
   789     CleanupStack::PopAndDestroy( startGesture );    
       
   790     }
       
   791     
       
   792 // ----------------------------------------------------------------------------
       
   793 // EmitCompletionEvents for single touch
       
   794 // ----------------------------------------------------------------------------
       
   795 //
       
   796 void CGestureHelperImpl::CompleteAndEmitSingleTouchL( CGesture& aGesture )
       
   797     {
       
   798     aGesture.SetSingleTouchComplete();
       
   799     // send gesture code if holding has not been started. If holding has 
       
   800     // been started, client has already received a "hold swipe left" e.g. event, in which
       
   801     // case don't another "swipe left" event
       
   802     if ( !aGesture.IsHolding() )
       
   803         {
       
   804         // if client leaves, the state is automatically reset.
       
   805         // In this case the client will not get the released event
       
   806         EmitEventL( aGesture ); 
       
   807         }
       
   808     // send an event that stylus was lifted
       
   809     aGesture.SetSingleTouchReleased();
       
   810     EmitEventL( aGesture ); 
       
   811     }
       
   812  
       
   813 // ----------------------------------------------------------------------------
       
   814 // EmitCompletionEvents for double touch
       
   815 // ----------------------------------------------------------------------------
       
   816 //
       
   817 void CGestureHelperImpl::CompleteAndEmitDoubleTouchL( CGesture& aGesture )
       
   818     {
       
   819     aGesture.SetMultiTouchComplete();
       
   820     if ( aGesture.IsPinch() )
       
   821         {
       
   822         // emit the pinch event to client
       
   823         EmitEventL( aGesture );
       
   824         }
       
   825     // send an event that stylus was lifted
       
   826     aGesture.SetMultiTouchReleased();
       
   827     EmitEventL( aGesture ); 
       
   828     }
       
   829 
       
   830 // ----------------------------------------------------------------------------
       
   831 // EmitCancelEventL
       
   832 // ----------------------------------------------------------------------------
       
   833 //
       
   834 void CGestureHelperImpl::EmitCancelEventL()
       
   835     {
       
   836     iDoubleTapTimer->Cancel();
       
   837 
       
   838     // ensure previous tap gesture is reset even if client leaves
       
   839     CleanupStack::PushL( TCleanupItem( &RecyclePreviousTapGesture, this ) );
       
   840 
       
   841     CGesture& gestureToCancel = iPreviousTapGesture ? *iPreviousTapGesture : *iGesture;
       
   842     gestureToCancel.SetCancelled();
       
   843     EmitEventL( gestureToCancel );
       
   844     
       
   845     // recycle the emitted gesture 
       
   846     CleanupStack::PopAndDestroy( this ); 
       
   847     }
       
   848 
       
   849 // ----------------------------------------------------------------------------
       
   850 // Notify observer
       
   851 // ----------------------------------------------------------------------------
       
   852 //
       
   853 void CGestureHelperImpl::EmitEventL( const CGesture& aGesture )
       
   854     {
       
   855     // iPoints array must have content when this function is called
       
   856     iObserver->HandleGestureL( aGesture );
       
   857     }
       
   858 
       
   859 // ----------------------------------------------------------------------------
       
   860 // Return a fresh gesture from the gesture pool (pool of one gesture)
       
   861 // ----------------------------------------------------------------------------
       
   862 //
       
   863 CGesture* CGestureHelperImpl::NewGesture()
       
   864     {
       
   865     __ASSERT_DEBUG( iUnusedGesture, Panic( EGesturePanicIllegalLogic ) ); // pool should no be empty
       
   866     iUnusedGesture->Reset();
       
   867     CGesture* freshGesture = iUnusedGesture;
       
   868     iUnusedGesture = NULL;
       
   869     return freshGesture;
       
   870     }
       
   871 
       
   872 // ----------------------------------------------------------------------------
       
   873 // Return a fresh gesture from the gesture pool (pool of one gesture)
       
   874 // ----------------------------------------------------------------------------
       
   875 //
       
   876 void CGestureHelperImpl::RecycleGesture( CGesture*& aGesturePointer )
       
   877     {
       
   878     // only one object fits into the pool, and that should currently be enough
       
   879     // one pointer must be null, one non-null
       
   880     __ASSERT_DEBUG( !iUnusedGesture != !aGesturePointer, Panic( EGesturePanicIllegalLogic ) );
       
   881     if ( aGesturePointer )
       
   882         {
       
   883         iUnusedGesture = aGesturePointer;
       
   884         aGesturePointer = NULL;
       
   885         }
       
   886     }
       
   887 
       
   888 // ----------------------------------------------------------------------------
       
   889 // AddObserver
       
   890 // ----------------------------------------------------------------------------
       
   891 //
       
   892 void CGestureHelperImpl::AddObserver(MGestureObserver* aObserver)
       
   893     {
       
   894     iObserver = aObserver;
       
   895     }
       
   896 	
       
   897 // end of file
       
   898