uifw/AvKon/AknKeyRotator/implementation/AknKeyRotatorImpl.cpp
changeset 0 2f259fa3e83a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uifw/AvKon/AknKeyRotator/implementation/AknKeyRotatorImpl.cpp	Tue Feb 02 01:00:49 2010 +0200
@@ -0,0 +1,696 @@
+/*
+* Copyright (c) 2005-2008 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 rotation implementation
+*
+*/
+
+
+// INCLUDE FILES
+#include "AknKeyRotatorImpl.h"
+
+#include <UikonInternalPSKeys.h>
+#include <PSVariables.h>
+#include <aknpriv.rsg>
+#include <barsread.h>
+#include <barsc.h>
+#include <bautils.h>
+#include <w32adll.h>
+
+// CONSTANTS
+_LIT( KAknPrivRscFilePath,  "z:\\resource\\AknPriv.rsc");
+const TUint KAknModifiersMask = 0xFFFF0000;
+// Path to wsini.ini
+_LIT( KAknWsini, "z:\\system\\data\\wsini.ini" );
+// Keyword for key rotator compensation.
+// Syntax: S60_KEYROTATOR <value>
+//         where <value> is one of the following: -270, -180, -90, -0, 0, 90, 180, 270
+//         to specify <value> as compensation
+//         S60_KEYROTATOR DISABLED
+//         to disable key rotator
+// 
+_LIT( KAknKeyRotatorKey, "S60_KEYROTATOR" );
+_LIT( KAknKeyRotatorDisabled, "DISABLED");
+
+// Scan codes for diagonal directions 0xc9 .. 0xcc
+const TInt KAknStdLeftUpArrow = EStdKeyDevice10;
+const TInt KAknStdRightUpArrow = EStdKeyDevice11;
+const TInt KAknStdRightDownArrow = EStdKeyDevice12;
+const TInt KAknStdLeftDownArrow = EStdKeyDevice13;
+
+// Configure
+#define KAknRotateArrowKeys 1
+#define KAknRotateInKeyboardDriver 0
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CAknKeyRotatorImpl::CAknKeyRotatorImpl
+// 1st phase constructor
+// -----------------------------------------------------------------------------
+//
+CAknKeyRotatorImpl::CAknKeyRotatorImpl()
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CAknKeyRotatorImpl::ConstructL
+// 2nd phase constructor
+// -----------------------------------------------------------------------------
+//
+void CAknKeyRotatorImpl::ConstructL()
+    {
+    if ( KAknRotateInKeyboardDriver )
+        {
+        LoadHwStateRotationsL();
+        }
+    
+    User::LeaveIfError( iProperty.Attach( KPSUidUikon, KUikLayoutState ) );
+    
+    TRAPD( err, iKeyRotatorCompensation = GetKeyRotatorCompensationL() );
+    if ( err != KErrNone )
+        {
+        iKeyRotatorCompensation = 0;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAknKeyRotatorImpl::NewL
+// Two-phased constructor
+// -----------------------------------------------------------------------------
+//
+CAknKeyRotatorImpl* CAknKeyRotatorImpl::NewL()
+    {
+    CAknKeyRotatorImpl* self = new( ELeave ) CAknKeyRotatorImpl;
+    
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+
+    return self;
+    }
+    
+// -----------------------------------------------------------------------------
+// CAknKeyRotatorImpl::~CAknKeyRotatorImpl
+// Destruction
+// -----------------------------------------------------------------------------
+//
+CAknKeyRotatorImpl::~CAknKeyRotatorImpl()
+    {
+    iHwRotations.Close();
+    iProperty.Close();
+    }
+
+// -----------------------------------------------------------------------------
+// CAknKeyRotatorImpl::LoadHwStateRotationsL
+// Reads the HW states from the AknPriv.rsc to an array.
+// -----------------------------------------------------------------------------
+//
+void CAknKeyRotatorImpl::LoadHwStateRotationsL()
+    {
+    // Find the language specific resource file and then load it.
+    RResourceFile resourceFile;
+    RFs fsSession;
+    User::LeaveIfError( fsSession.Connect() );
+    CleanupClosePushL( fsSession );
+    
+    TFileName resourceFileName (KAknPrivRscFilePath);
+    BaflUtils::NearestLanguageFile( fsSession, resourceFileName );
+    resourceFile.OpenL(fsSession, resourceFileName);
+
+    CleanupClosePushL( resourceFile );
+    resourceFile.ConfirmSignatureL(0);
+    
+    // Read resources to a buffer. The resource definition for the target and
+    // emulator are a bit different.
+    HBufC8* res;
+#ifdef __WINS__
+    res = resourceFile.AllocReadLC( R_AKNPRIV_HARDWARE_STATE_SCREEN_MAP_EMUL );
+#else
+    res = resourceFile.AllocReadLC( R_AKNPRIV_HARDWARE_STATE_SCREEN_MAP );
+#endif
+    
+    TResourceReader reader;
+    reader.SetBuffer(res);
+    
+    // Read the entires. We are only interrested about the hwRotation.
+    TInt count = reader.ReadInt16();
+    for (TInt ii=0; ii<count; ii++)
+        {
+        /*TInt state =*/ reader.ReadInt16(); // Assumption (state == ii)
+        /*TInt width =*/ reader.ReadInt16();
+        /*TInt height =*/ reader.ReadInt16();
+        CFbsBitGc::TGraphicsOrientation hwRotation = 
+            static_cast<CFbsBitGc::TGraphicsOrientation>(reader.ReadInt16());
+        /*CFbsBitGc::TGraphicsOrientation altRotation =*/ 
+            static_cast<CFbsBitGc::TGraphicsOrientation>(reader.ReadInt16());
+        
+        User::LeaveIfError( iHwRotations.Append( hwRotation ) );
+        }
+    
+    CleanupStack::PopAndDestroy(res);
+    CleanupStack::PopAndDestroy(&resourceFile); // resourceFile.Close();  
+    CleanupStack::PopAndDestroy(&fsSession); // fsSession.Close();
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAknKeyRotatorImpl::CheckRotation
+// Check if this is our own generated event.
+// -----------------------------------------------------------------------------
+//
+TBool CAknKeyRotatorImpl::CheckRotation( 
+    const TRawEvent &aRawEvent,
+    MAnimGeneralFunctions& aAnimGeneralFunctions )
+    {
+    if ( KMaxTInt == iKeyRotatorCompensation )
+        {
+        // Key rotator is disabled - wsini.ini contains "S60_KEYROTATOR DISABLED".
+        return EFalse;
+        }
+
+    // Check first that we are not processing just generated event again.
+    if ( iRotatedRawEvent )
+        {
+        // This is the generated avent from the last round. Do not modify again.
+        iRotatedRawEvent = EFalse;
+        }
+    else if ( aRawEvent.Type() == TRawEvent::EKeyDown || 
+              aRawEvent.Type() == TRawEvent::EKeyUp || 
+              aRawEvent.Type() == TRawEvent::EKeyRepeat )
+        {
+        // We get new event. Let's see if we need to modify that.
+        TRawEvent newRawEvent( aRawEvent );
+        DoCheckRotation( newRawEvent, aAnimGeneralFunctions );
+        if ( aRawEvent.ScanCode() != newRawEvent.ScanCode() )   
+            {
+            // Generate new event,
+            iRotatedRawEvent = ETrue;
+            aAnimGeneralFunctions.PostRawEvent( newRawEvent ); // Calls this function again!
+            return ETrue;
+            }
+        }
+    
+    return EFalse;
+    }
+    
+    
+// -----------------------------------------------------------------------------
+// CAknKeyRotatorImpl::DoCheckRotation
+// Checks the scan codes and the orientations. Decides if we need to generate
+// a new raw event.
+// -----------------------------------------------------------------------------
+//
+void CAknKeyRotatorImpl::DoCheckRotation(
+    TRawEvent& aNewRawEvent,
+    MAnimGeneralFunctions& aAnimGeneralFunctions )
+    {   
+    // Current implementation is only for arrow keys
+    if ( !KAknRotateArrowKeys )
+        {
+        return;
+        }
+    
+    // Do not rotate external keyboard events.
+    if ( aNewRawEvent.ScanCode() & EModifierKeyboardExtend )
+        {
+        return;
+        }    
+        
+    // Also check only the arrow keys
+    if ( !IsArrowScanCode( aNewRawEvent.ScanCode ()) )
+        {
+        return;
+        }
+    
+    // If 'newCode' is changed something else than -1, 
+    // a new event will be generated
+    TInt newCode = KErrNotFound;
+    
+    // Check the rotation on down event. Use the same rotation for up event.
+    
+    // finalRotation variable at the end of this function is used to determine
+    // the new scan code.
+    CFbsBitGc::TGraphicsOrientation finalRotation = 
+        CFbsBitGc::EGraphicsOrientationNormal;
+    
+    if ( aNewRawEvent.Type() == TRawEvent::EKeyUp || 
+         aNewRawEvent.Type() == TRawEvent::EKeyRepeat )
+        {
+        // Use the same orintation for up event.
+        finalRotation = iUsedRotationForDownEvent;
+        }
+    else // For down event, find out the rotation.
+        {
+        // Get SW screen rotation compared to the keyboard i.e. app orientation.
+        CFbsBitGc::TGraphicsOrientation swRotation = 
+            aAnimGeneralFunctions.ScreenDevice()->Orientation();
+    
+        // Get HW screen rotation
+        CFbsBitGc::TGraphicsOrientation hwRotation = 
+            CFbsBitGc::EGraphicsOrientationNormal;
+        TInt hwState;
+        if ( KAknRotateInKeyboardDriver && 
+             ( iProperty.Get(hwState) == KErrNone ) )
+            {
+            if ( hwState < iHwRotations.Count() )
+                {
+                hwRotation = iHwRotations[hwState];
+                }
+            }
+    
+        // Calculate the difference
+        TInt finalRotationInt = swRotation*90;
+    
+        if ( KAknRotateInKeyboardDriver )
+            {
+            // If the rotation is also done in the driver level, 
+            // the rotation needs to be compensated so we do not 
+            // rotate twice.
+            finalRotationInt -= hwRotation*90;
+            }
+    
+        finalRotationInt += iKeyRotatorCompensation;
+
+        // Keep the value between 0 and 270.
+        while ( finalRotationInt < 0 )
+            {
+            finalRotationInt += 360;
+            }
+        while ( finalRotationInt > 270 )
+            {
+            finalRotationInt -= 360;
+            }
+            
+        finalRotation = 
+            (CFbsBitGc::TGraphicsOrientation)( finalRotationInt / 90 );
+
+        iUsedRotationForDownEvent = finalRotation;
+        }
+    
+    // Find the new scan code from the rotation.
+    switch( aNewRawEvent.ScanCode() )
+        {
+        case EStdKeyLeftArrow:
+            switch ( finalRotation )
+                {
+                case CFbsBitGc::EGraphicsOrientationRotated90:
+                    newCode = EStdKeyDownArrow;
+                    break;
+                case CFbsBitGc::EGraphicsOrientationRotated180:
+                    newCode = EStdKeyRightArrow;
+                    break;
+                case CFbsBitGc::EGraphicsOrientationRotated270:
+                    newCode = EStdKeyUpArrow;
+                    break;
+                default:
+                    break;
+                }
+            break;
+        case EStdKeyDownArrow:
+            switch ( finalRotation )
+                {
+                case CFbsBitGc::EGraphicsOrientationRotated90:
+                    newCode = EStdKeyRightArrow;
+                    break;
+                case CFbsBitGc::EGraphicsOrientationRotated180:
+                    newCode = EStdKeyUpArrow;
+                    break;
+                case CFbsBitGc::EGraphicsOrientationRotated270:
+                    newCode = EStdKeyLeftArrow;
+                    break;
+                default:
+                    break;
+                }
+            break;
+        case EStdKeyRightArrow:
+            switch ( finalRotation )
+                {
+                case CFbsBitGc::EGraphicsOrientationRotated90:
+                    newCode = EStdKeyUpArrow;
+                    break;
+                case CFbsBitGc::EGraphicsOrientationRotated180:
+                    newCode = EStdKeyLeftArrow;
+                    break;
+                case CFbsBitGc::EGraphicsOrientationRotated270:
+                    newCode = EStdKeyDownArrow;
+                    break;
+                default:
+                    break;
+                }
+            break;
+        case EStdKeyUpArrow:
+            switch ( finalRotation )
+                {
+                case CFbsBitGc::EGraphicsOrientationRotated90:
+                    newCode = EStdKeyLeftArrow;
+                    break;
+                case CFbsBitGc::EGraphicsOrientationRotated180:
+                    newCode = EStdKeyDownArrow;
+                    break;
+                case CFbsBitGc::EGraphicsOrientationRotated270:
+                    newCode = EStdKeyRightArrow;
+                    break;
+                default:
+                    break;
+                }
+            break;
+
+        // Diagonal events
+        case KAknStdLeftUpArrow:
+            switch ( finalRotation )
+                {
+                case CFbsBitGc::EGraphicsOrientationRotated90:
+                    newCode = KAknStdLeftDownArrow;
+                    break;
+                case CFbsBitGc::EGraphicsOrientationRotated180:
+                    newCode = KAknStdRightDownArrow;
+                    break;
+                case CFbsBitGc::EGraphicsOrientationRotated270:
+                    newCode = KAknStdRightUpArrow;
+                    break;
+                default:
+                    break;
+                }
+            break;
+
+        case KAknStdRightUpArrow:
+            switch ( finalRotation )
+                {
+                case CFbsBitGc::EGraphicsOrientationRotated90:
+                    newCode = KAknStdLeftUpArrow;
+                    break;
+                case CFbsBitGc::EGraphicsOrientationRotated180:
+                    newCode = KAknStdLeftDownArrow;
+                    break;
+                case CFbsBitGc::EGraphicsOrientationRotated270:
+                    newCode = KAknStdRightDownArrow;
+                    break;
+                default:
+                    break;
+                }
+            break;
+
+        case KAknStdLeftDownArrow:
+            switch ( finalRotation )
+                {
+                case CFbsBitGc::EGraphicsOrientationRotated90:
+                    newCode = KAknStdRightDownArrow;
+                    break;
+                case CFbsBitGc::EGraphicsOrientationRotated180:
+                    newCode = KAknStdRightUpArrow;
+                    break;
+                case CFbsBitGc::EGraphicsOrientationRotated270:
+                    newCode = KAknStdLeftUpArrow;
+                    break;
+                default:
+                    break;
+                }
+            break;
+
+        case KAknStdRightDownArrow:
+            switch ( finalRotation )
+                {
+                case CFbsBitGc::EGraphicsOrientationRotated90:
+                    newCode = KAknStdRightUpArrow;
+                    break;
+                case CFbsBitGc::EGraphicsOrientationRotated180:
+                    newCode = KAknStdLeftUpArrow;
+                    break;
+                case CFbsBitGc::EGraphicsOrientationRotated270:
+                    newCode = KAknStdLeftDownArrow;
+                    break;
+                default:
+                    break;
+                }
+            break;
+
+        default:
+            break;    
+        }
+        
+    // If the 'newCode' was updated, add that value as the new scancode with existing modifiers.
+    if ( newCode != KErrNotFound )
+        {
+        aNewRawEvent.Set(
+            aNewRawEvent.Type(),
+            (aNewRawEvent.ScanCode()&KAknModifiersMask) + newCode);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAknKeyRotatorImpl::IsArrowScanCode
+// Returns true if it's arrow scan code.
+// -----------------------------------------------------------------------------
+//
+TBool CAknKeyRotatorImpl::IsArrowScanCode(TInt aScanCode)
+    {
+    return ( aScanCode >= EStdKeyLeftArrow && aScanCode <= EStdKeyDownArrow ) ||
+           ( aScanCode >= KAknStdLeftUpArrow && aScanCode <= KAknStdLeftDownArrow );
+    }
+
+// -----------------------------------------------------------------------------
+// CAknKeyRotatorImpl::GetKeyRotatorCompensationL
+// Parses wsini.ini to read key rotator compensation value.
+// -----------------------------------------------------------------------------
+//
+TInt CAknKeyRotatorImpl::GetKeyRotatorCompensationL()
+    {
+    TInt result = 0;
+    HBufC* wsiniText = GetWsiniLC();
+    
+    // Now look for keyword
+    const TInt pos = wsiniText->Find( KAknKeyRotatorKey );
+    if ( pos != KErrNotFound )
+        {        
+        // Keyword was found. Check that it is the beginning of line.
+        // Three cases:
+        // 1. Keyword could be at the beginning of the file.
+        // 2. Keyword could be at the beginning of the file 
+        //    after byte ordering marker.
+        // 3. Previous character can be end of line marker.
+        const TInt previousPos = pos - 1;
+        if ( previousPos < 0 || 
+             ( !previousPos && 
+               IsByteOrderingMarker( (*wsiniText)[ previousPos ] ) ) || 
+             IsEndOfLine( (*wsiniText)[ previousPos ] ) )
+            {
+            TLex text( wsiniText->Mid( pos + KAknKeyRotatorKey().Length() ) );
+            
+            // First, there must be at least a space after keyword.
+            TBool fail = !( SkipSpaces( text ) & EAknWasSpace );
+           
+            // Case 1: Disabled
+            TBool wasDisabled = EFalse;
+            if ( !fail )
+                {
+                wasDisabled = 
+                    !text.Remainder().Left( KAknKeyRotatorDisabled().Length() ).
+                    CompareF( KAknKeyRotatorDisabled );
+
+                if ( wasDisabled )
+                    {
+                    // wasDisabled == True, KAknKeyRotatorDisabled was prefix
+                    // of text. So skip over it
+                    text.Inc( KAknKeyRotatorDisabled().Length() );
+                    }
+                }
+            
+            // Case 2: Then follows a sequence of digits, optionally preceded by '-'.
+            if ( !wasDisabled && !fail )
+                {
+                // Check optional -
+                TBool negate = EFalse;
+                if ( !text.Eos() && text.Peek() == '-' )
+                    {
+                    negate = ETrue;
+                    text.Inc();
+                    }
+                    
+                // Get digit sequence and convert to integer value.
+                TPtrC token = GetDigits( text );
+                fail = !token.Length() || 
+                       ( TLex( token ).Val( result ) != KErrNone );
+                
+                // Handle negation
+                if ( !fail && negate )
+                    {
+                    result = -result;
+                    }
+                }
+
+            // That sequence of digits is followed by sequence of spaces until
+            // end of line or end of file.
+            fail = fail || ( SkipSpaces( text ) & EAknWasCharacter );
+            
+            if ( !wasDisabled )
+                {
+                // Finally, that sequence of digits must represent
+                // one valid decimal value of the following: 
+                // -270, -180, -90, 0, 90, 180, 270.
+                fail = fail || !CheckCompensationValue( result );
+                }
+                
+            // If any of above checks failed, use default value 0.
+            if ( fail )
+                {
+                result = 0;
+                }
+            else
+                {
+                if ( wasDisabled )
+                    {
+                    result = KMaxTInt;
+                    }
+                }
+            }
+        }
+        
+    CleanupStack::PopAndDestroy( wsiniText );   
+    return result;
+    }
+
+// -----------------------------------------------------------------------------
+// CAknKeyRotatorImpl::IsEndOfLine
+// Checks if specified character is end of line marker.
+// -----------------------------------------------------------------------------
+//
+inline TBool CAknKeyRotatorImpl::IsEndOfLine( TText aChar )
+    {
+    return aChar == '\r' || aChar == '\n';
+    }
+
+// -----------------------------------------------------------------------------
+// CAknKeyRotatorImpl::IsByteOrderingMarker
+// Checks if specified character is byte ordering marker.
+// -----------------------------------------------------------------------------
+//
+inline TBool CAknKeyRotatorImpl::IsByteOrderingMarker( TText aChar )
+    {
+    return aChar == 0xFEFF || aChar == 0xFFFE;
+    }
+
+// -----------------------------------------------------------------------------
+// CAknKeyRotatorImpl::GetWsiniLC
+// Reads the whole wsini.ini to memory and returns in heap descriptor.
+// -----------------------------------------------------------------------------
+//
+HBufC* CAknKeyRotatorImpl::GetWsiniLC()
+    {
+    // Read the whole wsini.ini to memory
+    RFs fs;
+    User::LeaveIfError( fs.Connect() );
+    CleanupClosePushL( fs );
+    
+    TEntry wsiniEntry;
+    User::LeaveIfError( fs.Entry( KAknWsini, wsiniEntry ) );
+
+    HBufC* wsiniText = HBufC::NewLC( ( wsiniEntry.iSize + 1 )/2 );
+    TPtr wsiniPtr = wsiniText->Des();
+    TPtr8 wsiniPtr8( (TText8*)wsiniPtr.Ptr(), 0, wsiniPtr.MaxLength()*2 );
+
+    RFile wsiniFile;
+    User::LeaveIfError( wsiniFile.Open( fs, KAknWsini, EFileRead | EFileShareReadersOnly ) );
+    CleanupClosePushL( wsiniFile );
+
+    User::LeaveIfError( wsiniFile.Read( wsiniPtr8, wsiniEntry.iSize ) );
+    wsiniPtr.SetLength( wsiniPtr8.Length() / 2 );
+
+    CleanupStack::PopAndDestroy( &wsiniFile );
+    CleanupStack::Pop( wsiniText );
+    CleanupStack::PopAndDestroy( &fs );
+    CleanupStack::PushL( wsiniText );
+    return wsiniText;
+    }
+
+// -----------------------------------------------------------------------------
+// CAknKeyRotatorImpl::SkipSpaces
+// Skips over spaces.
+// -----------------------------------------------------------------------------
+//
+TInt CAknKeyRotatorImpl::SkipSpaces( TLex& aLex )
+    {
+    TInt flags = 0;
+    // Skip spaces, but stop at end of line.
+    while ( !aLex.Eos() && !IsEndOfLine( aLex.Peek() ) )
+        {
+        if ( aLex.Peek().IsSpace() )
+            {
+            // There was a space, so ok for now.
+            flags |= EAknWasSpace;
+            aLex.Inc();
+            }
+        else
+            {
+            flags |= EAknWasCharacter;
+            break;
+            }
+        }
+    return flags;
+    }
+
+// -----------------------------------------------------------------------------
+// CAknKeyRotatorImpl::SkipSpaces
+// Goes over digits and returns that sequence.
+// -----------------------------------------------------------------------------
+//
+TPtrC CAknKeyRotatorImpl::GetDigits( TLex& aLex )
+    {
+    // Mark current place and go over digits.
+    aLex.Mark();
+    while ( !aLex.Eos() && !IsEndOfLine( aLex.Peek() ) )
+        {
+        if ( aLex.Peek().IsDigit() )
+            {
+            aLex.Inc();
+            }
+        else
+            {
+            break;
+            }
+        }
+    return aLex.MarkedToken();
+    }
+
+// -----------------------------------------------------------------------------
+// CAknKeyRotatorImpl::CheckCompensationValue
+// Checks that value contains valid key rotator compensation value.
+// -----------------------------------------------------------------------------
+//
+inline TBool CAknKeyRotatorImpl::CheckCompensationValue( TInt aValue )
+    {
+    // Check absolute value
+    if ( aValue < 0 )
+        {
+        aValue = -aValue;
+        }
+        
+    return aValue == 0 ||
+           aValue == 90 ||
+           aValue == 180 ||
+           aValue == 270;
+    }
+
+// ========================== OTHER EXPORTED FUNCTIONS =========================
+
+// -----------------------------------------------------------------------------
+// Creates a CAknKeyRotatorImpl instance.
+// Returns: new CAknKeyRotatorImpl object. Ownership is returned to the caller.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CAknKeyRotator* AknKeyRotatorFactory::CreateAknKeyRotatorL()
+    {
+    return CAknKeyRotatorImpl::NewL();
+    }
+
+//  End of File