tactilefeedback/tactilearearegistry/src/tactilearearegistry.cpp
changeset 0 d54f32e146dd
child 13 a4df7952b706
child 22 4838b44af342
equal deleted inserted replaced
-1:000000000000 0:d54f32e146dd
       
     1 /*
       
     2 * Copyright (c) 2007-2009 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:  The class to be used from server side for accessing registry.
       
    15 *                Hit testing is done using this API.
       
    16 * Part of:      Tactile Feedback.
       
    17 *
       
    18 */
       
    19 
       
    20 
       
    21 #include <tactilefeedbacktrace.h>
       
    22 #include "tactilearearegistry.h"
       
    23 #include "OstTraceDefinitions.h"
       
    24 #ifdef OST_TRACE_COMPILER_IN_USE
       
    25 #include "tactilearearegistryTraces.h"
       
    26 #endif
       
    27 
       
    28 // ======== MEMBER FUNCTIONS ========
       
    29 
       
    30 // ---------------------------------------------------------------------------
       
    31 //
       
    32 // ---------------------------------------------------------------------------
       
    33 //
       
    34 CTactileAreaRegistry::TTactilePenDownEvent::TTactilePenDownEvent(): 
       
    35         iWindowGroupId( -1 ), iWindowHandle( 0 )
       
    36     {
       
    37     }
       
    38     
       
    39 // ---------------------------------------------------------------------------
       
    40 //
       
    41 // ---------------------------------------------------------------------------
       
    42 //    
       
    43 CTactileAreaRegistry::TTactilePenDownEvent::TTactilePenDownEvent( 
       
    44     TInt aWindowGroupId, 
       
    45     TUint32 aWindowHandle, 
       
    46     TRect aFeedbackArea ): 
       
    47         iWindowGroupId( aWindowGroupId ), 
       
    48         iWindowHandle( aWindowHandle ),
       
    49         iFeedbackArea( aFeedbackArea )
       
    50     {
       
    51     }
       
    52 
       
    53 // ---------------------------------------------------------------------------
       
    54 //
       
    55 // ---------------------------------------------------------------------------
       
    56 //
       
    57 void CTactileAreaRegistry::TTactilePenDownEvent::Reset()
       
    58     {
       
    59     iWindowGroupId = -1 ;
       
    60     iWindowHandle = 0;
       
    61     }
       
    62 
       
    63 // ---------------------------------------------------------------------------
       
    64 // Constructor.
       
    65 // ---------------------------------------------------------------------------
       
    66 //
       
    67 CTactileAreaRegistry::CTactileAreaRegistry()
       
    68     {
       
    69     }
       
    70 
       
    71 // ---------------------------------------------------------------------------
       
    72 // 2-phased constructor.
       
    73 // ---------------------------------------------------------------------------
       
    74 //
       
    75 EXPORT_C CTactileAreaRegistry* CTactileAreaRegistry::NewL()
       
    76     {
       
    77     CTactileAreaRegistry* self = new ( ELeave ) CTactileAreaRegistry;
       
    78     
       
    79     // We don't need ConstructL in this class for the moment, so we
       
    80     // can just return the created instance right away.
       
    81     return self;
       
    82     }
       
    83 
       
    84 // ---------------------------------------------------------------------------
       
    85 // Destructor.
       
    86 // ---------------------------------------------------------------------------
       
    87 //
       
    88 CTactileAreaRegistry::~CTactileAreaRegistry()
       
    89     {
       
    90     iChunkArray.Close();
       
    91     iWgArray.Close();
       
    92     iTactileSemaphore.Close();
       
    93     }
       
    94 
       
    95 
       
    96 // ---------------------------------------------------------------------------
       
    97 // #1 Find the shared chunk created by client
       
    98 // #2 Open handle to the found chunk
       
    99 // #3 Store window group id and connection handle with the chunk, 
       
   100 //    and add chunk to array
       
   101 // #4 Open global semaphore in case it is not yet open
       
   102 // ---------------------------------------------------------------------------
       
   103 //
       
   104 EXPORT_C void CTactileAreaRegistry::HandleConnectL( 
       
   105     const TTactileFeedbackConnectData& aData )
       
   106     {
       
   107     TRACE3("CTactileAreaRegistry::HandleConnectL - wgId = %d, Chunk = %S", 
       
   108         aData.iWindowGroupId,
       
   109         &aData.iChunkName );
       
   110     
       
   111     // #1
       
   112     TFindChunk findChunk( aData.iChunkName );
       
   113     
       
   114     TFullName chunkFullName;
       
   115     
       
   116     TInt err = findChunk.Next( chunkFullName );
       
   117     
       
   118     User::LeaveIfError( err );
       
   119        
       
   120     // #2
       
   121     TTactileAreaChunk newChunk;
       
   122 
       
   123     err = newChunk.iChunk.OpenGlobal( chunkFullName, ETrue );
       
   124 
       
   125     User::LeaveIfError( err );
       
   126     
       
   127     CleanupClosePushL( newChunk.iChunk );
       
   128     
       
   129     // #3      
       
   130     newChunk.iWindowGroupId = aData.iWindowGroupId;
       
   131     
       
   132     newChunk.iConnectionHandle = 
       
   133         ConnectionHandleByWgId( aData.iWindowGroupId );
       
   134     
       
   135     iChunkArray.AppendL( newChunk );
       
   136     
       
   137     CleanupStack::Pop(); // newChunk.iChunk  
       
   138         
       
   139     // #4 Open global semaphore in case it is not yet open
       
   140     if ( !iTactileSemaphore.Handle() )
       
   141         {
       
   142         err = iTactileSemaphore.OpenGlobal( KTouchFeedbackSemaphore );
       
   143         User::LeaveIfError( err );
       
   144         }   
       
   145     }
       
   146    
       
   147     
       
   148 // ---------------------------------------------------------------------------
       
   149 // We handle diconnect by finding client's chunk, closing it and then
       
   150 // removing the entry from chunk array.
       
   151 //
       
   152 // #1 Find the correct entry
       
   153 // #2 Close chunk
       
   154 // #3 Remove entry from chunk array
       
   155 // ---------------------------------------------------------------------------
       
   156 //
       
   157 EXPORT_C void CTactileAreaRegistry::HandleDisconnect( 
       
   158     const TTactileFeedbackDisconnectData& aData )
       
   159     {
       
   160     // #1
       
   161     for ( TInt i=0; i < iChunkArray.Count(); i++ )
       
   162         {
       
   163         if ( iChunkArray[i].iWindowGroupId == aData.iWindowGroupId )
       
   164             {
       
   165             // #2
       
   166             iChunkArray[i].iChunk.Close();
       
   167             
       
   168             // #3
       
   169             iChunkArray.Remove( i );            
       
   170             break;
       
   171             }
       
   172         }  
       
   173     }
       
   174     
       
   175 
       
   176 // ---------------------------------------------------------------------------
       
   177 // Here we just store information (e.g. connection handle) about the
       
   178 // newly created window group.
       
   179 //
       
   180 // Notice that we ignore possible error on purpose when adding new item to
       
   181 // the array. Firstly a failure should be almost impossible, and secondly 
       
   182 // it would only cause feedback to be disabled for the newly created 
       
   183 // window group.
       
   184 // ---------------------------------------------------------------------------
       
   185 //
       
   186 EXPORT_C void CTactileAreaRegistry::HandleWindowGroupCreated( 
       
   187     TInt aIdentifier, TUint aConnectionHandle )
       
   188     {
       
   189     TTactileWgroupItem newItem;
       
   190     
       
   191     newItem.iWindowGroupId    = aIdentifier;
       
   192     newItem.iConnectionHandle = aConnectionHandle;
       
   193     
       
   194     iWgArray.Append( newItem );
       
   195     }
       
   196     
       
   197     
       
   198 // ---------------------------------------------------------------------------
       
   199 // When window group is closed, we remove all information about it from
       
   200 // the array (we don't destroy chunks because it has been done based
       
   201 // on the disconnect request already).
       
   202 // ---------------------------------------------------------------------------
       
   203 //
       
   204 EXPORT_C void CTactileAreaRegistry::HandleWindowGroupClosed(
       
   205     TInt aIdentifier )
       
   206     {
       
   207     // Loop down so that deleting of items won't mix up the array
       
   208     for ( TInt i = iWgArray.Count()-1; i >= 0; i-- ) 
       
   209         {
       
   210         if ( iWgArray[i].iWindowGroupId == aIdentifier )
       
   211             {
       
   212             iWgArray.Remove( i );
       
   213             }
       
   214         }
       
   215     }
       
   216     
       
   217     
       
   218 // ---------------------------------------------------------------------------
       
   219 // This is the implementation of hit testing.
       
   220 //
       
   221 // It is assumed that this function is not called unless there is at least
       
   222 // one connected application, and unless iTactileSemaphore has been opened 
       
   223 // succesfully.
       
   224 //
       
   225 // #1 Check that we have valid handle to global semaphore.
       
   226 // #2 Find correct chunk based on window group id.
       
   227 // #3 Do actual hit testing in a separate function.
       
   228 // #4 Return feedback type based on hit testing results.
       
   229 // ---------------------------------------------------------------------------
       
   230 //
       
   231 EXPORT_C TTouchLogicalFeedback CTactileAreaRegistry::HitTestPointerEvent( 
       
   232     const TPointerEvent& aPointerEvent,
       
   233     TInt aWgIdentifier,
       
   234     TUint32 aWindowHandle )
       
   235     {
       
   236     TTouchLogicalFeedback feedback(ETouchFeedbackNone);
       
   237     
       
   238     OstTrace0( TACTILE_PERFORMANCE, TACTILE_REGISTRY_HIT_TEST_1, "e_TACTILE_REGISTRY_HIT_TEST 1");
       
   239 
       
   240     // #1
       
   241     if ( iTactileSemaphore.Handle() && 
       
   242          ( aPointerEvent.iType == TPointerEvent::EButton1Down || 
       
   243            aPointerEvent.iType == TPointerEvent::EButton1Up ) )
       
   244         {
       
   245         // We keep performance trace here instead of beginning of function
       
   246         // so that drag events won't confuse performance measurements.    
       
   247         
       
   248         // #2
       
   249         TInt chunkIndex = ChunkIndexByWindowGroupId( aWgIdentifier );
       
   250         
       
   251         // #3 If we found the window group where pointer event is going to land,
       
   252         // then search for correct window (and area) in its shared chunk.
       
   253         if ( chunkIndex >= 0 && chunkIndex < iChunkArray.Count() )   
       
   254             {
       
   255             feedback = HitTestChunk( 
       
   256                 iChunkArray[chunkIndex].iChunk, 
       
   257                 aPointerEvent,
       
   258                 aWgIdentifier,
       
   259                 aWindowHandle );
       
   260             }
       
   261          }
       
   262     
       
   263     OstTrace0( TACTILE_PERFORMANCE, TACTILE_REGISTRY_HIT_TEST_0, "e_TACTILE_REGISTRY_HIT_TEST 0");
       
   264     
       
   265     // #4
       
   266     return feedback;
       
   267     }
       
   268       
       
   269 // ---------------------------------------------------------------------------
       
   270 // In this function we do hit testing for one chunk.
       
   271 //
       
   272 // There is currently support for feedback on both
       
   273 // pen down and up -events.
       
   274 //
       
   275 // #1 Reset last pen down information in case this was a pen down -event.
       
   276 // #2 Call wait on global semaphore for mutual exlusion of shared memory.
       
   277 // #3 Start from the beginning of chunk, and read number of windows first.
       
   278 // #4 Go through all windows in a loop
       
   279 // ---------------------------------------------------------------------------
       
   280 //
       
   281 TTouchLogicalFeedback CTactileAreaRegistry::HitTestChunk( 
       
   282     RChunk& aChunk, 
       
   283     const TPointerEvent& aPointerEvent,
       
   284     TInt aWgIdentifier, 
       
   285     TUint32 aWindowHandle )
       
   286     {
       
   287     // #1
       
   288     if ( aPointerEvent.iType == TPointerEvent::EButton1Down )
       
   289         {
       
   290         iLastPenDown.Reset();
       
   291         }
       
   292     
       
   293     TTouchLogicalFeedback feedback = ETouchFeedbackNone;
       
   294     
       
   295     // #2 Protect shared memory chunks so that nobody can modify
       
   296     // them in the middle of hit testing.
       
   297     iTactileSemaphore.Wait();
       
   298 
       
   299     // #3
       
   300     TInt* base = (TInt*) aChunk.Base();  
       
   301     
       
   302     TInt windowCount = *base;
       
   303     base++;
       
   304     
       
   305     TBool windowFound(EFalse);
       
   306     
       
   307     // #4 Iterate though windows
       
   308     for ( TInt i=0; i < windowCount && !windowFound; i++ )
       
   309         {
       
   310         // Read handle identifier of this window
       
   311         TInt wsHandle = *base;
       
   312         base++;
       
   313         // Read number of areas registered to this window
       
   314         TInt areaCount = *base;
       
   315         base++;
       
   316         // Read offset to the area data of this window
       
   317         TInt offset = *base;
       
   318         base++; 
       
   319        
       
   320         // Check if this window is the one where pointer event hit.
       
   321         if ( wsHandle == static_cast<TInt>( aWindowHandle ) ) 
       
   322             {
       
   323             // Set pointer to the first area belonging to this window.
       
   324             TFeedbackChunkAreaEntry* entryPtr = 
       
   325                 reinterpret_cast<TFeedbackChunkAreaEntry*>( aChunk.Base() + offset );
       
   326 
       
   327             TBool matchFound = EFalse;
       
   328             
       
   329             // Go through all areas and test each one against the pointer
       
   330             // event as long as a match is found.
       
   331             for ( TInt j = 0; j < areaCount && !matchFound; j++ )
       
   332                 {
       
   333                 matchFound = HitTestRegistryEntry( aPointerEvent,
       
   334                                                    *entryPtr,
       
   335                                                    aWgIdentifier,
       
   336                                                    aWindowHandle,
       
   337                                                    feedback );
       
   338                             
       
   339                 entryPtr++;
       
   340                 }
       
   341                 
       
   342             // No need to continue in the loop, 
       
   343             // because window found already
       
   344             windowFound = ETrue;
       
   345             }   
       
   346         }
       
   347         
       
   348     // Release the semaphore so that applications can do updates to
       
   349     // registry again.   
       
   350     iTactileSemaphore.Signal();  
       
   351     
       
   352     return feedback;  
       
   353     }
       
   354     
       
   355     
       
   356 // ---------------------------------------------------------------------------
       
   357 // Here we analyse the pointer event type against feedback area entry, that
       
   358 // is located in same window where the pointer event hit.
       
   359 //
       
   360 // This functionality is encapsulated into separate function mainly
       
   361 // because this is the only part of the implementation that needs
       
   362 // to be modified in case we'll have different kinds of down- and up event
       
   363 // combinations (there could be different types for e.g. in situations were
       
   364 // up event is / is not required to match down event for it to trigger 
       
   365 // feedback).
       
   366 //
       
   367 // Here we also record details of pen down events (that trigger feedback), so
       
   368 // that we can check on pen up event in case it matches the same feedback 
       
   369 // area where down -event landed.
       
   370 //
       
   371 // #1 First see if pointer event even hit the area
       
   372 //
       
   373 // #2 Currently pen down event always generates feedback
       
   374 // 
       
   375 // #3 We trigger feedback on pen up event only if it matches the same
       
   376 //    feedback area, where corresponding down event hit.
       
   377 //    
       
   378 // ---------------------------------------------------------------------------
       
   379 //
       
   380 TBool CTactileAreaRegistry::HitTestRegistryEntry( 
       
   381     const TPointerEvent&           aPointerEvent, 
       
   382     const TFeedbackChunkAreaEntry& aEntry,
       
   383     TInt                           aWgIdentifier, 
       
   384     TUint32                        aWindowHandle,
       
   385     TTouchLogicalFeedback&         aFeedback )
       
   386     {
       
   387     TBool matchFound = EFalse;
       
   388     
       
   389     // #1
       
   390     if ( aEntry.iRect.Contains( aPointerEvent.iPosition) )
       
   391         {
       
   392         TInt enablers     = aEntry.iFeedbackType & ( KTactileVibraBitDown | 
       
   393                                                      KTactileAudioBitDown | 
       
   394                                                      KTactileVibraBitUp   | 
       
   395                                                      KTactileAudioBitUp );
       
   396         TInt feedbackDown = aEntry.iFeedbackType & 0x3FF;         // the first 10 bits
       
   397         TInt feedbackUp   = aEntry.iFeedbackType & (0x3FF << 10); // next 10 bits
       
   398         feedbackUp   = feedbackUp >> 10;
       
   399         // #2 Pointer down on the area always triggers feedback     
       
   400         if ( ( aPointerEvent.iType == TPointerEvent::EButton1Down ))
       
   401             {
       
   402             matchFound = ETrue;
       
   403             aFeedback = static_cast<TTouchLogicalFeedback>( feedbackDown );
       
   404             iLastPenDown = 
       
   405                 TTactilePenDownEvent(
       
   406                     aWgIdentifier, aWindowHandle, aEntry.iRect );
       
   407             }
       
   408         // #3    
       
   409         else if ( ( aPointerEvent.iType == TPointerEvent::EButton1Up ))
       
   410             {
       
   411             if ( iLastPenDown.iWindowGroupId == aWgIdentifier &&
       
   412                  iLastPenDown.iWindowHandle == aWindowHandle && 
       
   413                  iLastPenDown.iFeedbackArea == aEntry.iRect )
       
   414                 {
       
   415                 matchFound = ETrue;
       
   416                 aFeedback = static_cast<TTouchLogicalFeedback>( feedbackUp );
       
   417 
       
   418                 // Can only match agains same pen down event once
       
   419                 iLastPenDown.Reset();            
       
   420                 }
       
   421             }
       
   422         if ( matchFound )
       
   423             {
       
   424             aFeedback = static_cast<TTouchLogicalFeedback>(aFeedback | enablers);
       
   425             }
       
   426         }
       
   427     return matchFound;
       
   428     }
       
   429     
       
   430     
       
   431 // ---------------------------------------------------------------------------
       
   432 // Find the chunk of that application, where pointer event hit.
       
   433 //
       
   434 // #1 First determine the window server client connection handle (we use
       
   435 //    this to indentify chunk instead of window group id, because this way
       
   436 //    resolving works the same way also for additional window groups)
       
   437 //
       
   438 // #2 Go though the chunk array for finding out the correct one.
       
   439 // ---------------------------------------------------------------------------
       
   440 //
       
   441 TInt CTactileAreaRegistry::ChunkIndexByWindowGroupId( TInt aWgIdentifier ) const
       
   442     {
       
   443     TInt chunkIndex = KErrNotFound;
       
   444     
       
   445     // #1
       
   446     TUint connectionHandle = ConnectionHandleByWgId( aWgIdentifier );
       
   447 
       
   448     // #2 Iterate though chunks to find the correct one
       
   449     for ( TInt chunk = 0; chunk < iChunkArray.Count() && chunkIndex == KErrNotFound; chunk++ ) 
       
   450         {
       
   451         if ( iChunkArray[chunk].iConnectionHandle == connectionHandle )
       
   452             {
       
   453             chunkIndex = chunk;
       
   454             }
       
   455         }
       
   456             
       
   457     return chunkIndex;
       
   458     }
       
   459 
       
   460 
       
   461 // ---------------------------------------------------------------------------
       
   462 // Here we scan through the window group array, and return the corresponding
       
   463 // connection handle in case a match is found.
       
   464 // ---------------------------------------------------------------------------
       
   465 //
       
   466 TUint CTactileAreaRegistry::ConnectionHandleByWgId( TInt aWgIdentifier ) const
       
   467     {
       
   468     TUint connectionHandle = 0;
       
   469     
       
   470     for ( TInt i=0; i < iWgArray.Count() && !connectionHandle; i++ )
       
   471         {
       
   472         if ( iWgArray[i].iWindowGroupId == aWgIdentifier )
       
   473             {
       
   474             connectionHandle = iWgArray[i].iConnectionHandle;
       
   475             }
       
   476         }
       
   477         
       
   478     return connectionHandle;
       
   479     }
       
   480    
       
   481     
       
   482     
       
   483