mulwidgets/gesturehelper/src/gesturehelperimpl.cpp
branchRCL_3
changeset 26 0e9bb658ef58
equal deleted inserted replaced
25:4ea6f81c838a 26:0e9bb658ef58
       
     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             if( iPointerCount == 0 && pointerNumber == 1)
       
   279                 {
       
   280                 return EFalse;                
       
   281                 }        
       
   282             else if( iPointerCount == 1 )
       
   283                 {
       
   284                 if(iCurrentPointer == pointerNumber )
       
   285                     {
       
   286                     TRAP_IGNORE( EmitCancelEventL() );
       
   287                     Reset();
       
   288                     }
       
   289                 }
       
   290             else if( iPointerCount == 2 )
       
   291                 {
       
   292                 // This case is similar to reciving a pointer up on the pointer
       
   293                 // on which the second down is recieved. We reset all the earlier points
       
   294                 // recieved on this pointer because we assume that some pointer up got
       
   295                 // missed in between.
       
   296             
       
   297                 // if pointer count is already 2, then reset the array of pointer for 
       
   298                 // which a down event is recieved, and continue handling in normal way
       
   299                 // Fix for error crash in photos fullscreen
       
   300                 // Like above if you reset the pointer array for which the down event
       
   301                 // is recieved the second time then in thecase of, 0 down, 1 down, 0 down
       
   302                 // iPoints will be null.
       
   303                 // Here whenever reseting it to single pointer havndling, always iPoints should have
       
   304                 // the data. Hence the first parameter should always be true.
       
   305                 // Fix is iGesture->ResetToLastPoint(pointerNumber != 0,pointerNumber != 0);
       
   306                 // is changed to iGesture->ResetToLastPoint( ETrue,pointerNumber != 0);
       
   307                 iPointerCount = 1; 
       
   308                 iCurrentPointer = pointerNumber == 0 ? 1 : 0;
       
   309                 iGesture->ResetToLastPoint( ETrue,pointerNumber != 0);
       
   310                 iGesture->SetSingleTouchActive();
       
   311                 }
       
   312 
       
   313             if(iPointerCount == 0)
       
   314                 {
       
   315                 iPointerCount = 1;
       
   316                 iCurrentPointer = pointerNumber;
       
   317                 // single touch gesture start
       
   318                 iGesture->SetSingleTouchActive();
       
   319                 HandleSinglePointerEventL( aEvent, aVisual );
       
   320                 }
       
   321             else if(iPointerCount == 1)
       
   322                 {              
       
   323                 iPointerCount = 2;
       
   324                 iCurrentPointer = -1;
       
   325                 // add the last point of the single touch event
       
   326                 // to first array of gesture
       
   327                 iGesture->ResetToLastPoint(pointerNumber != 0,ETrue);
       
   328                 iGesture->SetMultiTouchActive();
       
   329                 // multi touch gesture start
       
   330                 HandleMultiplePointerEventL( aEvent, pointerNumber );
       
   331                 }
       
   332             else
       
   333                 {
       
   334                 
       
   335                 }
       
   336             break;
       
   337             
       
   338         case TPointerEvent::EDrag:
       
   339             if(iPointerCount == 1)
       
   340                 {
       
   341                 if(pointerNumber == iCurrentPointer)
       
   342                     {
       
   343                     HandleSinglePointerEventL( aEvent, aVisual );
       
   344                     }
       
   345                 else
       
   346                     {
       
   347                     // only the drags on the current pointer should be considered.
       
   348                     return EFalse;
       
   349                     }
       
   350                 
       
   351                 }
       
   352             else if(iPointerCount == 2)
       
   353                 {
       
   354                 HandleMultiplePointerEventL( aEvent, pointerNumber );
       
   355                 }
       
   356             else
       
   357                 {
       
   358                 // nothing to be done
       
   359                 }
       
   360             break;
       
   361             
       
   362         case TPointerEvent::EButton1Up:
       
   363             if(iPointerCount == 2)
       
   364                 { 
       
   365                 // multi touch gesture complete
       
   366                 HandleMultiplePointerEventL( aEvent, pointerNumber );
       
   367                 // should the pointer count decrese first n then
       
   368                 // handling of event or otherwise
       
   369                 iPointerCount = 1;    
       
   370                 iCurrentPointer = pointerNumber == 0 ? 1 : 0;
       
   371                 iGesture->ResetToLastPoint(ETrue,pointerNumber != 0);
       
   372                 iGesture->SetSingleTouchActive();
       
   373                 }
       
   374             else if( iPointerCount == 1 )
       
   375                 {
       
   376                 iPointerCount = 0;
       
   377                 iCurrentPointer = -1;
       
   378                 // single touch gesture complete
       
   379                 HandleSinglePointerEventL( aEvent, aVisual ); 
       
   380                 }
       
   381             else
       
   382                 {
       
   383                 // nothing to be done
       
   384                 }
       
   385             break;
       
   386             
       
   387         default:
       
   388             break;
       
   389         }
       
   390     return ETrue; // consume
       
   391     }
       
   392 // ----------------------------------------------------------------------------
       
   393 // Handle a pointer event
       
   394 // ----------------------------------------------------------------------------
       
   395 //
       
   396 TBool CGestureHelperImpl::HandleSinglePointerEventL( const TPointerEvent& aEvent,
       
   397         CAlfVisual* aVisual )
       
   398     {  
       
   399     switch ( aEvent.iType )
       
   400         {
       
   401         case TPointerEvent::EButton1Down:
       
   402             // If no up event was received during previous gesture, cancel 
       
   403             // previous event and reset state
       
   404             if ( !IsIdle() )
       
   405                 {
       
   406                 // ambiguous what is the right thing when "cancel" event leaves
       
   407                 // and "start" does not. Leaving for cancel *after* "start" could 
       
   408                 // be unexpected to client, as client would have handled start 
       
   409                 // event successfully. Assume that leaving upon cancellation 
       
   410                 // can be ignored.
       
   411                 TRAP_IGNORE( EmitCancelEventL() );
       
   412                 Reset();  
       
   413                 }
       
   414             // as long as down event of a double tap comes within the double 
       
   415             // tap timeout, it does not matter how long the user keeps the finger
       
   416             // pressed for the gesture to be a double tap. Therefore, cancel
       
   417             // the timeout, as it is no longer relevant. (Of course, this call
       
   418             // will only do something if the timer is actually running, which
       
   419             // is only if received a tap event very recently.)
       
   420             iDoubleTapTimer->Cancel();
       
   421             // adding the first point implicitly makes the state "not idle"
       
   422             AddPointL( aEvent );
       
   423             iGesture->SetVisual( aVisual );
       
   424             // if pointer capturer leaves, the remaining pointer events will
       
   425             // not be captured if stylus is dragged outside the capturing visual
       
   426             // an error note will be shown, so the potential problem is irrelevant,
       
   427             // assuming client does not (incorrectly) block the leave from reaching 
       
   428             // the framework
       
   429             iPointerCapturer->StartL();
       
   430             // Delay emitting a down event _until_ it is known that this beginning 
       
   431             // gesture is _not_ the second tap of a double tap event.
       
   432             // iPreviousTapGesture is only non-null if very recently received 
       
   433             // a tap event and double tap is enabled. 
       
   434             if ( !iPreviousTapGesture )
       
   435                 {
       
   436                 EmitEventL( *iGesture );
       
   437                 }
       
   438             // else delay emitting an event, as it might be a double tap 
       
   439             // (allow the second tap of a double tap to be anywhere, so don't check
       
   440             // for start pos here)
       
   441             break;
       
   442             
       
   443         case TPointerEvent::EDrag:
       
   444             // While stylus down, the same event is received repeatedly
       
   445             // even if stylus does not move. Filter out by checking if point 
       
   446             // is the same as the latest point
       
   447             if ( !iGesture->IsLatestPoint( Position( aEvent ) ) )
       
   448                 {
       
   449                 AddPointL( aEvent );
       
   450 
       
   451                 // as long as the starting gesture is seen as a tap, do not emit any
       
   452                 // drag events
       
   453                 if ( !iGesture->IsTap() )
       
   454                     {
       
   455                     // if there is a previous tap gesture, getting drag events means that
       
   456                     // the previous gesture is not a double tap. So emit the previous gesture.
       
   457                     if ( iPreviousTapGesture )
       
   458                         {
       
   459                         // this is a second gesture after a tap (double tap is enabled)
       
   460                         EmitFirstTapEventL();
       
   461                         // emit down event for the current gesture (since its down was delayed, until
       
   462                         // it was to be known if the event is a tap. That is known now.)
       
   463                         EmitStartEventL( *iGesture );
       
   464                         }
       
   465                     // restart holding timer every time the current stylus pos changes
       
   466                     StartHoldingTimer( aEvent );
       
   467                     // emit the drag event to client
       
   468                     EmitEventL( *iGesture );
       
   469                     }
       
   470                 // else: do not emit drag events until it is known that the gesture is not a tap
       
   471                 // (or the second tap of double tap)
       
   472                 }
       
   473             break;
       
   474 
       
   475         case TPointerEvent::EButton1Up:
       
   476             // reset in case the down event for next gesture is not received for a reason 
       
   477             // in client, and instead drag or up events are received. 
       
   478             // reset via cleanup stack to ensure Reset is run even if
       
   479             // observer leaves
       
   480             CleanupStack::PushL( TCleanupItem( &ResetHelper, this ) );
       
   481             // if adding of the point fails, notify client with a 
       
   482             // cancelled event. It would be wrong to send another
       
   483             // gesture code when the up point is not known
       
   484             if ( KErrNone == AddPoint( aEvent ) )
       
   485                 {
       
   486                 // if the gesture is a tap, the gesture is either the first tap of a _potential_
       
   487                 // double tap, or the second tap of a double tap
       
   488                 if ( iDoubleTapTimer->IsEnabled() && iGesture->IsTap() )
       
   489                     {
       
   490                     __ASSERT_DEBUG( !iGesture->IsHolding(), Panic( EGesturePanicIllegalLogic ) );
       
   491                     if ( !iPreviousTapGesture )
       
   492                         {
       
   493                         // First tap. Delay emitting its code evemt and released events until it is known
       
   494                         // whether the tap is a double tap
       
   495                         iPreviousTapGesture = iGesture;
       
   496                         iGesture = NewGesture();
       
   497                         iDoubleTapTimer->Start(); 
       
   498                         }
       
   499                     else
       
   500                         {
       
   501                         // This is a second tap of a double tap. Do not emit anything for the second
       
   502                         // tap. Only down event has been emitted for the first tap. Emit the code 
       
   503                         // event (double tap) and released for the first tap.
       
   504                         iPreviousTapGesture->SetDoubleTap();
       
   505                         EmitFirstTapEventL();
       
   506                         }
       
   507                     }
       
   508                 else 
       
   509                     {
       
   510                     // modified iGesture to be "released"
       
   511                     CompleteAndEmitSingleTouchL( *iGesture );
       
   512                     }
       
   513                 }
       
   514             else
       
   515                 { // adding a point failed
       
   516                 EmitCancelEventL();
       
   517                 }
       
   518             // reset state
       
   519             CleanupStack::PopAndDestroy( this ); 
       
   520             break;
       
   521             
       
   522         default:
       
   523             break;
       
   524         }
       
   525     return ETrue; // consume
       
   526     }
       
   527 
       
   528 // ----------------------------------------------------------------------------
       
   529 // Handle multiple pointer events
       
   530 // ----------------------------------------------------------------------------
       
   531 //
       
   532 TBool CGestureHelperImpl::HandleMultiplePointerEventL( const TPointerEvent& aEvent,
       
   533        const TInt aPointerNumber )
       
   534     { 
       
   535     switch ( aEvent.iType )
       
   536         {
       
   537         case TPointerEvent::EButton1Down:
       
   538             // adding the first point implicitly makes the state "not idle"
       
   539             AddMultiTouchPointsL( aEvent, aPointerNumber);
       
   540             EmitEventL( *iGesture );
       
   541             break;
       
   542             
       
   543         case TPointerEvent::EDrag:
       
   544             // While stylus down, the same event is received repeatedly
       
   545             // even if stylus does not move. Filter out by checking if point 
       
   546             // is the same as the latest point
       
   547             if( AddMultiTouchPointsL(aEvent, aPointerNumber ))
       
   548                 {
       
   549                 // as long as the starting gesture is seen as a tap, do not emit any
       
   550                 // drag events
       
   551                 if ( iGesture->IsPinch() )
       
   552                     {
       
   553                     // emit the pinch event to client
       
   554                     EmitEventL( *iGesture );
       
   555                     }
       
   556                 // else: do not emit any events to the client               
       
   557                 }
       
   558 
       
   559             
       
   560             break;
       
   561 
       
   562         case TPointerEvent::EButton1Up:
       
   563                         
       
   564             // if adding of the point fails, notify client with a 
       
   565             // cancelled event. It would be wrong to send another
       
   566             // gesture code when the up point is not known
       
   567             AddMultiTouchPointsL(aEvent, aPointerNumber );
       
   568             CompleteAndEmitDoubleTouchL( *iGesture );
       
   569 
       
   570             break;
       
   571             
       
   572         default:
       
   573             break;
       
   574         }   
       
   575     return ETrue; // consume
       
   576     }
       
   577 
       
   578 // ----------------------------------------------------------------------------
       
   579 // Validate AddMultiTouchPointsL events
       
   580 // Check if the point recieved is the repeavt event of previous point or a new point 
       
   581 // inline ok in cpp file for a private member function
       
   582 // ----------------------------------------------------------------------------
       
   583 //
       
   584 inline TBool CGestureHelperImpl::AddMultiTouchPointsL( const TPointerEvent& aEvent, const TInt aPointerNumber)
       
   585     {
       
   586     TBool pointAdded = EFalse;
       
   587     if ( aPointerNumber > 0 )
       
   588         {
       
   589         if ( !iGesture->IsLatestSecondaryPoint( Position( aEvent ) ) )
       
   590             {
       
   591             AddSecondaryPointL( aEvent );
       
   592             pointAdded = ETrue;
       
   593             }                 
       
   594         }
       
   595     else
       
   596         {
       
   597         if ( !iGesture->IsLatestPoint( Position( aEvent ) ) )
       
   598             {
       
   599             AddPointL( aEvent );
       
   600             pointAdded = ETrue;
       
   601             }                
       
   602         }
       
   603     return pointAdded;
       
   604     }
       
   605 
       
   606 // ----------------------------------------------------------------------------
       
   607 // Check for Stray evnet
       
   608 // ----------------------------------------------------------------------------
       
   609 //
       
   610 TBool CGestureHelperImpl::StrayEvent( const TPointerEvent& aEvent ) const
       
   611     {
       
   612      //If we are recieving a button down on pointer 0 in pointer capturer then its a stray event
       
   613     // Dont consume it
       
   614     if ( aEvent.iType == TPointerEvent::EButton1Down && IsIdle( 0) )
       
   615         {
       
   616         return ETrue; // don't consume
       
   617         }  
       
   618 	return EFalse;  
       
   619     }
       
   620 // ----------------------------------------------------------------------------
       
   621 // Validate the events
       
   622 // is it a valid event or a stray pointer form some other visuals
       
   623 // inline ok in cpp file for a private member function
       
   624 // ----------------------------------------------------------------------------
       
   625 //
       
   626 inline TBool CGestureHelperImpl::ValidatePointer( const TPointerEvent& aEvent, const TInt aPointerNumber) const
       
   627     {
       
   628     // Check if received event is valid or not.
       
   629     // In practice, event is NOT valid in the following situations:
       
   630     //
       
   631     // 1. Pointer down event is received for pointer which is already down.
       
   632     // 2. Pointer up event is received for pointer which is already up.
       
   633     // 3. Pointer drag event is received for pointer which is not down.
       
   634     // 4. Pointer numbers other than 0 and 1. We are handling only 2 pointers.
       
   635     //
       
   636     // In these situations this function returns EFalse,
       
   637     // corresponding event is ignored and recognition continues as earlier.
       
   638     //
       
   639     
       
   640     // filter all the events for which the pointer number is less than 0
       
   641     // or greater than 1. we will handle only 2 pointer events.  
       
   642     if( aPointerNumber >= 2 || aPointerNumber < 0 )
       
   643         {
       
   644         return EFalse;
       
   645         }
       
   646         
       
   647     // filter out events that do not start with button down. It is a stray
       
   648     // event from another visual    
       
   649     TInt pointerTovalidate = aPointerNumber ;
       
   650     if( iPointerCount == 1 && aPointerNumber == 1)
       
   651 	    {
       
   652 	    pointerTovalidate = 0;
       
   653 	    }
       
   654     if ( aEvent.iType != TPointerEvent::EButton1Down && IsIdle( pointerTovalidate ) )
       
   655         {
       
   656         return EFalse; // don't consume
       
   657         }
       
   658 
       
   659     
       
   660     return ETrue;
       
   661     }
       
   662 
       
   663 // ----------------------------------------------------------------------------
       
   664 // Is the helper idle?
       
   665 // Checks whether any points are already added in the array corresponding
       
   666 // to the pointer number 
       
   667 // inline ok in cpp file for a private member function
       
   668 // ----------------------------------------------------------------------------
       
   669 //
       
   670 inline TBool CGestureHelperImpl::IsIdle( TBool aPointerNumber ) const
       
   671     {
       
   672     if( aPointerNumber == 0 )
       
   673         {
       
   674         return iGesture->IsEmpty();
       
   675         }
       
   676     else if( aPointerNumber == 1 )
       
   677         {
       
   678         return iGesture->IsMultiTouch();
       
   679         }
       
   680     return ETrue;
       
   681     }
       
   682 
       
   683 // ----------------------------------------------------------------------------
       
   684 // Add a point to the sequence of points that together make up the gesture
       
   685 // inline ok in cpp file for a private member function
       
   686 // ----------------------------------------------------------------------------
       
   687 //
       
   688 inline void CGestureHelperImpl::AddPointL( const TPointerEvent& aEvent )
       
   689     {
       
   690     User::LeaveIfError( AddPoint( aEvent ) );
       
   691     }
       
   692 
       
   693 // ----------------------------------------------------------------------------
       
   694 // Add a point to the sequence of points that together make up the gesture
       
   695 // inline ok in cpp file for a private member function
       
   696 // ----------------------------------------------------------------------------
       
   697 //
       
   698 inline TInt CGestureHelperImpl::AddPoint( const TPointerEvent& aEvent )
       
   699     {
       
   700     return iGesture->AddPoint( Position ( aEvent ) );
       
   701     }
       
   702 
       
   703 // ----------------------------------------------------------------------------
       
   704 // Add a point to the sequence of points that together make up the gesture
       
   705 // inline ok in cpp file for a private member function
       
   706 // ----------------------------------------------------------------------------
       
   707 //
       
   708 inline void CGestureHelperImpl::AddSecondaryPointL( const TPointerEvent& aEvent )
       
   709     {
       
   710     User::LeaveIfError( AddSecondaryPoint( aEvent ) );
       
   711     }
       
   712 
       
   713 // ----------------------------------------------------------------------------
       
   714 // Add a point to the sequence of points that together make up the gesture
       
   715 // inline ok in cpp file for a private member function
       
   716 // ----------------------------------------------------------------------------
       
   717 //
       
   718 inline TInt CGestureHelperImpl::AddSecondaryPoint( const TPointerEvent& aEvent )
       
   719     {
       
   720     return iGesture->AddSecondaryPoint( Position ( aEvent ) );
       
   721     }
       
   722 
       
   723 // ----------------------------------------------------------------------------
       
   724 // StartHoldingTimer
       
   725 // ----------------------------------------------------------------------------
       
   726 //
       
   727 void CGestureHelperImpl::StartHoldingTimer( const TPointerEvent& aNewEvent )
       
   728     {
       
   729     if ( !( iGesture->IsHolding() ||
       
   730             iGesture->IsNearHoldingPoint( Position( aNewEvent ) ) ) )
       
   731         {
       
   732         // restart hold timer, since pointer has moved
       
   733         iHoldingTimer->Start();
       
   734         // Remember the point in which holding was started
       
   735         iGesture->SetHoldingPoint();
       
   736         }
       
   737     }
       
   738 
       
   739 /** 
       
   740  * Helper function that calls ContinueHolding on the pointer to TGesture
       
   741  */
       
   742 static void ContinueHolding( TAny* aGesture )
       
   743     {
       
   744     static_cast< CGesture* >( aGesture )->ContinueHolding();
       
   745     }
       
   746 
       
   747 // ----------------------------------------------------------------------------
       
   748 // Add a point to the sequence of points that together make up the gesture
       
   749 // ----------------------------------------------------------------------------
       
   750 //
       
   751 void CGestureHelperImpl::StartHoldingL()
       
   752     {
       
   753     // hold & tap event is specifically filtered out. Use case: in list fast 
       
   754     // scrolling activation (e.g. enhanced coverflow), tap & hold should not
       
   755     // start fast scroll. In addition, after long tap on start position,
       
   756     // drag and drag & hold swiping should emit normal swipe and swipe&hold
       
   757     // events. Therefore, tap & hold is not supported.
       
   758     __ASSERT_DEBUG( !iGesture->IsTap() && !iPreviousTapGesture, Panic( EGesturePanicIllegalLogic ) );
       
   759     
       
   760     // holding has just started, and gesture code should be provided to client.
       
   761     // set gesture state so that it produces a gesture code (other than drag)
       
   762     iGesture->StartHolding();
       
   763     
       
   764     // create an item in the cleanup stack that will set the gesture state
       
   765     // to holding-was-started-earlier state. NotifyL may leave, but the
       
   766     // holding-was-started-earlier state must still be successfully set,
       
   767     // otherwise, the holding gesture code will be sent twice
       
   768     CleanupStack::PushL( TCleanupItem( &ContinueHolding, iGesture ) );
       
   769     
       
   770     EmitEventL( *iGesture );
       
   771     
       
   772     // set holding state to "post holding"
       
   773     CleanupStack::PopAndDestroy( iGesture );
       
   774     }
       
   775 
       
   776 // ----------------------------------------------------------------------------
       
   777 // RecyclePreviousTapGesture
       
   778 // ----------------------------------------------------------------------------
       
   779 //
       
   780 void CGestureHelperImpl::RecyclePreviousTapGesture( TAny* aSelf )
       
   781     {
       
   782     CGestureHelperImpl& self = *reinterpret_cast<CGestureHelperImpl*>( aSelf );
       
   783     self.RecycleGesture( self.iPreviousTapGesture );
       
   784     }
       
   785 
       
   786 // ----------------------------------------------------------------------------
       
   787 // Emit the remainder of the previous tap event (tap + released)
       
   788 // ----------------------------------------------------------------------------
       
   789 //
       
   790 void CGestureHelperImpl::EmitFirstTapEventL()
       
   791     {
       
   792     // when this function is called, a tap has turned out to _not_ be a double tap
       
   793     __ASSERT_DEBUG( IsDoubleTapEnabled(), Panic( EGesturePanicIllegalLogic ) );
       
   794     __ASSERT_DEBUG( iPreviousTapGesture, Panic( EGesturePanicIllegalLogic ) );
       
   795     
       
   796     iDoubleTapTimer->Cancel();
       
   797     
       
   798     // ensure previous tap gesture is reset even if client leaves
       
   799     CleanupStack::PushL( TCleanupItem( &RecyclePreviousTapGesture, this ) );
       
   800     
       
   801     CompleteAndEmitSingleTouchL( *iPreviousTapGesture );
       
   802     
       
   803     // recycle the emitted gesture 
       
   804     CleanupStack::PopAndDestroy( this ); 
       
   805     }
       
   806 
       
   807 // ----------------------------------------------------------------------------
       
   808 // EmitStartEventL
       
   809 // ----------------------------------------------------------------------------
       
   810 //
       
   811 void CGestureHelperImpl::EmitStartEventL( const CGesture& aGesture )    
       
   812     {
       
   813     CGesture* startGesture = aGesture.AsStartEventLC();
       
   814     EmitEventL( *startGesture );
       
   815     CleanupStack::PopAndDestroy( startGesture );    
       
   816     }
       
   817     
       
   818 // ----------------------------------------------------------------------------
       
   819 // EmitCompletionEvents for single touch
       
   820 // ----------------------------------------------------------------------------
       
   821 //
       
   822 void CGestureHelperImpl::CompleteAndEmitSingleTouchL( CGesture& aGesture )
       
   823     {
       
   824     aGesture.SetSingleTouchComplete();
       
   825     // send gesture code if holding has not been started. If holding has 
       
   826     // been started, client has already received a "hold swipe left" e.g. event, in which
       
   827     // case don't another "swipe left" event
       
   828     if ( !aGesture.IsHolding() )
       
   829         {
       
   830         // if client leaves, the state is automatically reset.
       
   831         // In this case the client will not get the released event
       
   832         EmitEventL( aGesture ); 
       
   833         }
       
   834     // send an event that stylus was lifted
       
   835     aGesture.SetSingleTouchReleased();
       
   836     EmitEventL( aGesture ); 
       
   837     }
       
   838  
       
   839 // ----------------------------------------------------------------------------
       
   840 // EmitCompletionEvents for double touch
       
   841 // ----------------------------------------------------------------------------
       
   842 //
       
   843 void CGestureHelperImpl::CompleteAndEmitDoubleTouchL( CGesture& aGesture )
       
   844     {
       
   845     aGesture.SetMultiTouchComplete();
       
   846     if ( aGesture.IsPinch() )
       
   847         {
       
   848         // emit the pinch event to client
       
   849         EmitEventL( aGesture );
       
   850         }
       
   851     // send an event that stylus was lifted
       
   852     aGesture.SetMultiTouchReleased();
       
   853     EmitEventL( aGesture ); 
       
   854     }
       
   855 
       
   856 // ----------------------------------------------------------------------------
       
   857 // EmitCancelEventL
       
   858 // ----------------------------------------------------------------------------
       
   859 //
       
   860 void CGestureHelperImpl::EmitCancelEventL()
       
   861     {
       
   862     iDoubleTapTimer->Cancel();
       
   863 
       
   864     // ensure previous tap gesture is reset even if client leaves
       
   865     CleanupStack::PushL( TCleanupItem( &RecyclePreviousTapGesture, this ) );
       
   866 
       
   867     CGesture& gestureToCancel = iPreviousTapGesture ? *iPreviousTapGesture : *iGesture;
       
   868     gestureToCancel.SetCancelled();
       
   869     EmitEventL( gestureToCancel );
       
   870     
       
   871     // recycle the emitted gesture 
       
   872     CleanupStack::PopAndDestroy( this ); 
       
   873     }
       
   874 
       
   875 // ----------------------------------------------------------------------------
       
   876 // Notify observer
       
   877 // ----------------------------------------------------------------------------
       
   878 //
       
   879 void CGestureHelperImpl::EmitEventL( const CGesture& aGesture )
       
   880     {
       
   881     // iPoints array must have content when this function is called
       
   882     iObserver->HandleGestureL( aGesture );
       
   883     }
       
   884 
       
   885 // ----------------------------------------------------------------------------
       
   886 // Return a fresh gesture from the gesture pool (pool of one gesture)
       
   887 // ----------------------------------------------------------------------------
       
   888 //
       
   889 CGesture* CGestureHelperImpl::NewGesture()
       
   890     {
       
   891     __ASSERT_DEBUG( iUnusedGesture, Panic( EGesturePanicIllegalLogic ) ); // pool should no be empty
       
   892     iUnusedGesture->Reset();
       
   893     CGesture* freshGesture = iUnusedGesture;
       
   894     iUnusedGesture = NULL;
       
   895     return freshGesture;
       
   896     }
       
   897 
       
   898 // ----------------------------------------------------------------------------
       
   899 // Return a fresh gesture from the gesture pool (pool of one gesture)
       
   900 // ----------------------------------------------------------------------------
       
   901 //
       
   902 void CGestureHelperImpl::RecycleGesture( CGesture*& aGesturePointer )
       
   903     {
       
   904     // only one object fits into the pool, and that should currently be enough
       
   905     // one pointer must be null, one non-null
       
   906     __ASSERT_DEBUG( !iUnusedGesture != !aGesturePointer, Panic( EGesturePanicIllegalLogic ) );
       
   907     if ( aGesturePointer )
       
   908         {
       
   909         iUnusedGesture = aGesturePointer;
       
   910         aGesturePointer = NULL;
       
   911         }
       
   912     }
       
   913 
       
   914 // ----------------------------------------------------------------------------
       
   915 // AddObserver
       
   916 // ----------------------------------------------------------------------------
       
   917 //
       
   918 void CGestureHelperImpl::AddObserver(MGestureObserver* aObserver)
       
   919     {
       
   920     iObserver = aObserver;
       
   921     }
       
   922 	
       
   923 // end of file
       
   924