phoneapp/phoneuicontrol/src/cphonekeyeventforwarder.cpp
branchRCL_3
changeset 62 5266b1f337bd
child 69 8baf28733c3d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phoneapp/phoneuicontrol/src/cphonekeyeventforwarder.cpp	Wed Sep 01 12:30:10 2010 +0100
@@ -0,0 +1,796 @@
+/*
+* Copyright (c) 2007 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:  Key event forwarder.
+*
+*/
+
+
+// INCLUDE FILES
+#include <eikenv.h>
+#include <eikappui.h>
+#include <bldvariant.hrh>
+#include <featmgr.h>
+#include <PtiDefs.h>
+#include <AknUtils.h>
+
+#include "mphonestatemachine.h"
+#include "mphonekeyeventhandler.h"
+#include "cphonekeys.h"
+#include "cphonekeyeventforwarder.h"
+#include "cphonepubsubproxy.h"
+#include "cphonetimer.h"
+#include "phonelogger.h"
+#include "phoneui.pan"
+#include "mphoneviewcommandhandle.h"
+#include "cphoneqwertyhandler.h"
+#include "tphonecmdparampointer.h"
+#include "tphonecmdparamboolean.h"
+#include "mphoneqwertymodeobserver.h"
+#include "cdialer.h"
+
+// CONSTANTS
+
+//Avkon P&S keys
+const TUid KCRUidAvkon = { 0x101F876E };
+const TUint32 KAknKeyBoardLayout = 0x0000000B;
+
+// Characters resulting from multitapping *-key.
+_LIT( KAsteriskMultitapCharacters, "*+pw" );
+
+// Multitap delay parameter in micro seconds.
+const TInt KMultitapDelay = 1000000;
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::NewL
+// -----------------------------------------------------------------------------
+//
+CPhoneKeyEventForwarder* CPhoneKeyEventForwarder::NewL(
+        const TRect& aRect,
+        MPhoneStateMachine* aStateMachine,
+        MPhoneViewCommandHandle* aViewCommandHandle )
+    {
+    CPhoneKeyEventForwarder* self =
+        new (ELeave) CPhoneKeyEventForwarder( aStateMachine, aViewCommandHandle );
+
+    CleanupStack::PushL( self );
+    self->ConstructL( aRect );
+    CleanupStack::Pop( self );
+
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::~CPhoneKeyEventForwarder
+// -----------------------------------------------------------------------------
+//
+CPhoneKeyEventForwarder::~CPhoneKeyEventForwarder()
+    {
+    __LOGMETHODSTARTEND( EPhoneControl, "CPhoneKeyEventForwarder::~CPhoneKeyEventForwarder");
+
+    if ( AknLayoutUtils::PenEnabled() ) 
+        {
+        iPeninputServer.RemovePenUiActivationHandler( this );
+        }
+    
+    iPeninputServer.Close();
+    
+    if ( iEikonEnv )
+        {
+        iEikonEnv->EikAppUi()->RemoveFromStack( this );
+        }
+    delete iLongPressKeyEventTimer;
+    
+    delete iQwertyHandler;
+    }
+
+// -----------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::CountComponentControls
+// -----------------------------------------------------------------------------
+//
+TInt CPhoneKeyEventForwarder::CountComponentControls() const
+    {
+    __LOGMETHODSTARTEND( EPhoneControl, "CPhoneKeyEventForwarder::CountComponentControls");
+    return 0;
+    }
+
+// -----------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::ComponentControl
+// -----------------------------------------------------------------------------
+//
+CCoeControl* CPhoneKeyEventForwarder::ComponentControl(
+        TInt /*aIndex*/ ) const
+    {
+    __LOGMETHODSTARTEND( EPhoneControl, "CPhoneKeyEventForwarder::ComponentControl");
+    return NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::SizeChanged
+// -----------------------------------------------------------------------------
+//
+void CPhoneKeyEventForwarder::SizeChanged()
+    {
+    __LOGMETHODSTARTEND( EPhoneControl, "CPhoneKeyEventForwarder::SizeChanged");
+    }
+
+// -----------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::Draw
+// -----------------------------------------------------------------------------
+//
+void CPhoneKeyEventForwarder::Draw(
+        const TRect& /*aRect*/ ) const
+    {
+    __LOGMETHODSTARTEND( EPhoneControl, "CPhoneKeyEventForwarder::Draw");
+    }
+
+// -----------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::OfferKeyEventL
+// Checks is hte keyevent such that the number entry can be opened
+// -----------------------------------------------------------------------------
+//
+TKeyResponse CPhoneKeyEventForwarder::OfferKeyEventL(
+        const TKeyEvent& aKeyEvent,
+        TEventCode aType )
+    {
+    __LOGMETHODSTARTEND( EPhoneControl,
+        "CPhoneKeyEventForwarder::OfferKeyEventL");
+
+    TKeyResponse ret( EKeyWasNotConsumed );
+    
+    // After event key, expect to have key up event.
+    iExpectKeyUpEvent = ( aType == EEventKey );
+
+    ret = OfferKeyEventBeforeControlStackL( aKeyEvent, aType );
+
+    if ( !aKeyEvent.iRepeats && aKeyEvent.iCode != EKeyEscape )
+        {
+        // Convert event. Use already converted iKeyPressedDown.
+        TKeyEvent keyEvent = aKeyEvent;
+        if ( keyEvent.iScanCode == EStdKeyApplication0 )
+            {
+            keyEvent.iCode = EKeyApplication0;
+            }
+        else
+            {
+            keyEvent.iCode = iKeyPressedDown;
+            }
+        
+        // Do not handle dtmf tone if the type is EEventKey but we are not
+        // expecting key up event. This happens if the key up event has been
+        // handled by some CActiveSchedulerWait object somewhere in the execution 
+        // of function OfferKeyEventBeforeControlStackL.
+        if ( iExpectKeyUpEvent || aType != EEventKey )
+            {
+            // Start and stop dtmf
+            iStateMachine->State()->HandleDtmfKeyToneL( keyEvent, aType );
+            }
+        
+        // Open number entry view if any allowed character key
+        // is pressed on homescreen or in-call ui
+        if ( aType != EEventKeyUp && IsKeyAllowedL( keyEvent ) )
+            {
+            // Do not open number entry with up key
+            iStateMachine->State()->HandleCreateNumberEntryL( keyEvent, aType );
+            }
+        }
+
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::CPhoneKeyEventForwarder
+// -----------------------------------------------------------------------------
+//
+CPhoneKeyEventForwarder::CPhoneKeyEventForwarder(
+    MPhoneStateMachine* aStateMachine,
+    MPhoneViewCommandHandle* aViewCommandHandle  )
+    : iStateMachine( aStateMachine ),
+    iViewCommandHandle( aViewCommandHandle )
+    {
+    __LOGMETHODSTARTEND( EPhoneControl,
+        "CPhoneKeyEventForwarder::CPhoneKeyEventForwarder");
+    }
+
+// -----------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CPhoneKeyEventForwarder::ConstructL( const TRect& aRect )
+    {
+    __LOGMETHODSTARTEND( EPhoneControl,
+        "CPhoneKeyEventForwarder::ConstructL");
+
+    if ( FeatureManager::FeatureSupported( KFeatureIdKeypadNoSlider ) )
+        {
+        RWindowGroup& groupWin = iCoeEnv->RootWin();
+        }
+    // Create invisible control.
+    CreateWindowL();
+    MakeVisible( EFalse );
+    SetRect( aRect );
+
+    if ( iEikonEnv )
+        {
+        iEikonEnv->EikAppUi()->AddToStackL(
+            this,
+            ECoeStackPriorityEnvironmentFilter,
+            ECoeStackFlagRefusesFocus );
+        }
+
+    // Create the long press key event timer
+    iLongPressKeyEventTimer = CPhoneTimer::NewL();
+    
+    // Create qwerty mode handler
+    iQwertyHandler = CPhoneQwertyHandler::NewL();
+    
+    TPhoneCmdParamPointer ptrParam;
+    iViewCommandHandle->ExecuteCommand( EPhoneViewGetQwertyModeObserver, &ptrParam );
+    CDialer* qwertyObserver = 
+            static_cast<CDialer*>( ptrParam.Pointer() );
+            
+    iQwertyHandler->AddQwertyModeObserverL( *qwertyObserver );
+    
+    if ( AknLayoutUtils::PenEnabled() )
+        {
+        User::LeaveIfError( iPeninputServer.Connect() );
+        iPeninputServer.AddPenUiActivationHandler( this, EPluginInputModeAll );
+        iVirtualKeyBoardOpen = iPeninputServer.IsVisible();
+        }
+    
+    CEikonEnv* env = static_cast<CEikonEnv*>( ControlEnv() );
+    if ( env )
+        {
+        iMenu = env->AppUiFactory()->MenuBar();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::IsKeyAllowedL
+// -----------------------------------------------------------------------------
+//
+TBool CPhoneKeyEventForwarder::IsKeyAllowedL( const TKeyEvent& aKeyEvent )
+    {
+    __LOGMETHODSTARTEND( EPhoneControl,
+        "CPhoneKeyEventForwarder::IsKeyAllowedL");
+
+    TKeyEvent keyEvent( aKeyEvent );
+    
+    // Check keyboard mode
+    TBool isModeNumeric = iViewCommandHandle->HandleCommandL(
+          EPhoneViewIsNumberEntryNumericMode ) == EPhoneViewResponseSuccess;
+
+    // Check if key is a numeric key
+    TBool isNumeric = CPhoneKeys::IsNumericKey( keyEvent, EEventKey );
+    
+    // Check if key is alpha numeric key and alphabet input is allowed
+    TBool isAllowedAlphaNumeric =
+       iStateMachine->State()->IsAlphanumericSupportedAndCharInput( keyEvent );
+
+    return ( ( isModeNumeric && isNumeric ) || 
+             ( !isModeNumeric && isAllowedAlphaNumeric ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::ConvertHalfQwertySpecialChar
+// -----------------------------------------------------------------------------
+//
+TBool CPhoneKeyEventForwarder::ConvertHalfQwertySpecialChar( TUint& aCode,
+        const TKeyEvent& aKeyEvent )
+    {
+    __LOGMETHODSTARTEND( EPhoneControl,
+        "CPhoneKeyEventForwarder::ConvertHalfQwertySpecialChar");
+
+    TBool ret( EFalse );
+    TInt keyboard( CPhonePubSubProxy::Instance()->Value(
+          KCRUidAvkon,
+          KAknKeyBoardLayout ) );
+
+    if ( keyboard == EPtiKeyboardHalfQwerty )
+        {
+        switch ( aKeyEvent.iScanCode )
+           {
+           case EStdKeyLeftShift:
+               ret = ETrue;
+               aCode = KPhoneDtmfHashCharacter;
+               break;
+           case EStdKeyLeftFunc:
+               ret = ETrue;
+               aCode = KPhoneDtmfStarCharacter;
+               break;
+           case EStdKeySpace:
+               ret = ETrue;
+               aCode = KPhoneDtmf0Character;
+               break;
+           default:
+               break;
+           }
+        }
+
+    __PHONELOG1( EBasic, EPhoneControl,
+        "CPhoneKeyEventForwarder::ConvertHalfQwertySpecialChar =%d ",
+        ret );
+
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::IsKeySimulatedByTouchDialer
+// 
+// -----------------------------------------------------------------------------
+//
+TBool CPhoneKeyEventForwarder::IsKeySimulatedByTouchDialer( 
+        const TKeyEvent& aKeyEvent ) const
+    {
+    return ( ( aKeyEvent.iModifiers & EModifierNumLock ) &&
+             ( aKeyEvent.iModifiers & EModifierKeypad ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::HandleTouchDialerKeyEventL
+// Handle EEventKey type of event from touch dialer
+// -----------------------------------------------------------------------------
+//
+void CPhoneKeyEventForwarder::HandleTouchDialerKeyEventL( const TKeyEvent& aKeyEvent )
+    {
+    TBool multitap = aKeyEvent.iScanCode == EStdKeyNkpAsterisk && 
+            iPreviousScanCode == EStdKeyNkpAsterisk &&
+            iKeyPressTime.MicroSecondsFrom( iPreviousKeyPressTime ) < KMultitapDelay;
+    
+    if ( multitap )
+        {
+        // Update multitap index
+        iMultitapIndex = ( iMultitapIndex + 1 ) % KAsteriskMultitapCharacters().Length();
+        
+        // Delete the previously entered character by simulating a backspace character.
+        TKeyEvent backSpaceEvent;
+        backSpaceEvent.iModifiers = 0;
+        backSpaceEvent.iRepeats = 0;
+        backSpaceEvent.iCode = EKeyBackspace;
+        backSpaceEvent.iScanCode = EStdKeyBackspace;
+        iStateMachine->State()->HandleKeyEventL( backSpaceEvent, EEventKey );
+        
+        TKeyEvent keyEvent( aKeyEvent );
+        
+        // Modify the key event to contain the next character on multitap list.
+        keyEvent.iCode = ( TInt ) KAsteriskMultitapCharacters()[ iMultitapIndex ];
+        
+        // Send character to number entry.
+        iStateMachine->State()->HandleKeyEventL( keyEvent, EEventKey );
+        }
+    else 
+        {
+        iMultitapIndex = 0;
+        iStateMachine->State()->HandleKeyEventL( aKeyEvent, EEventKey );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::OfferKeyEventBeforeControlStackL
+// Let phone handle before other components in control stack
+// -----------------------------------------------------------------------------
+//
+TKeyResponse CPhoneKeyEventForwarder::OfferKeyEventBeforeControlStackL(
+    const TKeyEvent& aKeyEvent,
+    TEventCode aType )
+    {
+    __LOGMETHODSTARTEND( EPhoneControl,
+        "CPhoneKeyEventForwarder::OfferKeyEventBeforeControlStackL");
+
+    TKeyResponse response( EKeyWasNotConsumed );
+
+    // Handle key events before FEP
+    // This is must becouse FEP consumes * key and when
+    // editor is in alphanumeric mode FEP consumes all alphanumeric
+    // keys
+    switch( aType )
+        {
+         // EEventKeyDown
+        case EEventKeyDown:
+            response = HandleEventKeyDownBeforeControlStackL( aKeyEvent );
+            break;
+        // EEventKey
+        case EEventKey:
+            response = HandleEventKeyBeforeControlStackL( aKeyEvent );
+            break;
+        // EEventKeyUp
+        case EEventKeyUp:
+            response = HandleEventKeyUpBeforeControlStackL( aKeyEvent );
+            break;
+        default:
+            break;
+        }
+
+    return response;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::OfferKeyEventAfterControlStackL
+// Let phone handle keys if no one has done it already
+// -----------------------------------------------------------------------------
+//
+TKeyResponse CPhoneKeyEventForwarder::OfferKeyEventAfterControlStackL(
+    const TKeyEvent& aKeyEvent,
+    TEventCode aType )
+    {
+    __LOGMETHODSTARTEND( EPhoneControl,
+        "CPhoneKeyEventForwarder::OfferKeyEventAfterControlStackL");
+    
+    // Send key to editor
+    iStateMachine->State()->HandleKeyEventL( aKeyEvent, aType );
+    
+    if ( EEventKeyUp == aType && EKeyNull != iKeyPressedDown )
+        {
+		// EKeyEnter is always offered to Telephony so donīt offer it 
+		// to state if there is menu or a dialog open.
+        if ( !( EKeyEnter == iKeyPressedDown 
+                && iDisplayingMenuOrDialogOnEventKeyDown ) )
+            {
+            // Handle short key press
+            iStateMachine->State()->HandleKeyMessageL( 
+                    MPhoneKeyEvents::EPhoneKeyShortPress, 
+                    TKeyCode( iKeyPressedDown ) );
+            }
+        // Reset key code
+        iScanCode = EStdKeyNull;
+        iKeyPressedDown = EKeyNull;
+        iDisplayingMenuOrDialogOnEventKeyDown = EFalse;
+        }
+
+    return EKeyWasNotConsumed;
+    }
+
+// ---------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::OnPeninputUiDeactivated
+//
+// Gets called when the virtual keyboard editor is closed.
+// ---------------------------------------------------------------------------
+//
+void CPhoneKeyEventForwarder::OnPeninputUiDeactivated()
+    {
+    __LOGMETHODSTARTEND( EPhoneControl,
+            "CPhoneKeyEventForwarder::OnPeninputUiDeactivated");
+    iVirtualKeyBoardOpen = EFalse;
+    }
+
+// ---------------------------------------------------------------------------
+// CPhoneKeyEventForwarder::OnPeninputUiActivated
+//
+// Gets called when the virtual keyboard editor is opened.
+// ---------------------------------------------------------------------------
+//
+void CPhoneKeyEventForwarder::OnPeninputUiActivated()
+    {
+    __LOGMETHODSTARTEND( EPhoneControl,
+            "CPhoneKeyEventForwarder::OnPeninputUiActivated");
+    iVirtualKeyBoardOpen = ETrue;
+    }
+
+// -----------------------------------------------------------
+// CPhoneKeyEventForwarder::HandleEventKeyDownBeforeControlStackL
+// -----------------------------------------------------------
+//
+TKeyResponse CPhoneKeyEventForwarder::HandleEventKeyDownBeforeControlStackL(
+    const TKeyEvent& aKeyEvent )
+    {
+    __LOGMETHODSTARTEND( EPhoneControl,
+        "CPhoneKeyEventForwarder::HandleEventKeyDownBeforeControlStackL");
+
+    // Convert key code
+    ConvertKeyCodeL( iKeyPressedDown, aKeyEvent );
+    // Save key scan code
+    iScanCode = aKeyEvent.iScanCode;
+    
+    // Store the previous keypress time.
+    iPreviousKeyPressTime = iKeyPressTime;
+
+    // Start the key press timer
+    iKeyPressTime.UniversalTime();
+
+    // Cancel the long press key event timer, if it is active
+    if ( iLongPressKeyEventTimer->IsActive() )
+        {
+        iLongPressKeyEventTimer->CancelTimer();
+        }
+    
+    // Don't initiate long tap timer if all these are true 
+    // a) key event is not from virtual dialer
+    // b) device is in qwerty mode
+    // c) phone number editor is alpha mode, i.e. not in numeric mode
+    // This is to prevent phone app's long tap functionality with qwerty 
+    // long presses, and to have the normal editor long press behaviour 
+    // instead.
+    TBool preventLongTap = 
+            !IsKeySimulatedByTouchDialer( aKeyEvent ) && 
+            iQwertyHandler->IsQwertyInput() &&
+            iViewCommandHandle->HandleCommandL( EPhoneViewIsNumberEntryNumericMode ) != EPhoneViewResponseSuccess;
+    
+    // Prevent long tap functionality for key events coming from virtual touch keyboard.
+    // Virtual touch keyboard has own editing functionality for long presses, and telephony
+    // should not add conflicting behaviour on top of that.
+    preventLongTap = preventLongTap || iVirtualKeyBoardOpen;
+
+    if ( !preventLongTap ) 
+        {
+        // Start long press timer
+        iLongPressKeyEventTimer->After(
+            KPhoneLongPressKeyEventDuration,
+            TCallBack( DoHandleLongPressKeyEventCallbackL,
+            this ) );
+        }
+
+    // Check if dialog or menu is open
+    // EikAppUi()->IsDisplayingMenuOrDialog doesnīt always return correct 
+    // value for menubar, so ask visibility also from CEikMenuBar
+    iDisplayingMenuOrDialogOnEventKeyDown = ( iViewCommandHandle->HandleCommandL(
+            EPhoneViewIsDisplayingMenuOrDialog ) == 
+            EPhoneViewResponseSuccess ) || ( iMenu && iMenu->IsDisplayed() );
+
+
+    return ( EKeyWasNotConsumed );
+    }
+
+// -----------------------------------------------------------
+// CPhoneKeyEventForwarder::HandleEventKeyBeforeControlStackL
+// Both short key press event (iRepeats == 0) and
+// long key press event (iRepeats == 1) are handled here
+// -----------------------------------------------------------
+//
+TKeyResponse CPhoneKeyEventForwarder::HandleEventKeyBeforeControlStackL(
+    const TKeyEvent& aKeyEvent )
+    {
+    __LOGMETHODSTARTEND( EPhoneControl,
+        "CPhoneKeyEventForwarder::HandleEventKeyBeforeControlStackL");
+
+    TKeyResponse response( EKeyWasNotConsumed );
+    TKeyEvent keyEvent( aKeyEvent );
+
+    // Special handling for virtual dialer keys events
+    const TBool simulatedByDialer = IsKeySimulatedByTouchDialer( keyEvent );
+    if ( simulatedByDialer )
+        {
+        // feed the event directly to number entry
+        HandleTouchDialerKeyEventL( keyEvent );
+        response = EKeyWasConsumed;
+        }
+    else 
+        {
+        // If not simulated by dialer, multitap related fields are reset.
+        // Any key event not originating from dialer interrupts multitap
+        // behaviour.
+        iMultitapIndex = 0;
+        iPreviousScanCode = 0;
+        }
+    
+    // Special handling for QWERTY numeric mode key events
+    if ( response == EKeyWasNotConsumed )
+        {
+        // FEP does not handle numeric characters 0123456789+*#pw correctly
+        // when in QWERTY mode and number mode. If nothing is done about it, 
+        // these problems result in non-hybrid mode qwerty:
+        //      +, # and * cannot be typed without pressing Fn-key
+        //      Fn + <p/0> produces 0 although p is expected.
+        //      Fn + <w/2> produces 2 although w is expected.
+        // To avoid this problems we do the following.
+    
+        // Take numeric keyevent, pass it to number entry and consume it.
+        TBool numericMode = iViewCommandHandle->HandleCommandL(
+              EPhoneViewIsNumberEntryNumericMode ) == EPhoneViewResponseSuccess;
+        
+        TPhoneCmdParamBoolean blockingDialog;
+        iViewCommandHandle->ExecuteCommandL( EPhoneViewGetBlockingDialogStatus, 
+            &blockingDialog );
+
+        // Handle and consume keyevent only if in qwerty mode, editor is 
+        // in numeric mode, menu is not shown and there is no blocking dialog.
+        if ( iQwertyHandler->IsQwertyInput() && numericMode && 
+             ( !iMenu || !iMenu->IsDisplayed() ) && !blockingDialog.Boolean() )
+            {
+            iQwertyHandler->ConvertToNumeric( keyEvent );
+            
+            // Send key to editor only if a) it is not a repeating keyevent and 
+            // it is a valid number entry character (0123456789+*#pw).
+            if ( aKeyEvent.iRepeats == 0 &&
+                 ( CPhoneKeys::IsDtmfTone( keyEvent, EEventKey ) ||
+                   CPhoneKeys::IsExtraChar( keyEvent.iCode ) ) )
+                {
+                iStateMachine->State()->HandleKeyEventL( keyEvent, EEventKey );
+                response = EKeyWasConsumed;
+                }
+            }
+        }
+    
+    return response;
+    }
+
+// -----------------------------------------------------------
+// CPhoneKeyEventForwarder::HandleEventKeyUpBeforeControlStackL
+// -----------------------------------------------------------
+//
+TKeyResponse CPhoneKeyEventForwarder::HandleEventKeyUpBeforeControlStackL(
+    const TKeyEvent& aKeyEvent )
+    {
+    __LOGMETHODSTARTEND( EPhoneControl,
+        "CPhoneKeyEventForwarder::HandleEventKeyUpBeforeControlStackL");
+
+    // Send a long press key event to the current state provided
+    // that the key scan code is the same as the key that was pressed
+    if ( iScanCode == aKeyEvent.iScanCode )
+        {
+        // Pass the key press duration to the current state
+        TTime now;
+        now.UniversalTime();
+        TTimeIntervalMicroSeconds keyPressDuration = now.MicroSecondsFrom(
+           iKeyPressTime );
+        iStateMachine->State()->HandleKeyPressDurationL(
+            TKeyCode( iKeyPressedDown ),
+            keyPressDuration );
+
+        // Cancel the long press timer, if it is active. Otherwise
+        // ignore the key event since it was already handled as a long press
+        // key event.
+        if ( iLongPressKeyEventTimer->IsActive() )
+            {
+            iLongPressKeyEventTimer->CancelTimer();
+            }
+        }
+
+    // Store the previous scan code
+    iPreviousScanCode = iScanCode;
+
+    // Consume dialer simulated key events, pass others on
+    return EKeyWasNotConsumed;
+    }
+
+// ---------------------------------------------------------
+// CPhoneKeyEventForwarder::DoHandleLongPressKeyEventCallback
+//
+// This routine is called when the long press key event timer expires
+// after KPhoneLongPressKeyEventDuration.
+// ---------------------------------------------------------
+//
+TInt CPhoneKeyEventForwarder::DoHandleLongPressKeyEventCallbackL( TAny* aAny )
+    {
+    __LOGMETHODSTARTEND( EPhoneControl,
+        "CPhoneKeyEventForwarder::DoHandleLongPressKeyEventCallbackL");
+
+    __ASSERT_DEBUG( aAny,
+        Panic( EPhoneCtrlUnknownPanic ) );
+
+    reinterpret_cast< CPhoneKeyEventForwarder* >( aAny )->
+        HandleLongPressKeyEventL();
+
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------
+// CPhoneKeyEventForwarder::HandleLongPressKeyEventL
+// Handle long press key event
+// ---------------------------------------------------------
+//
+void CPhoneKeyEventForwarder::HandleLongPressKeyEventL()
+    {
+    __LOGMETHODSTARTEND( EPhoneControl,
+        "CPhoneKeyEventForwarder::HandleLongPressKeyEventL");
+
+    // In alphanumeric mode EEventKey-event is not received so we must
+    // compare also with scan code.
+    if ( KPhoneDtmfHashCharacter == iKeyPressedDown )
+        {
+        // Separate handling for long hash key because there is so much
+        // different functionality under it and it works differently
+        // in different protocols.
+        iStateMachine->State()->HandleLongHashL();
+        }
+    else if ( KPhoneDtmfStarCharacter == iKeyPressedDown )
+        {
+        // KPhoneDtmfStarCharacter value used in configuration file for
+        // long key press application launching
+        iStateMachine->State()->HandleKeyMessageL(
+               MPhoneKeyEvents::EPhoneKeyLongPress,
+               TKeyCode( KPhoneDtmfStarCharacter ) );
+        }
+    else
+        {
+        __PHONELOG1(
+            EBasic, EPhoneControl,
+            "CPhoneKeyEventHandler::HandleLongPressKeyEventL iCode(%d)",
+            iKeyPressedDown );
+        iStateMachine->State()->HandleKeyMessageL(
+            MPhoneKeyEvents::EPhoneKeyLongPress,
+            TKeyCode( iKeyPressedDown ) );
+        }
+
+    // Reset key code
+    iScanCode = EStdKeyNull;
+    iKeyPressedDown = EKeyNull;
+    }
+
+// -----------------------------------------------------------
+// CPhoneKeyEventForwarder::ConvertKeyCodeL
+// -----------------------------------------------------------
+//
+void CPhoneKeyEventForwarder::ConvertKeyCodeL( TUint& aCode,
+        const TKeyEvent& aKeyEvent )
+    {
+    __LOGMETHODSTARTEND( EPhoneControl,
+        "CPhoneKeyEventForwarder::ConvertKeyCodeL");
+
+    // Handler for special device key mapping in case iScanCode
+    // to iCode conversion hasn't been handled by CAknAppUi::GetAliasKeyCodeL
+    __PHONELOG1( EBasic, EPhoneControl,
+        "CPhoneKeyEventHandler::ConvertKeyCodeL scan code (%d)",
+        aKeyEvent.iScanCode );
+
+    if ( !ConvertHalfQwertySpecialChar( aCode, aKeyEvent ) )
+        {
+        TBool numMode = iViewCommandHandle->HandleCommandL(
+              EPhoneViewIsNumberEntryNumericMode ) == EPhoneViewResponseSuccess;
+        TBool simulatedByDialer = IsKeySimulatedByTouchDialer( aKeyEvent );
+    
+        if ( iQwertyHandler->IsQwertyInput() && numMode && !simulatedByDialer )
+            {
+            TUint numCode = iQwertyHandler->NumericKeyCode( aKeyEvent );
+            if ( numCode )
+                {
+                aCode = numCode;
+                }
+            else
+                {
+                aCode = aKeyEvent.iScanCode;
+                }
+            }
+        else 
+            {
+            switch ( aKeyEvent.iScanCode )
+                {
+                case EStdKeyEnter:
+                case EStdKeyNkpEnter:
+                    aCode = EKeyEnter;
+                    break;
+                case EStdKeyYes:
+                    aCode = EKeyYes;
+                    break;
+                case EStdKeyEnd: // End key is emulated if the device has combined power and end key
+                case EStdKeyNo:
+                    aCode = EKeyNo;
+                    break;
+                case EStdKeyDeviceF:
+                    aCode = EKeyDeviceF;  // EStdKeyDeviceF mapping for unlock switch.
+                    break;
+                case EStdKeyHash:
+                    aCode = KPhoneDtmfHashCharacter;
+                    break;
+                case EStdKeyNkpAsterisk:
+                    aCode = KPhoneDtmfStarCharacter;
+                    break;
+                case EStdKeyApplication0:
+                    aCode = EKeyApplication0;
+                    break;
+                default:
+                    aCode = aKeyEvent.iScanCode; // Use default code
+                    break;
+                }
+            }
+        }
+
+    __PHONELOG1( EBasic, EPhoneControl,
+        "CPhoneKeyEventHandler::ConvertKeyCodeL aCode (%d)", aCode );
+    }
+
+//  End of File
+