coreapplicationuis/kefmapper/src/kefmapimpl.cpp
changeset 0 2e3d3ce01487
child 81 676b6116ca93
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/coreapplicationuis/kefmapper/src/kefmapimpl.cpp	Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,1546 @@
+/*
+* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  An implementation of a configurable key translation map.
+*
+*/
+
+
+// INCLUDES
+#include "kefmapimpl.h"
+#include <e32std.h>
+#include <e32math.h>
+#include <barsc.h>
+#include <barsread.h>
+#include <bautils.h>
+#include "kefresource.h"
+#include <AknKeyEventMap.rsg>
+#include "keflogger.h"
+#include "kefprovider.h"
+
+// CONSTANTS
+#define STRIP_MODS  &0x0000FFFF
+#define GET_MODS    &0xFFFF0000
+
+// Key event map resource file.
+_LIT( KKefKeyTableRsc, "z:\\resource\\AknKeyEventMap.rsc" );
+
+// Publish & Subscribe device mode category.
+const TInt32 KUidWinservCategoryValue = 0x10003B20;
+
+// Publish & Subscribe device mode category as TUid.
+const TUid KUidWinservCategory = { KUidWinservCategoryValue };
+
+// Always pass policy.
+_LIT_SECURITY_POLICY_PASS(KAlwaysPassPolicy);
+
+// Only system application can access.
+_LIT_SECURITY_POLICY_S0(KSysapOnlyPolicy, 0x100058F3);
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::NewL
+// -----------------------------------------------------------------------------
+//
+CKefMapImpl* CKefMapImpl::NewL()
+    {
+    CKefMapImpl* self = new (ELeave)CKefMapImpl();
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::CKefMapImpl
+// -----------------------------------------------------------------------------
+//
+CKefMapImpl::CKefMapImpl()
+    : iDownEvents( KKefMaxComboKeys ), iUpEvents( KKefMaxComboKeys )
+    {    
+    }
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::ConstructL
+//
+// Initializes member variables, reads the default keytables from a resource 
+// file, instantiates P&S subscriber and opens the door for raw events.
+// -----------------------------------------------------------------------------
+//
+void CKefMapImpl::ConstructL()
+    {
+
+    if ( KKefMaxDeviceMode < 1 || KKefMaxDeviceMode > 15)
+        {
+        __KEFLOGSTRING("CKefMapImpl::ConstructL ERROR: must have at least 1 and at most 15 device modes");
+        User::Leave(KErrGeneral);
+        }
+    //NEW CODE
+    iDelayedCombo = EFalse;
+    iIsPartialMatch = EFalse;
+    iCompleteDelayedComboMatch = EFalse;
+    iPostPendingDownEvents = EFalse;
+    //END NEW CODE
+    iCurrentDeviceMode = KKefModeDefault;
+    iKeyBeacon.iKeyCode = EKeyNull;
+    iKeyBeacon.iEventType = 0;
+    iDownTimer = CPeriodic::New( CActive::EPriorityLow );
+    iCombos = new (ELeave) RArray<RArray<TUint32>*>( KKefMaxComboKeys );
+    
+    iRepeatRate = KKefRepeatRate;
+    iKeyPollInterval = static_cast<TTimeIntervalMicroSeconds32>(1000000./iRepeatRate);
+    
+    iConsume = EFalse;
+    iIsCanceled = EFalse;
+    
+    iScanCodeIJustGenerated = -1;
+    iPostedDelayedScanCode = -1;
+    
+    iIsCombo = EFalse;
+    
+    // Initialize keymap.
+    const TKefKeyEvent nullEvent = { EKeyNull, EKeyNull, 0 };
+    for ( TUint j = 0; j < KKefKeyMapRows; j++ )
+        {
+        for ( TUint i = 0; i < KKefKeyMapColumns; i++ )
+            {
+            iKeyMap[i][j] = nullEvent;
+            }
+        }
+    
+    // Load the default configuration.
+    TRAPD( ierr, InitializeKeyTableFromResourceL( KKefKeyTableRsc ) );
+    if ( ierr != KErrNone )
+        {
+        __KEFLOGSTRING1( "Error initializing the key tables, %d", ierr );
+        }
+
+    if ( !IsKeyEventMapEnabled() )
+        {
+        return;
+        }
+    
+    // Define Publish & Subscribe key
+    TInt err = RProperty::Define( KUidWinservCategory, KKefPSDeviceMode, 
+        RProperty::EInt, KAlwaysPassPolicy, KSysapOnlyPolicy );
+    if ( err != KErrNone )
+        {
+        __KEFLOGSTRING1("CKefMapImpl::ConstrucL() Problem defining The Key %d", err);
+        }
+
+    // Subscribe to Publish & Subscribe keys
+    err = KErrNone;
+    CKefSubscriber *sub = NULL;
+    
+    sub = CKefSubscriber::NewL( *this, KUidWinservCategory , KKefPSDeviceMode  );
+    if ( sub )
+        {        
+        err = iKefSubscribers.Append( sub );
+        if ( err != KErrNone )
+            {
+            delete sub;
+            __KEFLOGSTRING( "CKefMapImpl::ConstructL ERROR: device mode subscription failed." );
+            // We could stop the boot here, but we can also continue, just without 
+            // the device modes.
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::~CKefMapImpl
+// -----------------------------------------------------------------------------
+//
+CKefMapImpl::~CKefMapImpl()
+    {
+    __KEFLOGSTRING("CKefMapImpl::Destructor entered.");
+    
+    if ( iCombos )
+        {
+        const TInt count = iCombos->Count();
+        for ( TInt i = count - 1; i >= 0; i-- ) 
+            {
+            (*iCombos)[i]->Close();
+            delete (*iCombos)[i];
+            iCombos->Remove(i);
+            }
+        iCombos->Close();
+        delete iCombos;
+        }
+    
+    delete iDownTimer;
+
+    iUpEvents.Close();   
+    iDownEvents.Close();
+    iRepeatRates.Close();
+    
+    iKefSubscribers.ResetAndDestroy();
+    iKefSubscribers.Close();
+    
+    iRawEventsNotPosted.Close();
+    }
+
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::SetProvider
+// -----------------------------------------------------------------------------
+//    
+void CKefMapImpl::SetProvider( MKefProvider& aProvider )
+    {
+    iProvider = &aProvider;
+    }
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::IsKeyEventMapEnabled
+// -----------------------------------------------------------------------------
+//
+TBool CKefMapImpl::IsKeyEventMapEnabled() const
+    {
+    return iKeyEventMapEnabled;
+    }
+    
+// -----------------------------------------------------------------------------
+// CKefMapImpl::OfferRawEvent
+// 
+// This is where the raw events end up in, and
+// where we have to decide what to do with them.
+// -----------------------------------------------------------------------------
+//
+TBool CKefMapImpl::OfferRawEvent( const TRawEvent& aRawEvent, TBool aSilentEvent )    
+    {
+    __ASSERT_ALWAYS( iProvider, User::Invariant() );
+    
+    const TBool downEvent = ( aRawEvent.Type() == TRawEvent::EKeyDown );
+    const TBool upEvent = ( aRawEvent.Type() == TRawEvent::EKeyUp );
+    //NEW CODE
+    iCompleteDelayedComboMatch = EFalse;
+    //END NEW CODE
+    //
+    // Raw events created by this CKefMapImpl itself: pass them on.
+    //
+    if ( ( downEvent || upEvent ) && 
+         ( aRawEvent.ScanCode() == iScanCodeIJustGenerated ) )
+        {
+        if ( downEvent )
+            {
+            // Add this scan code to iUpEvents so we can generate
+            // the appropriate raw UPs when the key press is finished.
+            __KEFLOGSTRING1("CKefMapImpl::OfferRawEvent adding %x to iUpEvents", iScanCodeIJustGenerated);
+            TInt err = iUpEvents.Append( iScanCodeIJustGenerated );
+            if ( err != KErrNone )  // never happened
+                {
+                __KEFLOGSTRING("CKefMapImpl::OfferRawEvent ERROR appending up event!");
+                }        
+            }
+    
+        if ( upEvent )
+            {
+            // would be nice to .Remove() elements from iUpEvents here,
+            // but that'd require another call to ResolveMapping(),
+            //  -- .Remove() in CancelProcessingKeyPress() instead.
+            }
+            
+        iScanCodeIJustGenerated = -1;
+        return EFalse;  // not further processing for scan codes iJustGenerated.
+        } 
+    
+    //NEW CODE
+    if ( ( downEvent || upEvent ) && 
+         ( aRawEvent.ScanCode() == iPostedDelayedScanCode ) )
+        { 
+        iPostedDelayedScanCode = -1;
+        return EFalse;  // not further processing for scan codes iJustGenerated.
+        }
+    //END NEW CODE      
+        
+    TInt err = KErrNone;
+    iConsume = EFalse;  // very important to set this here.
+    
+    // log arrays
+#ifdef _KEF_LOGGING	
+    for ( TInt i = 0 ; i < iDownEvents.Count() ; i++ )
+        {
+        __KEFLOGSTRING2("CKefMapImpl::OfferRawEvent iDownEvents[%d] = %x", i, iDownEvents[i] );
+        }
+    for ( TInt i = 0 ; i < iUpEvents.Count() ; i++ )
+        {
+        __KEFLOGSTRING2("CKefMapImpl::OfferRawEvent iUpEvents[%d] = %x", i, iUpEvents[i] );
+        }
+#endif // _KEF_LOGGING	
+    
+    // Down events
+    if ( downEvent && aRawEvent.ScanCode() >= 0 )
+        {
+        iIsDownEvent = ETrue;
+        iCurrentScanCode = aRawEvent.ScanCode(); 
+        iPostMeOnUp.iKeyCode = EKeyNull;
+        iPostMeOnUp.iEventType = 0;
+        __KEFLOGSTRING3( "CKefMapImpl::OfferRawEvent KeyDown scancode=%x mods=%x, we're in devicemode=%d", 
+            iCurrentScanCode STRIP_MODS, iCurrentScanCode GET_MODS, iCurrentDeviceMode);
+        
+        // Combo support
+        if ( iDownEvents.Count() < KKefMaxComboKeys )
+            {
+            err = iDownEvents.Append( aRawEvent.ScanCode() STRIP_MODS );
+            if ( err != KErrNone )  // never happened
+                {
+                __KEFLOGSTRING("CKefMapImpl::OfferRawEvent ERROR appending down event!");
+                }                
+            }
+        else 
+            {
+            // User is trying to press more simultaneous keys than supported.
+            // We have no problem with that, just ignore it.
+            }
+        
+        // Resolve mapping for this event and set is as the beacon.
+        iKeyBeacon = ResolveMapping();
+
+        // Launch a CPeriodic so the duration of the keypress can be known.  
+        // There's only one timer; for combos, it measures the time starting
+        // from the first DOWN event of the combo.  If usability troubles appear,
+        // try re-starting the timer for each participating key in a combo
+        // (by removing the test against iDownEvents.Count())
+        //NEW CODE
+        if ( iDownEvents.Count() < 2 && !iDelayedCombo)
+        //END NEW CODE        
+            {            
+            iKeyPressDuration = 0.0;
+            iDownTimer->Cancel();
+            iIsCanceled = EFalse; // set this before Start()
+            iDownTimer->Start( iKeyPollInterval, iKeyPollInterval, 
+                TCallBack( &KeyPressDuration, (TAny*) this ) );
+            }
+
+        if ( iKeyBeacon.iKeyCode > KKefKeyDisabled )
+            {
+            if ( ( iKeyBeacon.iEventType & KKefIsLongOnly ) )
+                {
+                // delayed posting of the short event when KKefIsLongOnly
+                iPostMeOnUp = iKeyBeacon;  
+                return iConsume;      // notice!  we're finished with this event.
+                }//this might be part of special combo key event
+            //NEW CODE
+            else if(iDelayedCombo && !iCompleteDelayedComboMatch)
+                {
+                    __KEFLOGSTRING("CKefMapImpl::OfferRawEvent Delayed Combo; downevent pending");
+                 //delay posting of down event(s) in case this is part of the combo
+                 return iConsume;      // notice!  we're finished with this event.   
+                }
+            //END NEW CODE
+            else
+                {
+                if ( ( iKeyBeacon.iEventType & KKefIsShortKey ) == EFalse )
+                    {
+                    PostEvent( EKefPostRaw );
+                    }
+                else 
+                    {
+                    PostEvent( EKefPostKey );
+                    }
+                //NEW CODE    
+                if(iCompleteDelayedComboMatch)
+                    {
+                        TInt existsAlready(-1);
+                        __KEFLOGSTRING("CKefMapImpl::OfferRawEvent Delayed Combo Complete. Key event posted");
+                      //Events for keys part of completed special combo are NOT posted. Ever.
+                      for(TInt i=0; i<iDownEvents.Count(); i++)
+                        {   
+                            existsAlready = iRawEventsNotPosted.Find( iDownEvents[i] );
+                            //However, do NOT add same events more than once.
+                            //When user is pressing the second key of a combo multiple times and holding the first down
+                            //we'd have the first key of the combo umpty times on the list.
+                            if(existsAlready == KErrNotFound)
+                                iRawEventsNotPosted.Append( iDownEvents[i] );
+                        }
+                            
+                      iIsPartialMatch = EFalse;
+                      iPostPendingDownEvents = EFalse;
+                      iCompleteDelayedComboMatch = EFalse;
+                    }
+                //END NEW CODE  
+                }
+            }
+         //NEW CODE
+         if(iPostPendingDownEvents)
+                {   //This is not a special combo. Post delayed downevents.
+                    __KEFLOGSTRING("CKefMapImpl::OfferRawEvent Delayed Combo ABORT. Post pending events.");
+                    iDelayedCombo = EFalse;
+                    iIsPartialMatch = EFalse;
+                    TInt lastBeforeCurrentEvent = iDownEvents.Count();
+                    TInt eventNotPostedIndex(-1);
+                    //The current downevent will be posted by the window server (iConsume is EFalse).
+                    for(TInt i=0; i<lastBeforeCurrentEvent; i++)
+                        {
+                            eventNotPostedIndex = KErrNotFound;
+                            if(iRawEventsNotPosted.Count())                           
+                                eventNotPostedIndex = iRawEventsNotPosted.Find( iDownEvents[i] );
+                            if(eventNotPostedIndex == KErrNotFound)
+                                {
+                                    
+                                    iPostedDelayedScanCode = iDownEvents[i];
+                                    TRawEvent rawEvent;
+                                    rawEvent.Set( TRawEvent::EKeyDown, iPostedDelayedScanCode );
+                                    __KEFLOGSTRING1("CKefMapImpl::OfferRawEvent Posted pending event scancode=%x",rawEvent.ScanCode());
+                                    iProvider->KefPostRawEvent( rawEvent );
+                                }
+                        }          
+                    iPostPendingDownEvents = EFalse;
+                }
+            //END NEW CODE       
+        
+        // Emit a keyclick.
+        if ( !aSilentEvent && iKeyBeacon.iKeyCode != KKefKeyDisabled )
+            {
+            if ( iKeyBeacon.iKeyCode > KKefKeyDisabled )
+                {
+                if (iDownEvents.Count() > 1)
+                	{	//Make sure the key sound is played for the last key of a combo
+                		iProvider->KefGenerateKeySound( iCurrentScanCode STRIP_MODS );
+                	}
+                else
+                	{	//Otherwise send the mapped single key
+                		iProvider->KefGenerateKeySound( iKeyBeacon.iKeyCode STRIP_MODS );
+                	}
+                }
+            else
+                {
+                iProvider->KefGenerateKeySound( aRawEvent.ScanCode() STRIP_MODS );
+                }
+            }
+        
+        return iConsume; // this was set by ResolveMapping
+        }
+    
+    //  Up events    
+    if ( upEvent )
+        {
+        iIsDownEvent = EFalse;               
+        iCurrentScanCode = aRawEvent.ScanCode(); 
+        __KEFLOGSTRING1("CKefMapImpl::OfferRawEvent KeyUp scancode=%x",aRawEvent.ScanCode());
+        
+        // Check whether this up event finishes a keypress we've been handling.
+        TInt finishesKeyPress = 
+            iDownEvents.Find( aRawEvent.ScanCode() STRIP_MODS );
+        __KEFLOGSTRING1("CKefMapImpl::OfferRawEvent finishesKeypress index %d", finishesKeyPress);
+        __KEFLOGSTRING1("CKefMapImpl::OfferRawEvent Duration =%f",iKeyPressDuration);
+        
+        // We got an UP for a known DOWN
+
+        if ( finishesKeyPress != KErrNotFound) 
+            {
+
+                 
+            if ( iPostMeOnUp.iKeyCode > KKefKeyDisabled && !iIsLongKeyPress  )
+                {
+                iKeyBeacon = iPostMeOnUp;
+                if ( ( iKeyBeacon.iEventType & KKefIsShortKey ) == EFalse )
+                    {
+                    PostEvent( EKefPostRaw );
+                    }
+                else 
+                    {
+                    PostEvent( EKefPostKey );
+                    }
+                iPostMeOnUp.iKeyCode = EKeyNull;
+                iPostMeOnUp.iEventType = 0;
+                }
+            
+            //NEW CODE
+            if(iDelayedCombo )
+                {
+                    TInt lastDownEventIndex = iDownEvents.Count() - 1;
+                    TInt eventNotPostedIndex(-1);
+                    TInt lastEvent = iDownEvents[lastDownEventIndex]; //DEBUG VARIABLE
+                    //Up event for some other key than the last pressed; handling of special event aborted.
+                    if(finishesKeyPress != lastDownEventIndex)
+                        {
+                            __KEFLOGSTRING("CKefMapImpl::OfferRawEvent: Not the last key of DK. ABORT by UP event.");
+                            iDelayedCombo = EFalse;
+                            iIsPartialMatch = EFalse;
+                            iCompleteDelayedComboMatch = EFalse;
+                            iPostPendingDownEvents = ETrue;
+                            //Check if current UP event is in the "not to be posted" list
+                            eventNotPostedIndex = iRawEventsNotPosted.Find( iCurrentScanCode STRIP_MODS );
+                            if(eventNotPostedIndex != KErrNotFound)
+                              {
+                                iDownEvents.Remove( finishesKeyPress ); 
+                                iRawEventsNotPosted.Remove(eventNotPostedIndex);
+                                iConsume = ETrue; //This UP event is not sent either...
+                              }
+                            //Post pending down events
+                            __KEFLOGSTRING("CKefMapImpl::OfferRawEvent: Post pending events.");
+                            for(TInt i=0; i<iDownEvents.Count(); i++)
+                                {
+                                    eventNotPostedIndex = iRawEventsNotPosted.Find( iDownEvents[i] STRIP_MODS );
+                                    //Event is not in the "not to be posted" list; send it.
+                                    if(eventNotPostedIndex == KErrNotFound)
+                                        {
+                                            iPostedDelayedScanCode = iDownEvents[i];
+                                            TRawEvent rawEvent;
+                                            rawEvent.Set( TRawEvent::EKeyDown, iPostedDelayedScanCode );
+                                            iProvider->KefPostRawEvent( rawEvent );
+                                            eventNotPostedIndex = - 1;
+                                        }
+      
+                                }
+                                          
+                            iPostPendingDownEvents = EFalse;
+                        }
+                     else //Last key of a special combo or a candidate.Continue processing as special combo.
+                        {
+                            __KEFLOGSTRING("CKefMapImpl::OfferRawEvent: The last key of DK.");
+                            eventNotPostedIndex = iRawEventsNotPosted.Find( iCurrentScanCode STRIP_MODS );
+                            //Last key of a partial match 
+                            if(eventNotPostedIndex == KErrNotFound)
+                                {
+                                  __KEFLOGSTRING("CKefMapImpl::OfferRawEvent: Last key not on NO list. Post downevent.");
+                                  iPostedDelayedScanCode = iDownEvents[finishesKeyPress];
+                                  iDownEvents.Remove( finishesKeyPress ); 
+                                  TRawEvent rawEvent;
+                                  rawEvent.Set( TRawEvent::EKeyDown, iPostedDelayedScanCode );
+                                  //Post DOWN event. UP event will be posted by Window Server since iConsume is False.
+                                  iProvider->KefPostRawEvent( rawEvent );
+                                }
+                            else //Part of a completed special event. Do not post events associated with this key.
+                                { 
+                                    __KEFLOGSTRING("CKefMapImpl::OfferRawEvent: Last key on NO list. Don't post events.");  
+                                  iDownEvents.Remove( finishesKeyPress ); 
+                                  iRawEventsNotPosted.Remove(eventNotPostedIndex);
+                                  iConsume = ETrue;
+                                }  
+   
+                        }
+
+                }
+            else
+                {
+                     TInt eventNotPostedIndex = iRawEventsNotPosted.Find( aRawEvent.ScanCode() STRIP_MODS );
+                     //This has been part of a sent special combo; do not send raw event.
+                     if(eventNotPostedIndex != KErrNotFound)
+                         {
+                           iRawEventsNotPosted.Remove(eventNotPostedIndex);
+                           iDownEvents.Remove( finishesKeyPress );
+                           iConsume = ETrue;
+                         }
+                 //END NEW CODE
+                     else //Business as usual.
+                        {
+                            //
+                            iKeyBeacon = ResolveMapping();
+                            // Remove key from the down array
+                            iDownEvents.Remove( finishesKeyPress );
+                            
+                            // if it is mapped on the up array -> generate the up event
+                            TInt upKeyPressIndex = KErrNotFound;
+                            for ( TInt i = 0 ; i < iUpEvents.Count() ; i++ )
+                                {
+                                if ( (iUpEvents[i] STRIP_MODS) == ( iKeyBeacon.iKeyCode STRIP_MODS ) )
+                                    {
+                                    upKeyPressIndex = i;
+                                    break;
+                                    }
+                                }
+                            
+                            if ( upKeyPressIndex != KErrNotFound )
+                                {
+                                iScanCodeIJustGenerated = iUpEvents[upKeyPressIndex];
+                                TRawEvent rawEvent;
+                                rawEvent.Set( TRawEvent::EKeyUp, iScanCodeIJustGenerated );
+                                __KEFLOGSTRING1("CKefMapImpl::OfferRawEvent POST RAW UP-EVENT for %x",iScanCodeIJustGenerated);
+                                iProvider->KefPostRawEvent( rawEvent ) ;
+                                iUpEvents.Remove(upKeyPressIndex);
+                                iConsume = ETrue;
+                                }
+                        }
+                        
+                }
+                
+                    
+            if ( !iDownEvents.Count() )
+                 {
+                  CancelProcessingKeyPress();
+                 }
+
+            }
+         else // finishesKeyPress == KErrNotFound
+            {
+
+                    // probably a hardware/driver error, in any case we're
+                    // confused now.
+                    __KEFLOGSTRING("CKefMapImpl::OfferRawEvent INPUT IS CONFUSED: cancel key processing");            
+                    CancelProcessingKeyPress();     
+            }
+        }
+    
+    return iConsume;
+    }
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::CancelProcessingKeyPress
+// -----------------------------------------------------------------------------
+
+void CKefMapImpl::CancelProcessingKeyPress()
+    {
+    iDownTimer->Cancel();
+    iIsCanceled = ETrue;
+    iDownEvents.Reset();
+    iRawEventsNotPosted.Reset();
+    
+    // be sure to send out all raw upevents or CKeyTranslator
+    // will think the key is still being pressed.
+    TRawEvent rawEvent;    
+    while ( iUpEvents.Count() > 0 )
+        {
+        iScanCodeIJustGenerated = iUpEvents[0];
+        rawEvent.Set( TRawEvent::EKeyUp, iScanCodeIJustGenerated );
+        __KEFLOGSTRING1("CKefMapImpl::CancelProcessingKeyPress POST RAW UP-EVENT for %x",iScanCodeIJustGenerated);
+        iProvider->KefPostRawEvent( rawEvent ) ;
+        iUpEvents.Remove(0);
+        }
+        
+    iUpEvents.Reset();
+    iRepeats = 0;
+    iKeyPressDuration = 0.0;
+    iIsLongKeyPress = EFalse;                
+    __KEFLOGSTRING1("CKefMapImpl::CancelProcessingKeyPress Last beacon sent: %x", iKeyBeacon.iKeyCode);
+    iKeyBeacon.iKeyCode = EKeyNull;
+    iKeyBeacon.iEventType = 0;
+    //NEW CODE
+    iDelayedCombo = EFalse;
+    iIsPartialMatch = EFalse;
+    iCompleteDelayedComboMatch = EFalse;            
+    iPostPendingDownEvents = EFalse;   
+    //END NEW CODE                     
+    }
+    
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::HandlePropertyChangedL
+//
+// Callback for Publish & Subscribe key events, it tracks
+// the device mode changes for internal use.
+// -----------------------------------------------------------------------------
+//
+void CKefMapImpl::HandlePropertyChangedL( 
+        const TUid& aCategory, 
+        const TUint aKey )
+    {
+    TInt keyValue( 0 );
+    TInt err = KErrNone;
+    err = RProperty::Get( aCategory, aKey, keyValue );
+    if ( err == KErrNone )
+        {
+        switch( aKey )
+            {
+            case KKefPSDeviceMode:
+                {
+                __KEFLOGSTRING1("CKefMapImpl::HandlePropertyChanged VALUE: %d",aKey);
+                iCurrentDeviceMode = keyValue;
+                
+                const TInt count = iRepeatRates.Count();
+                TUint16 currentMode = iCurrentDeviceMode; 
+                for ( TInt ii = 0; ii < count; ii++ )
+                    {
+                    const TKefKeyRepeatRate& repeatRate = iRepeatRates[ ii ];
+                    
+                    if ( ( currentMode & repeatRate.iModeMask ) == 
+                         repeatRate.iMode )
+                        {
+                        SetRepeatRate( repeatRate.iRate );
+                        ii = count; // exit the loop.
+                        }
+                    }
+                }
+                break;
+            default:
+                {
+                __KEFLOGSTRING1("CKefMapImpl::HandlePropertyChanged GOT A P&S VALUE: %d",aKey);
+                }
+                break;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::InitializeKeyTableFromResourceL
+// -----------------------------------------------------------------------------
+//
+void CKefMapImpl::InitializeKeyTableFromResourceL(
+        const TDesC& aConfigFile ) 
+    {
+    // Get a handle for the resource file.
+    RFs fsSession;
+    CleanupClosePushL( fsSession );
+    TInt err = fsSession.Connect();
+    if ( err != KErrNone )
+        {
+        User::Leave( err );
+        }
+    RResourceFile resourceFile;
+    CleanupClosePushL( resourceFile );
+    
+    // Make sure we have the resource file.
+    if ( BaflUtils::FileExists( fsSession, aConfigFile ) )
+        {
+        resourceFile.OpenL( fsSession, aConfigFile );
+        }
+    else
+        {
+        __KEFLOGSTRING( "CKefMapImpl::InitializeKeyTableFromResourceL: no configuration file!");
+        CleanupStack::PopAndDestroy(); // CleanupClosePushL.
+        CleanupStack::PopAndDestroy(); // CleanupClosePushL.
+        return;
+        }
+    
+    // Confirm signature of the resource file.
+    resourceFile.ConfirmSignatureL( 0 );
+    
+    // Now just get the resource chunk into a heap buffer and give it to a 
+    // TResourceReader.
+    HBufC8* res;
+    res = resourceFile.AllocReadLC( R_AVKON_KEY_EVENT_MAP );
+    
+    TResourceReader theReader;
+    theReader.SetBuffer( res );
+    
+    // Check version field.
+    const TUint16 version = theReader.ReadUint16();
+    if ( version != KKefKeyEventVersion1 )
+        {
+        __KEFLOGSTRING( "CKefMapImpl::InitializeKeyTableFromResourceL: key event map disabled!");
+        CleanupStack::PopAndDestroy( res );
+        CleanupStack::PopAndDestroy(); // CleanupClosePushL.
+        CleanupStack::PopAndDestroy(); // CleanupClosePushL.
+        return;
+        }
+    
+    iKeyEventMapEnabled = ETrue;
+    theReader.ReadUint16(); // read flags, not in use yet.
+
+    // Read repeat rates.
+    const TUint count = theReader.ReadUint16();
+    for ( TInt idx = 0; idx < count; idx++ )
+        {
+        TUint16 mode = theReader.ReadUint16();
+        TUint16 modeMask = theReader.ReadUint16();
+        TUint8 rate = theReader.ReadUint8();
+        
+        const TKefKeyRepeatRate repeatRate = 
+            {
+            mode,
+            modeMask,
+            rate
+            };
+        
+        User::LeaveIfError( iRepeatRates.Append( repeatRate ) );
+        }
+
+    // Parses the resource data
+    CKefResourceArray* keyResourceArray = CKefResourceArray::NewLC();
+    CArrayPtrFlat<CKefResource>* keyEvents = NULL;
+    keyEvents = keyResourceArray->GetKeyEventsL( theReader );
+    
+    // At this point we have all the key event info; just put it in its place
+    // in iKeyMap and iCombos.
+    for ( TUint i = 0; i < (TUint)keyEvents->Count(); i++ )
+        {
+        CKefResource* keyEvent = keyEvents->At(i);
+        
+        if ( keyEvent->GetScanCodes().Count() > 0 )
+            {
+            if ( (keyEvent->GetKeyCodes().Count() == keyEvent->GetDeviceModes().Count())
+                 && (keyEvent->GetKeyCodes().Count() == keyEvent->GetEventTypes().Count()))
+                {
+                for ( TUint j = 0; 
+                      j < (TUint)keyEvent->GetKeyCodes().Count(); 
+                      j++ )
+                    {            
+                    TUint16 thisMode = keyEvent->GetDeviceModes().At(j);
+                    RArray<TUint> theseModes;
+                    CleanupClosePushL( theseModes );
+                    
+                    ResolveDeviceModeL( 
+                        theseModes, 
+                        keyEvent->GetDeviceModes().At(j) );
+                    
+                    TUint16 thisType = keyEvent->GetEventTypes().At(j);
+                    for ( TUint k = 0; k < (TUint)theseModes.Count(); k++ )
+                        {
+                        TKefKeyDefinition thisKey;
+                        thisKey.iScanCodes = &(keyEvent->GetScanCodes());
+                        thisKey.iDeviceMode = theseModes[k];
+                        thisKey.iKeyCode = keyEvent->GetKeyCodes().At(j);
+                        thisKey.iEventType = thisType;
+#ifdef RD_TACTILE_FEEDBACK
+                        thisKey.iFeedbackType = keyEvent->GetFeedbackType();
+#endif // RD_TACTILE_FEEDBACK
+                        
+                        TRAPD( error, SetKeyMappingL( thisKey ) );
+                        if (error != KErrNone)
+                            {
+                            __KEFLOGSTRING( "CKefMapImpl::InitializeKeyTableFromResourceL ERROR setting a mapping");
+                            }
+                        }
+                    
+                    CleanupStack::PopAndDestroy( &theseModes );
+                    }
+                }
+            else
+                {
+                // Keyboard configuration is erroneous!
+                // When multiple keycodes have been defined, they must have
+                // an associated device mode, etc.
+                __KEFLOGSTRING( "CKefMapImpl::InitializeKeyTableFromResourceL ERROR: inconsistent data in KEY_EVENT" );
+                User::Leave( KErrGeneral );
+                }
+            }
+        else 
+            {
+            // Error. No scancodes for the key event.
+            User::Leave( KErrGeneral );
+            }    
+        }
+    
+    // All done! The maps are now ready for use!
+    CleanupStack::PopAndDestroy( 4 ); // keyResourceArray, res, 
+                                      // &resourceFile, &fsSession
+    }
+    
+// -----------------------------------------------------------------------------
+// CKefMapImpl::SetRepeatRate
+// -----------------------------------------------------------------------------
+//
+void CKefMapImpl::SetRepeatRate( TUint8 aRepeatRate )
+    {
+    if ( iRepeatRate > 0 && iRepeatRate < 32 )
+        {        
+        iRepeatRate = aRepeatRate;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::SetKeyMappingL
+//
+// Sets the keycodes in iKeyMap and iCombos for one device mode.
+// -----------------------------------------------------------------------------
+//
+void CKefMapImpl::SetKeyMappingL( const TKefKeyDefinition& aKey )
+    {
+    if ( aKey.iScanCodes->Count() == 1 )
+        {        
+        // Normal (=single key) mapping
+        if ( (aKey.iEventType & KKefTypeShort) == KKefTypeShort )
+            {
+            // handle anykey definition for single presses.
+            if ( aKey.iScanCodes->At(0) == KKefAnyKey)
+                {
+                for (TUint j = 0; j < KKefMaxScanCode; j++) 
+                    {
+                    iKeyMap[j][aKey.iDeviceMode].iShortPress = 
+                        aKey.iKeyCode;
+                    iKeyMap[j][aKey.iDeviceMode].iLongPress = 
+                        aKey.iKeyCode;
+                    iKeyMap[j][aKey.iDeviceMode].iEventType |=
+                        ResolveEventType ( aKey.iEventType );
+#ifdef RD_TACTILE_FEEDBACK
+                    iKeyMap[j][aKey.iDeviceMode].iFeedbackType = 
+                        aKey.iFeedbackType;
+#endif // RD_TACTILE_FEEDBACK
+                    }
+                }
+            else 
+                {                                
+                // default is to set iLongPress to same as iShortPress, which in 
+                // practice means that the default behavior for long keypresses is
+                // to repeat.
+                iKeyMap[aKey.iScanCodes->At(0)][aKey.iDeviceMode].iShortPress = 
+                    aKey.iKeyCode;
+                iKeyMap[aKey.iScanCodes->At(0)][aKey.iDeviceMode].iLongPress = 
+                    aKey.iKeyCode;
+                iKeyMap[aKey.iScanCodes->At(0)][aKey.iDeviceMode].iEventType |= 
+                    ResolveEventType( aKey.iEventType );
+#ifdef RD_TACTILE_FEEDBACK
+                iKeyMap[aKey.iScanCodes->At(0)][aKey.iDeviceMode].iFeedbackType = 
+                    aKey.iFeedbackType;
+#endif // RD_TACTILE_FEEDBACK
+                }
+            }
+        else if ( ((aKey.iEventType & KKefTypeLong) == KKefTypeLong) ||
+                  ((aKey.iEventType & KKefTypeLongOnly) == KKefTypeLongOnly))
+            {
+            iKeyMap[aKey.iScanCodes->At(0)][aKey.iDeviceMode].iLongPress  = 
+                aKey.iKeyCode;
+            iKeyMap[aKey.iScanCodes->At(0)][aKey.iDeviceMode].iEventType |= 
+                ResolveEventType( aKey.iEventType );
+#ifdef RD_TACTILE_FEEDBACK
+            iKeyMap[aKey.iScanCodes->At(0)][aKey.iDeviceMode].iFeedbackType = 
+                aKey.iFeedbackType;
+#endif // RD_TACTILE_FEEDBACK
+            }
+        else
+            {
+            // Ignored.
+            }
+        }
+    else
+        {
+        // Combo mapping
+        RArray<TUint32>* newCombo = 
+            new (ELeave) RArray<TUint32>( KKefMaxComboKeys );
+        TUint i;
+        TInt err = KErrNone;
+        for ( i = 0; i < aKey.iScanCodes->Count(); i++ ) 
+            {           
+            err = newCombo->Append( aKey.iScanCodes->At(i) );
+            if ( err != KErrNone ) 
+                {
+                User::Leave( err );  // we're trapped, just bail out.
+                }
+            }
+        
+        // For combos, the device mode information is encoded in to the
+        // upper 16 bits of the Key Code value.    
+        TUint32 keyMode = aKey.iKeyCode + ( aKey.iDeviceMode << 16 );
+        newCombo->Insert( keyMode, 0 );
+       
+        TUint32 eventType = ResolveEventType( aKey.iEventType );
+        newCombo->Insert( eventType, 1 );
+
+        err = iCombos->Append( newCombo );
+        if ( err != KErrNone )
+            {
+            newCombo->Close();
+            delete newCombo;
+            User::Leave( err );
+            }  
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::ResolveEventType
+//
+// A conversion between the eventtype representation in the resource file
+// and iKeyMap.
+// -----------------------------------------------------------------------------
+
+TUint8 CKefMapImpl::ResolveEventType( TUint8 aEventType )
+    {
+    TUint8 result = 0;
+    
+    if ( (aEventType & (KKefTypeLongOnly)) == KKefTypeLongOnly )
+        {
+        result |= KKefIsLongOnly;
+        result |= KKefIsLongPress;
+        if ( (aEventType & KKefTypeKey) )
+            {
+            result |= KKefIsLongKey;
+            }
+        }
+    else if ( (aEventType & KKefTypeLong) == KKefTypeLong )
+        {
+        result |= KKefIsLongPress;
+        if ( (aEventType & KKefTypeKey) == KKefTypeKey )
+            {
+            result |= KKefIsLongKey;
+            
+            // This is needed if you want continious events from your
+            // combo mapping, i.e. hold down the modifier and press
+            // the other key several times to obtain the wanted result
+            //
+            if ( (aEventType & KKefTypeShort) == KKefTypeShort )
+                {
+                result |= KKefTypeShort;
+                }
+            
+            }
+        
+        }
+    else if ( (aEventType & KKefTypeShort) == KKefTypeShort )
+        {
+        result = 0; // to be 101% sure
+        if ( (aEventType & KKefTypeKey) == KKefTypeKey )
+            {
+            result |= KKefIsShortKey;
+            //NEW CODE
+            //In case this is a special combo event.
+            if ( (aEventType & KKefTypeDelayedCombo) == KKefTypeDelayedCombo )
+            	{
+            	result |= KKefIsDelayedOnCombo;
+            	}
+            //END NEW CODE
+            }
+        }
+
+    return result;
+    }
+    
+// -----------------------------------------------------------------------------
+// CKefMapImpl::ResolveDeviceModeLC
+//
+// Given a TUint specifying a device mode, this function figures out 
+// which rows of the iKeyMap are affected by a mapping. Only used in 
+// setting up the key tables, not when querying data from them (just use 
+// iCurrentDeviceMode then).
+// -----------------------------------------------------------------------------
+//
+void CKefMapImpl::ResolveDeviceModeL( 
+        RArray<TUint>& aModes, 
+        TUint16 aMode )
+    {
+    TInt err;   
+    TUint16 myMode = aMode;
+    
+    for ( TUint k = 0; k < KKefKeyMapRows; k++ )
+        {
+        // The loop index is now tested against aMode to see whether
+        // there should be a non-null value in iKeyMap.
+        
+        if ( k == myMode )
+            {            
+            err = aModes.InsertInOrder( k );
+            if ( err != KErrNone && err != KErrAlreadyExists )
+                {
+                User::Leave( err );  // we can't initialize the table.  fail.
+                }
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::GetKeyMapping
+//
+// Returns mappings from iKeyMap.
+// -----------------------------------------------------------------------------
+//
+TKefKeyBeacon CKefMapImpl::GetKeyMapping( 
+        TUint16 aScanCode, 
+        TUint16 aDeviceMode )
+    {
+#ifndef RD_TACTILE_FEEDBACK
+    TKefKeyBeacon mapValue = { EKeyNull, 0 };
+#else
+    TKefKeyBeacon mapValue = { EKeyNull, 0, 0 };
+#endif // RD_TACTILE_FEEDBACK
+
+        if ( aScanCode < KKefKeyMapColumns && aDeviceMode < KKefKeyMapRows )
+            {
+            // Look up the mode specific value, if any
+            if ( iIsLongKeyPress == EFalse )
+                {
+                mapValue.iKeyCode = iKeyMap[aScanCode][aDeviceMode].iShortPress;
+                }
+            else
+                {
+                mapValue.iKeyCode = iKeyMap[aScanCode][aDeviceMode].iLongPress;
+                }
+
+            mapValue.iEventType = iKeyMap[aScanCode][aDeviceMode].iEventType;        
+#ifdef RD_TACTILE_FEEDBACK
+            mapValue.iFeedbackType = iKeyMap[aScanCode][aDeviceMode].iFeedbackType;
+#endif // RD_TACTILE_FEEDBACK
+                
+            // With this, we always return the default mapping (if any)
+            // unless a mode-specific mapping was found.  
+            if ( !mapValue.iKeyCode )
+                {
+                if ( iIsLongKeyPress == EFalse )
+                    {
+                    mapValue.iKeyCode = iKeyMap[aScanCode][ KKefModeDefault ].iShortPress; 
+                    }
+                else
+                    {
+                    mapValue.iKeyCode = iKeyMap[aScanCode][ KKefModeDefault ].iLongPress;
+                    }
+                mapValue.iEventType = iKeyMap[aScanCode][ KKefModeDefault ].iEventType;        
+#ifdef RD_TACTILE_FEEDBACK
+                mapValue.iFeedbackType = iKeyMap[aScanCode][KKefModeDefault].iFeedbackType;
+#endif // RD_TACTILE_FEEDBACK
+                }
+            }
+
+    return mapValue;
+    }
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::GetComboMapping
+//
+// Returns mappings from iCombos.
+// -----------------------------------------------------------------------------
+//
+TKefKeyBeacon CKefMapImpl::GetComboMapping( 
+        RArray<TUint32>& aComboCandidate )
+    {
+    TKefKeyBeacon mapValue = { EKeyNull, 0 };        
+    
+    TUint i;
+    TUint j;
+    //NEW CODE
+    TUint noOfMatches(0);
+    TBool partialMatch(EFalse);
+    //END NEW CODE
+    
+    // First we check the first index of aComboCandidate
+    // against the second index (= first scancode) of all combo
+    // arrays in iCombos. If they match, then the i'th combo
+    // array in iCombos could match aComboCandidate.
+    //
+    // iCombos[i][0] contains the key code that is to be returned for a 
+    // succesful mapping, which introduces the offset-by-one in the following 
+    // loops/lookups.also included in [i][0] are the device mode info and the 
+    // event type info, both encoded into the upper 16 bits of iCombos[i][0].
+    
+    RArray<TUint> possibleMatch;  //  iCombos indices that might match
+    for (i = 0; i < iCombos->Count(); i++) 
+        {
+        if ( (*(*iCombos)[i])[2] == aComboCandidate[0])
+            {
+            if((((*iCombos)[i])->Count()-2) == aComboCandidate.Count() )
+                possibleMatch.Append(i);
+            //NEW CODE
+            //This might still be a potential match...
+            if(iIsDownEvent)
+                {
+                    if(iDelayedCombo && (((((*iCombos)[i])->Count()-2) > aComboCandidate.Count())))
+                        possibleMatch.Append(i);
+                }           
+            //END NEW CODE
+            __KEFLOGSTRING1("CKefMapImpl::GetComboMapping ComboCandidate might hit iCombos[%d]",i);
+            }                    
+        }
+    
+    // If we have possibleMatches, then we just check whether any of
+    // them matches aComboCandidate precisely. For the first match,
+    // we return the keyvalue from the first element of the matching
+    // combo array.
+    if ( possibleMatch.Count() )
+        {
+        TInt8 isAMatch = -1;
+        for ( i = 0; i < possibleMatch.Count() && isAMatch < 0; i++ ) 
+            {
+            // If isAMatch doesn't go to -1 within this loop, 
+            // then we got a match.
+            isAMatch = possibleMatch[i]; 
+            for ( j = 2; j < (*(*iCombos)[possibleMatch[i]]).Count(); j++ ) 
+                {
+                // Try to find all scan codes of the current event 
+                // in a combo definition.
+                // NOTE: the order of the remaining scancodes is not matched,
+                // as long as the first scancode is OK, the others can come in 
+                // any order.
+                TInt err = KErrNotFound;
+                for ( TInt f = (*(*iCombos)[possibleMatch[i]]).Count()-1; f >= 0 ; f-- )
+                    {
+                    if ( (*(*iCombos)[possibleMatch[i]])[f] == aComboCandidate[j-2] )
+                        {
+                        err = f;
+                        //NEW CODE
+                        noOfMatches++; //record each hit
+                        //END NEW CODE
+                        break;
+                        }
+                    }
+                
+                
+                // err < 2 must be discarded, because the first two elements are
+                // used for device mode & event type data.
+                if ( err == KErrNotFound || err < 2)
+                    {
+                    // If a scan code cannot be found, this possibleMatch is 
+                    // not a real match.
+                    isAMatch = -1;
+                    //NEW CODE
+                    noOfMatches --; //remove this "hit".
+                    //END NEW CODE
+                    }
+                    //NEW CODE
+                if ((j-2) == aComboCandidate.Count())
+                    {
+                        if(noOfMatches == aComboCandidate.Count())
+                            partialMatch = ETrue;
+                        break;//can happen when looking for a partial match as we took in combos
+                          //with more scancodes than in the candidate array. Must exit or we go out of bounds
+                          // of the candidate arrray.
+                    }
+                    //END NEW CODE
+                }
+            
+            // If a matching combination of keys has been 
+            // found we need to check that the combo type (long/short) and 
+            // the active device mode for this combo match those of the current
+            // event.
+
+              TUint16 comboMode = ((*(*iCombos)[possibleMatch[i]])[0] GET_MODS) >> 16;
+              TUint16 comboType = ((*(*iCombos)[possibleMatch[i]])[1]);
+
+            
+            
+            // If ..
+            //    a matching set of scan codes (or a partial match) was found,
+            //    but it fails the long/short test,
+            //    or it's defined for another device mode (default is always accepted).
+            if ( isAMatch > -1 && 
+                 ( iIsLongKeyPress && (!(comboType & KKefIsLongPress)  ) || 
+                   ( ( iCurrentDeviceMode != comboMode ) && ( comboMode != KKefModeDefault ) ) ) )
+                {
+                isAMatch = -1;
+                partialMatch = EFalse; //This wasn't even a partial match after all...
+                }
+            
+            }
+        
+        if ( isAMatch > -1  && isAMatch < iCombos->Count() )
+            {
+            // The correct return value can be found from the isAMatch'th 
+            // combo-mapping's first element.
+            mapValue.iKeyCode = (*(*iCombos)[isAMatch])[0] STRIP_MODS;
+            mapValue.iEventType = (*(*iCombos)[isAMatch])[1];
+            __KEFLOGSTRING1("CKefMapImpl::GetComboMapping ComboCandidate DID hit iCombos[%d]", isAMatch);
+            __KEFLOGSTRING1("CKefMapImpl::GetComboMapping mapValue = %d", mapValue.iKeyCode);
+            partialMatch = EFalse; //Since complete match was found there's no need for a partial match, even if one was found.
+            }
+        }
+    else 
+        {
+        mapValue.iKeyCode = EKeyNull;
+        mapValue.iEventType = 0 ;
+        }
+    possibleMatch.Close();
+    //NEW CODE
+    iIsPartialMatch = partialMatch;
+    //END NEW CODE
+    return mapValue;
+    }
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::ResolveMapping
+// 
+// A little macro for figuring out how to map the current scan code.  
+// -----------------------------------------------------------------------------
+//
+TKefKeyBeacon CKefMapImpl::ResolveMapping()
+    {
+    TKefKeyBeacon keyBeacon = 
+    {
+        EKeyNull, 0 
+#ifdef RD_TACTILE_FEEDBACK
+        , 0
+#endif // RD_TACTILE_FEEDBACK
+    };
+    
+    if ( iDownEvents.Count() > 1 && iDownEvents.Count() <= KKefMaxComboKeys ) 
+        {
+        // check that the current key is not disabled in this mode
+        // if it is, then any combo containing this key must be 
+        // blocked.
+        TKefKeyBeacon tmp = GetKeyMapping( 
+            iCurrentScanCode STRIP_MODS, iCurrentDeviceMode);
+        
+        if (tmp.iKeyCode != KKefKeyDisabled)
+            {
+            
+            //Some products have two keys mapped to same scancode. It's not much use to try to check for combo
+            //for two identical downevents as we'd just send the first potential combo event in the combo event list.    
+            if(iDownEvents[0] != iDownEvents[1]) 
+                {
+                    keyBeacon = GetComboMapping( iDownEvents );
+                }
+           
+
+            
+            if ( (keyBeacon.iKeyCode == EKeyNull))
+                {
+                //NEW CODE 
+                if((iDelayedCombo && !iIsPartialMatch) || !iDelayedCombo)
+                    {                       
+                //END NEW CODE 
+                       __KEFLOGSTRING( "CKefMapImpl::ResolveMapping Combo not found. Trying to get single." );
+                       keyBeacon = GetKeyMapping( iCurrentScanCode STRIP_MODS, iCurrentDeviceMode );
+                //NEW CODE 
+                    if(iDelayedCombo)
+                        {
+                            iDelayedCombo = EFalse;
+                            iPostPendingDownEvents = ETrue; //spec combo has been aborted; send all pending down events.
+                        }
+                       
+                    }
+                 iCompleteDelayedComboMatch = EFalse;
+                 
+                }
+            else 
+                {   //Combo found; if the flag is up then a special event is ready.
+                
+                    iIsCombo = ETrue;
+                    if(iDelayedCombo)
+                        {
+                            __KEFLOGSTRING("CKefMapImpl::ResolveMapping:handling Delayed Combo FOUND.");
+                            iIsPartialMatch = EFalse; //lower this flag just to be sure
+                            iCompleteDelayedComboMatch = ETrue; 
+                        }
+                       
+                } 
+               //END NEW CODE 
+            }
+        else
+            {
+            __KEFLOGSTRING("CKefMapImpl::ResolveMapping Ignoring combo because component is disabled");
+            keyBeacon.iKeyCode = KKefKeyDisabled;
+            keyBeacon.iEventType = 0;
+            }
+        }
+    else if ( iDownEvents.Count() == 1 )
+        { //NEW CODE                        
+            iCompleteDelayedComboMatch = EFalse;
+            //There's not much use to start searching for special combos if this is an UP event.
+            if(iIsDownEvent)
+                keyBeacon = GetFirstKey( iCurrentScanCode STRIP_MODS );
+            
+            if((keyBeacon.iKeyCode != EKeyNull) && (keyBeacon.iEventType & KKefIsDelayedOnCombo))
+                {
+                 __KEFLOGSTRING("CKefMapImpl::ResolveMapping:handling Delayed Combo first key.");
+                 iDelayedCombo = ETrue;
+                }
+            else
+           //END NEW CODE  //not the first key of a special combo, get normal mapping.
+                keyBeacon = GetKeyMapping( iCurrentScanCode STRIP_MODS, iCurrentDeviceMode );
+         
+        }
+    
+    // Always consume succesful mappings, including EKeyDisabled
+    if ( keyBeacon.iKeyCode != EKeyNull )
+        {
+        iConsume = ETrue;
+        __KEFLOGSTRING1( "CKefMapImpl::ResolveMapping mapping found: %x", keyBeacon.iKeyCode );
+        }
+    else
+        {
+        __KEFLOGSTRING( "CKefMapImpl::ResolveMapping mapping not found" );
+        }
+    
+    return keyBeacon;
+    }
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::KeyPressDuration
+//
+// Callback for iDownTimer, used to distinguish between short and 
+// long key presses and to handle repeats.
+// -----------------------------------------------------------------------------
+//
+TInt CKefMapImpl::KeyPressDuration( TAny* aSelf )
+    {
+    if (aSelf != NULL)
+        {
+        CKefMapImpl* self = reinterpret_cast<CKefMapImpl*>(aSelf);
+        
+        self->iKeyPressDuration += ((TReal32)self->iKeyPollInterval.Int())/1e6;
+        
+        // Distinguish between short and long key presses.
+        if ( self->iKeyPressDuration < KKefKeyLongThreshold )
+            {
+            // nothing to do.  if combo duration measurement is changed
+            // so that each participating key resets the timer, then
+            // un-comment the following lines:
+            // self->iIsLongKeyPress = EFalse;
+            // self->iKeyBeacon = self->ResolveMapping();
+            }
+        else 
+            {            
+            // Keypress turned out to be a long one
+            if ( ! self->iIsLongKeyPress && ! self->iIsCanceled ) 
+                {
+                self->iIsLongKeyPress = ETrue;
+                self->iKeyBeacon = self->ResolveMapping();
+    
+                // post the KKefTypeLongOnly event
+                if ( self->iKeyBeacon.iKeyCode > KKefKeyDisabled
+                    && (self->iKeyBeacon.iEventType & KKefIsLongPress))
+                    {
+                    if ( (self->iKeyBeacon.iEventType & KKefIsLongKey ) ) 
+                        {
+                        self->PostEvent( EKefPostKey );
+                        }
+                    else  
+                        {
+                        if ( self->iKeyBeacon.iEventType & KKefIsLongOnly )
+                            {
+                            self->PostEvent( EKefPostRaw );
+                            }
+                        else
+                            {
+                            __KEFLOGSTRING("CKefMapImpl::KeyPressDuration - LONG PRESS JUST DETECTED; RAW repeat not sent (CKeyTranslator handles that)");
+                            }
+                        }
+                    }
+                }
+            }
+        
+        // Handle repeats.
+        if ( self->iKeyPressDuration >= KKefKeyLongThreshold && 
+             self->iKeyBeacon.iKeyCode > KKefKeyDisabled ) 
+            {
+            if ( ( self->iKeyBeacon.iEventType & KKefIsLongKey ) )
+                {
+                //Make sure that the mapping is re-checked otherwise the iRepeats will grow until the last combo key is released
+                TKefKeyBeacon oldBeacon(self->iKeyBeacon);
+                
+                // Call resolve mapping to check if one of the keys has been released
+                self->iKeyBeacon = self->ResolveMapping();
+                // If no change in mapping increase number of repeats
+                // otherwise reset the iRepeats variable
+                if ( self->iKeyBeacon.iKeyCode == oldBeacon.iKeyCode &&
+                     self->iKeyBeacon.iEventType == oldBeacon.iEventType )
+                    {
+                    self->iRepeats++;    
+                    }
+                else
+                    {
+                    self->iRepeats = 0;
+                    }
+                  // These conditions needs to be re-checked, since iKeyBeacon may have changed above                     
+                if ( self->iKeyBeacon.iKeyCode > KKefKeyDisabled
+                    && (self->iKeyBeacon.iEventType & KKefIsLongPress))
+                    {
+                     if ( (self->iKeyBeacon.iEventType & KKefIsLongKey ) ) 
+                        {
+                        self->PostEvent( EKefPostKey );
+                        }
+                     else  
+                        {
+                        __KEFLOGSTRING("CKefMapImpl::KeyPressDuration - KKefIsLongKey = 1; RAW repeat not sent (CKeyTranslator handles that)");    
+                        }
+                        
+                    }                    
+                }
+            else
+                {
+                __KEFLOGSTRING("CKefMapImpl::KeyPressDuration - KKefIsLongKey = 0; RAW repeat not sent (CKeyTranslator handles that)");   
+                }
+            }
+        
+        if ( self->iIsCanceled )
+            {
+            self->iDownTimer->Cancel();
+            }
+        }
+    return KErrNone;
+    } 
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::PostEvent
+// -----------------------------------------------------------------------------
+
+void CKefMapImpl::PostEvent(TUint aType) 
+    {
+    switch ( aType )
+        {
+        case EKefPostKey:
+            TKeyEvent keyEvent;
+            keyEvent.iCode = iKeyBeacon.iKeyCode;
+            if(!iIsCombo)
+                keyEvent.iScanCode = iCurrentScanCode STRIP_MODS;
+            else// Discard the scan code in favour of the key code as combo events don't have a unabiguous scancode
+                keyEvent.iScanCode = EStdKeyNull;
+            keyEvent.iRepeats = iRepeats;
+            keyEvent.iModifiers = iCurrentScanCode GET_MODS; 
+            iProvider->KefPostKeyEvent(keyEvent);
+#ifdef RD_TACTILE_FEEDBACK
+            // tactile feedback requested in case of key events
+            iProvider->KefGenerateFeedback( iKeyBeacon.iFeedbackType );
+#endif // RD_TACTILE_FEEDBACK
+            __KEFLOGSTRING1( "CKefMapImpl::PostEvent() POST KEY code=%x", keyEvent.iCode);
+            iIsCombo = EFalse;
+            break;        
+        
+        case EKefPostRaw:
+        default:
+            TRawEvent rawEvent;
+            rawEvent.Set(TRawEvent::EKeyDown, (iCurrentScanCode GET_MODS) + iKeyBeacon.iKeyCode );
+            iScanCodeIJustGenerated = rawEvent.ScanCode();
+            __KEFLOGSTRING1( "CKefMapImpl::PostEvent() POST RAW scancode=%x", rawEvent.ScanCode());
+            iProvider->KefPostRawEvent( rawEvent );
+            break;
+        }
+    iConsume = ETrue;
+    }
+    
+    
+// -----------------------------------------------------------------------------
+// KefMapFactory::CreateKefMapL
+// Factory functoin to create instance out of CKefMap(Impl).
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CKefMap* KefMapFactory::CreateKefMapL()
+    {
+    return CKefMapImpl::NewL();
+    }
+
+// -----------------------------------------------------------------------------
+// CKefMapImpl::GetFirstKey
+// -----------------------------------------------------------------------------
+//NEW CODE    
+TKefKeyBeacon CKefMapImpl::GetFirstKey(TUint32 aComboFirstCodeCandidate )
+    {
+    TKefKeyBeacon mapValue = { EKeyNull, 0 };        
+    
+    TUint i;
+    
+    // We check the aComboCandidate
+    // against the second index (= first scancode) of all combo
+    // arrays in iCombos. If they match, then the i'th combo
+    // array in iCombos could match aComboCandidate.
+    //
+    // iCombos[i][0] contains the key code that is to be returned for a 
+    // succesful mapping, which introduces the offset-by-one in the following 
+    // loops/lookups.also included in [i][0] are the device mode info.  
+    // Event type info, is encoded into iCombos[i][1].
+    
+    TInt possibleMatch(-1);  //  iCombos index that might match
+    for (i = 0; i < iCombos->Count(); i++) 
+        {
+        if ( (*(*iCombos)[i])[2] == aComboFirstCodeCandidate) 
+            {
+            //Check device mode and event type 
+    		TUint16 comboMode = ((*(*iCombos)[i])[0] GET_MODS) >> 16; 
+    		TUint16 comboType = ((*(*iCombos)[i])[1]);
+    		
+    		if((comboType & KKefIsDelayedOnCombo)) //We've found a special combo
+    		    {
+    		        __KEFLOGSTRING("CKefMapImpl::GetFirstKey: IS a special event");
+    		        if((iCurrentDeviceMode != comboMode) && (comboMode != KKefModeDefault))
+    		            {
+    		                //but it is not for correct devicemode
+    		                 __KEFLOGSTRING("CKefMapImpl::GetFirstKey Wrong devicemode");
+    		            }
+    		        else
+    		            {
+    		               possibleMatch = i;
+                            __KEFLOGSTRING1("CKefMapImpl::GetFirstKey SPECIAL ComboCandidate might hit iCombos[%d]",i);
+        	               break;  
+    		            }
+    		    }
+                        
+            }                    
+        }
+	if ( possibleMatch >= 0 ) //We have apossible match
+	{
+	    
+		mapValue.iKeyCode = (*(*iCombos)[possibleMatch])[0] STRIP_MODS;
+        mapValue.iEventType = (*(*iCombos)[possibleMatch])[1]; 
+
+	}
+	return mapValue;
+  }
+//END NEW CODE  
+// End of File