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