webengine/webkitutils/stmgesturefw/src/tapgesturerecogniser.cpp
changeset 28 d39add9822e2
child 47 e1bea15f9a39
equal deleted inserted replaced
27:6297cdf66332 28:d39add9822e2
       
     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 the License "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 "GenericSimpleGesture.h"
       
    19 #include "TapGestureRecogniser.h"
       
    20 #include "rt_uievent.h"
       
    21 #include "filelogger.h"
       
    22 
       
    23 using namespace stmGesture ;
       
    24 
       
    25 /* some utility functions, are these things not provided by the OS? */
       
    26 const TInt KFingerSize_mm = 8;
       
    27 const TInt KTwipsInInch = 1440;
       
    28 const TReal KTwipsInMm = 56.7;
       
    29 
       
    30 long Twips2Pixels(long twips)
       
    31 {
       
    32     CWsScreenDevice* screen = CCoeEnv::Static()->ScreenDevice();
       
    33     TZoomFactor deviceMap(screen);
       
    34     deviceMap.SetZoomFactor(TZoomFactor::EZoomOneToOne);
       
    35     long px = deviceMap.VerticalTwipsToPixels(twips); //assuming that vertical
       
    36     return px; //the same as horizontal
       
    37 }
       
    38 
       
    39 long Mm2Pixels(long mm)
       
    40 {
       
    41     return Twips2Pixels(mm * KTwipsInMm);
       
    42 }
       
    43 
       
    44 long Inches2Pixels(double inches)
       
    45 {
       
    46     return Twips2Pixels(inches * KTwipsInInch);
       
    47 }
       
    48 
       
    49 TRect ToleranceRect(const TPoint& aCenterPoint, int size)
       
    50 {
       
    51     long toleranceLength = Mm2Pixels(KFingerSize_mm) / 2;
       
    52     TRect toleranceRect(aCenterPoint, TSize());
       
    53     toleranceRect.Shrink(-size, -size);
       
    54     return toleranceRect;
       
    55 }
       
    56 
       
    57 CTapGestureRecogniser* CTapGestureRecogniser::NewL(MGestureListener* aListener)
       
    58 {
       
    59     CTapGestureRecogniser* self = new (ELeave) CTapGestureRecogniser(aListener) ;
       
    60     CleanupStack::PushL(self);
       
    61     self->ConstructL(); // construct base class
       
    62     CActiveScheduler::Add(self);
       
    63     CleanupStack::Pop(self);
       
    64     return self;
       
    65 }
       
    66 
       
    67 CTapGestureRecogniser::CTapGestureRecogniser(MGestureListener* aListener) :
       
    68     CTimer(EPriorityRealTime - 1)
       
    69 {
       
    70     m_powner = aListener->getOwner() ;
       
    71     // if a listener is given here, then it is both tap and doubletap listener
       
    72     if (aListener)
       
    73     {
       
    74         addTapListener(aListener, m_powner) ;
       
    75         addDoubleTapListener(aListener, m_powner) ;
       
    76     }
       
    77     m_waitingforsecondtap = false ;
       
    78     m_gestureEnabled = true ;
       
    79     m_ignorefirst = true ;  // by default ignore the first tap
       
    80 }
       
    81 
       
    82 CTapGestureRecogniser::~CTapGestureRecogniser()
       
    83 {
       
    84     Cancel();
       
    85     m_tapListeners.Reset() ;
       
    86     m_tapListenerWindows.Reset() ;
       
    87     m_doubleTapListeners.Reset() ;
       
    88     m_doubleTapListenerWindows.Reset() ;
       
    89 
       
    90 }
       
    91 
       
    92 TGestureRecognitionState CTapGestureRecogniser::recognise(int numOfActiveStreams,
       
    93         MGestureEngineIf* pge)
       
    94 {
       
    95     TGestureRecognitionState state = ENotMyGesture;
       
    96     // Check if we are enabled or not
       
    97     if (!m_gestureEnabled) return state ;
       
    98 
       
    99     // Look at the events to see if it looks like a tap or double tap
       
   100     if (numOfActiveStreams == 1)
       
   101     {
       
   102         // Then look at the event stream, it has to be tap and release
       
   103         const stmUiEventEngine::MUiEvent* puie = pge->getUiEvents(0);
       
   104         if (!puie) return state;
       
   105         
       
   106         int countOfEvents = puie->countOfEvents() ;
       
   107         stmUiEventEngine::TUiEventCode eventCode = puie->Code() ;
       
   108 
       
   109         if (m_loggingenabled)
       
   110         {
       
   111             LOGARG("CTapGestureRecogniser: %d num %d code %d", eventCode, countOfEvents, eventCode);
       
   112         }
       
   113         if (countOfEvents == 2) // Do we have touch and release in the stream, check if there are two events
       
   114         {
       
   115             // Then look at the events to see if they are suitable for us
       
   116             if (eventCode == stmUiEventEngine::ERelease) // The last one is release
       
   117             {
       
   118                 stmUiEventEngine::MUiEvent* puieFirst = puie->previousEvent();
       
   119                 
       
   120                 if(puieFirst)
       
   121                     eventCode = puieFirst->Code();
       
   122                 else 
       
   123                     return state; 
       
   124                 
       
   125                 if (eventCode == stmUiEventEngine::ETouch)   // is the first one ETouch
       
   126                 {
       
   127                     if (m_loggingenabled)
       
   128                     {
       
   129                         LOGARG("CTapGestureRecogniser: 0x%x TAP: num %d code %d", 
       
   130                                 this, countOfEvents, eventCode);
       
   131                     }
       
   132                     // It is tap gesture in our window, handle it
       
   133                     state = EGestureActive;
       
   134 
       
   135                     CCoeControl* target = (CCoeControl*)puie->Target();
       
   136 
       
   137                     if (m_waitingforsecondtap)
       
   138                     {
       
   139                         m_waitingforsecondtap = false ;
       
   140                         if (m_loggingenabled)
       
   141                         {
       
   142                             LOGARG("CTapGestureRecogniser: 0x%x second tap: num %d code %d", 
       
   143                                     this, countOfEvents, eventCode);
       
   144                         }
       
   145 
       
   146                         Cancel() ;  // The timer
       
   147 
       
   148                         const TPoint& secondPoint = puieFirst->CurrentXY() ;
       
   149                         if (isSecondTapClose(secondPoint, m_firstTapXY))
       
   150                         {
       
   151                             // Taps were close enough together, so issue a doubletap
       
   152 
       
   153                             // Call the listener of the current window to inform that a doubletap has occurred...
       
   154                             TInt inx = m_doubleTapListenerWindows.Find(target) ;
       
   155                             if (inx == KErrNotFound)
       
   156                             {
       
   157                                 // the second tap hit a window with no listener,
       
   158                                 // check if the first one has a listener
       
   159                                 inx = m_doubleTapListenerWindows.Find(m_firstTapTarget) ;
       
   160                             }
       
   161                             // not found, check if the parent is in the listener list
       
   162                             if (inx == KErrNotFound)
       
   163                             {
       
   164                                 CCoeControl* pc = target ;
       
   165                                 while (pc)
       
   166                                 {
       
   167                                     pc = pc->Parent() ;
       
   168                                     inx = m_doubleTapListenerWindows.Find(pc) ;
       
   169                                     if (inx != KErrNotFound) break ;
       
   170                                 }
       
   171                             }
       
   172                             if (inx != KErrNotFound)
       
   173                             {
       
   174                                 // Tap gesture
       
   175                                 stmGesture::TGenericSimpleGesture pgest(
       
   176                                     stmGesture::EGestureUidDoubleTap, 
       
   177                                     secondPoint, stmGesture::ETapTypeDouble, puie) ;
       
   178                                 MGestureListener* plistener = m_doubleTapListeners[inx] ;
       
   179                                 plistener->gestureEnter(pgest) ;
       
   180                             }
       
   181                         }
       
   182                         else
       
   183                         {
       
   184                             // Second tap is too far away, generate just tap
       
   185                             // and if configured, also the fist tap is generated
       
   186                             if (!m_ignorefirst)
       
   187                             {
       
   188                                 // do not ignore the first tap, so issue it now using the stored location
       
   189                                 // Call the listener to inform that a Tap has occurred, if there was a listener in that window
       
   190                                 TInt inx = m_tapListenerWindows.Find(m_firstTapTarget) ;
       
   191                                 if (inx != KErrNotFound)    // check if the listener exists
       
   192                                 {
       
   193                                     stmGesture::TGenericSimpleGesture pgest(
       
   194                                         stmGesture::EGestureUidTap, puieFirst->CurrentXY(), 
       
   195                                         stmGesture::ETapTypeSingle, puieFirst) ; // TODO: speed is 0?
       
   196                                     MGestureListener* plistener = m_tapListeners[inx] ;
       
   197                                     plistener->gestureEnter(pgest) ;
       
   198                                 }
       
   199                             }
       
   200                             // generate a tap at the current location, if there is a listener for it
       
   201                             TInt inx = m_tapListenerWindows.Find(target) ;
       
   202                             if (inx != KErrNotFound)
       
   203                             {
       
   204                                 stmGesture::TGenericSimpleGesture pgest(
       
   205                                     stmGesture::EGestureUidTap, puie->CurrentXY(), 
       
   206                                     stmGesture::ETapTypeSingle, puie) ; // TODO: speed is 0?
       
   207                                 MGestureListener* plistener = m_tapListeners[inx] ;
       
   208                                 plistener->gestureEnter(pgest) ;
       
   209                             }
       
   210                         }
       
   211                     }
       
   212                     else
       
   213                     {
       
   214                         m_firstTapXY = puieFirst->CurrentXY() ;
       
   215                         m_firstTapTarget = target ;
       
   216                         m_firstTapSpeedX = puie->speedX() ;
       
   217                         m_firstTapSpeedY = puie->speedY() ;
       
   218                         // This was the first tap, start the timer...
       
   219                         m_waitingforsecondtap = true ;
       
   220                         if (m_loggingenabled)
       
   221                         {
       
   222                             LOGARG("CTapGestureRecogniser: 0x%x first tap: num %d code %d", 
       
   223                                     this, countOfEvents, eventCode);
       
   224                         }
       
   225                         Cancel() ;  // Just to be sure...
       
   226                         After(m_doubleTapTimeout) ;
       
   227                     }
       
   228 
       
   229                 }
       
   230             }
       
   231         }
       
   232     }
       
   233     return state;
       
   234 }
       
   235 
       
   236 void CTapGestureRecogniser::release(MGestureEngineIf* /*ge*/)
       
   237 {
       
   238     Cancel() ;  // some other gesture took hold of the thing, do not send tap gesture
       
   239     m_waitingforsecondtap = false ;
       
   240     if (m_loggingenabled)
       
   241     {
       
   242         LOGARG("CTapGestureRecogniser: 0x%x release, %d %d", 
       
   243                 this, m_firstTapXY.iX, m_firstTapXY.iY);
       
   244     }
       
   245 }
       
   246 
       
   247 void CTapGestureRecogniser::RunL()
       
   248 {
       
   249     m_waitingforsecondtap = false ;
       
   250     if (m_loggingenabled)
       
   251     {
       
   252         LOGARG("CTapGestureRecogniser: 0x%x timer, %d %d", this, m_firstTapXY.iX, m_firstTapXY.iY);
       
   253     }
       
   254     // Double tap timer has been elapsed without new Touch/Release, generate the tap if there is a listener
       
   255     TInt inx = m_tapListenerWindows.Find(m_firstTapTarget) ;
       
   256     if (inx != KErrNotFound)
       
   257     {
       
   258         using stmUiEventEngine::TUiEventSpeed;
       
   259 
       
   260         TUiEventSpeed speedIf(m_firstTapSpeedX,m_firstTapSpeedY);
       
   261 
       
   262         stmGesture::TGenericSimpleGesture pgest(
       
   263                 stmGesture::EGestureUidTap,
       
   264                 m_firstTapXY,
       
   265                 stmGesture::ETapTypeSingle,
       
   266                 &speedIf) ;
       
   267 
       
   268         MGestureListener* plistener = m_tapListeners[inx] ;
       
   269         plistener->gestureEnter(pgest) ;
       
   270     }
       
   271 }
       
   272 
       
   273 void CTapGestureRecogniser::enableLogging(bool loggingOn)
       
   274 {
       
   275     m_loggingenabled = loggingOn;
       
   276 }
       
   277 
       
   278 void CTapGestureRecogniser::setOwner(CCoeControl* owner)
       
   279 {
       
   280     m_powner = owner;
       
   281 }
       
   282 
       
   283 void CTapGestureRecogniser::setDoubleTapTimeout(int newtimeout)
       
   284 {
       
   285     m_doubleTapTimeout  = newtimeout;
       
   286 }
       
   287 
       
   288 void CTapGestureRecogniser::enable(bool enabled)
       
   289 {
       
   290     m_gestureEnabled = enabled ;
       
   291 }
       
   292 
       
   293 bool CTapGestureRecogniser::isEnabled()
       
   294 {
       
   295     return m_gestureEnabled ;
       
   296 }
       
   297 
       
   298 void CTapGestureRecogniser::setDoubleTapRange(int rangeInMillimetres)
       
   299 {
       
   300     m_rangesizeInPixels = Mm2Pixels(rangeInMillimetres) ;
       
   301 }
       
   302 
       
   303 void CTapGestureRecogniser::ignoreFirstTap(bool ignore)
       
   304 {
       
   305     m_ignorefirst = ignore ;
       
   306 }
       
   307 
       
   308 /*!
       
   309  * Check whether the two taps are close enough to each other
       
   310  */
       
   311 bool CTapGestureRecogniser::isSecondTapClose(const TPoint& secondPoint, const TPoint& firstTapXY)
       
   312 {
       
   313     TRect tolerance = ToleranceRect(secondPoint, m_rangesizeInPixels) ;
       
   314     bool aretheyclose = tolerance.Contains(firstTapXY);
       
   315     return aretheyclose ;
       
   316 }
       
   317 
       
   318 void CTapGestureRecogniser::addTapListener(MGestureListener* aListener, CCoeControl* listenerOwner)
       
   319 {
       
   320     m_tapListeners.Append(aListener) ;
       
   321     m_tapListenerWindows.Append(listenerOwner) ;
       
   322 }
       
   323 
       
   324 void CTapGestureRecogniser::removeTapListener(MGestureListener* aListener, 
       
   325                                               CCoeControl* /*listenerOwner*/)
       
   326 {
       
   327     TInt inx = m_tapListeners.Find(aListener) ;
       
   328     if(inx != KErrNotFound)
       
   329     {
       
   330         m_tapListeners.Remove(inx) ;
       
   331         m_tapListenerWindows.Remove(inx) ;
       
   332     }
       
   333 }
       
   334 
       
   335 void CTapGestureRecogniser::addDoubleTapListener(MGestureListener* aListener, 
       
   336                                                  CCoeControl* listenerOwner)
       
   337 {
       
   338     m_doubleTapListeners.Append(aListener) ;
       
   339     m_doubleTapListenerWindows.Append(listenerOwner) ;
       
   340 }
       
   341 
       
   342 void CTapGestureRecogniser::removeDoubleTapListener(MGestureListener* aListener, 
       
   343                                                     CCoeControl* /*listenerOwner*/)
       
   344 {
       
   345     TInt inx = m_doubleTapListeners.Find(aListener) ;
       
   346     if(inx != KErrNotFound)
       
   347     {
       
   348         m_doubleTapListeners.Remove(inx) ;
       
   349         m_doubleTapListenerWindows.Remove(inx) ;
       
   350     }
       
   351 }
       
   352