diff -r 000000000000 -r 2f259fa3e83a uifw/AvKon/AknKeyRotator/implementation/AknKeyRotatorImpl.cpp --- /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 +#include +#include +#include +#include +#include +#include + +// 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 +// where is one of the following: -270, -180, -90, -0, 0, 90, 180, 270 +// to specify 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(reader.ReadInt16()); + /*CFbsBitGc::TGraphicsOrientation altRotation =*/ + static_cast(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