Use RVCT assembler for __crash() when running armcc with the --gnu option. Fix for bug 2742.
// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "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:
// e32\ewsrv\ky_tran.cpp
// The main code for setting modifiers and translating raw scanCodes into
// keyCodes. Also traps capture-keys
//
//
#include <e32svr.h>
#include <k32keys.h>
#include <e32keys.h>
#include <e32uid.h>
enum {EDummy,EKeyDataConv,EKeyDataFunc,EKeyDataSettings};
EXPORT_C CKeyTranslator* CKeyTranslator::New()
//
// Return the actual key translator
//
{
CKeyTranslatorX* pS=new CKeyTranslatorX;
if (pS && pS->Initialise()!=KErrNone)
{
delete pS;
pS=NULL;
}
return(pS);
}
CKeyTranslatorX::CKeyTranslatorX()
#pragma warning (disable: 4705)
{
#pragma warning (default: 4705)
UpdateModifiers(0);
}
TInt CKeyTranslatorX::Initialise()
{
return (ChangeKeyData(_L(""))); //Set default keydata
}
TBool CKeyTranslatorX::currentlyUpperCase(void)
//
// Determines whether a letter should be returned as upper case given the
// current state of the modifiers. This is used for accented characters
// created, for example, by entering Ctrl-1 "a". Since the keyboard may be
// configured in different ways (e.g. shift AND capslock together may result
// in either upper or lower case letters), a dynamic function such as this
// is necessary
//
{
TInt modifiersAffectingUpperCase=0;
if (iCurModifiers&EModifierCapsLock)
modifiersAffectingUpperCase|=EModifierCapsLock;
if (iCurModifiers&EModifierShift)
modifiersAffectingUpperCase|=EModifierShift;
for (TUint i=iConvTable.FirstScanCode(); i<=iConvTable.LastScanCode(); i++)
{
TChar ch=iConvTable.Convert(i, modifiersAffectingUpperCase).keyCode;
if (ch.IsUpper())
return ETrue;
else if (ch.IsLower())
return EFalse;
}
return EFalse;
}
TUint CKeyTranslatorX::executeFunctionsAndSetState(TCharExtended aChar)
//
// Looks up and carries out the function required for the given
// key-code/modifiers/state
//
{
TUint keyCode=EKeyNull;
SFunc modifierFunc=iFuncTable.GetModifierFunc(aChar, iCurModifiers);
SFuncAndState genFuncAndNewState=iFuncTable.GetGeneralFuncAndState(aChar, iCurModifiers, iCurState,
iCurCtrlDigits.GetRadix());
SetModifierState((TEventModifier)modifierFunc.funcParam,(TModifierState)modifierFunc.func);
if(!(iCurModifiers&(EModifierLeftAlt|EModifierRightAlt)))
iCurModifiers&=~EModifierAlt;
if(!(iCurModifiers&(EModifierLeftShift|EModifierRightShift)))
iCurModifiers&=~EModifierShift;
if(!(iCurModifiers&(EModifierLeftFunc|EModifierRightFunc)))
iCurModifiers&=~EModifierFunc;
if(!(iCurModifiers&(EModifierLeftCtrl|EModifierRightCtrl)))
iCurModifiers&=~EModifierCtrl;
switch (genFuncAndNewState.func)
{
case EDoNothing:
break;
case EPassKeyThru:
keyCode=aChar;
break;
case EPassSpecialKeyThru:
iCurCtrlDigits.Reset();
keyCode=(currentlyUpperCase())?
User::UpperCase(genFuncAndNewState.funcParam):
genFuncAndNewState.funcParam;
iCurModifiers|=(EModifierSpecial);
break;
case EPassCtrlDigitsThru:
if (iCurCtrlDigits.WithinLimits())
{
keyCode=iCurCtrlDigits.GetDigits();
iCurModifiers|=(EModifierSpecial);
}
iCurCtrlDigits.Reset();
break;
case EAddOnCtrlDigit:
iCurCtrlDigits.AppendDigit(aChar, iCurModifiers);
if (iCurCtrlDigits.Terminated(iCurModifiers) && !iCurCtrlDigits.Error() && iCurCtrlDigits.WithinLimits())
{
keyCode=iCurCtrlDigits.GetDigits();
iCurModifiers|=(EModifierSpecial);
}
break;
}
switch (genFuncAndNewState.state)
{
case EStateUnchanged:
break;
case EStateDerivedFromDigitEntered:
iCurState=aChar.DigitValue();
break;
case EStateCtrlDigits:
if (iCurCtrlDigits.Terminated(iCurModifiers) || iCurCtrlDigits.Error())
{
iCurState=EStateNormal;
iCurCtrlDigits.Reset();
}
else
iCurState=iCurCtrlDigits.SetStateToCtrlDigits();
break;
default:
iCurState=genFuncAndNewState.state;
if (iCurState==EStateNormal)
iCurCtrlDigits.Reset();
break;
}
return keyCode;
}
TInt CKeyTranslatorX::GetModifierState()
//
// Return the current modifier state
//
{
return(iCurModifiers);
}
void CKeyTranslatorX::UpdateModifiers(TInt aModifiers)
//
//
//
{
if(aModifiers == EModifierCancelRotation || aModifiers & KRotationModifiers)
iCurModifiers &= KPersistentModifiers; // if a Rotation modifier is being updated, only keep persistent modifiers
else
iCurModifiers &= KPersistentModifiers|KRotationModifiers; // if not, keep Rotation modifiers also
iCurModifiers |= aModifiers;
iCurState = EStateNormal;
}
void CKeyTranslatorX::SetModifierState(TEventModifier aModifier,TModifierState aState)
//
// Change a modifier state
//
{
switch(aState)
{
case ETurnOffModifier:
iCurModifiers&=~aModifier;
break;
case ETurnOnModifier:
iCurModifiers|=aModifier;
break;
case EToggleModifier:
iCurModifiers^=aModifier;
}
}
TBool CKeyTranslatorX::TranslateKey(TUint aScanCode, TBool aKeyUp,
const CCaptureKeys &aCaptureKeys, TKeyData &aKeyData)
//
// The function called for every keyup/keydown converting the aScanCode into a
// keyCode, carrying out the function specified in the keyboard configuration
// tables and setting the new state of the keyboard
//
{
#if defined(__WINS__)
// This code extracts the character code if there is one munged
// with the scan code. Code which does not take advantage of this
// new facility to pass a character code as part of aScanCode should
// be unaffected
//
// extract the character code
TUint charCode=(aScanCode&0xFFFF0000)>>16;
// extract the scan code
aScanCode&=0x0000FFFF;
#endif
TUint oldState=iCurState;
TCharExtended ch;
iCurModifiers&=~(EModifierPureKeycode);
if(aScanCode<ESpecialKeyBase || aScanCode>=(ESpecialKeyBase+ESpecialKeyCount))
{
SConvKeyData convKeyData=(iCurState==EStateNormal)?
iConvTable.Convert(aScanCode, iCurModifiers):
iConvTable.ConvertBaseCase(aScanCode, iCurModifiers);
TMaskedModifiers convModifiers;
convModifiers.iMask=KConvTableSettableModifiers;
convModifiers.iValue=convKeyData.modifiers;
MergeModifiers(iCurModifiers,convModifiers);
ch=convKeyData.keyCode;
}
else
ch=aScanCode;
if (aKeyUp)
iCurModifiers|=(EModifierKeyUp);
else
iCurModifiers&=~(EModifierKeyUp);
aKeyData.iKeyCode=executeFunctionsAndSetState(ch);
ch=aKeyData.iKeyCode;
// prevent modifier keys returning as keypresses
if(ch.IsModifier())
{
aKeyData.iKeyCode=EKeyNull;
iCurModifiers&=~EModifierPureKeycode;
}
TBool ret;
ret=(aKeyData.iKeyCode!=EKeyNull);
#if defined(__WINS__)
// see comments in __WINS__ block above
if (charCode)
{
if (!(iCurModifiers & KRotationModifiers)) // if rotation modifiers not set we trust the WINDOWS translation
{
aKeyData.iKeyCode=charCode;
iCurModifiers|=EModifierAutorepeatable;
}
ret = ETrue;
}
#endif
if (aKeyUp
|| (aKeyData.iKeyCode==EKeyNull)
|| (iCurState!=EStateNormal)
|| (iCurState!=oldState))
{
iCurModifiers&=~(EModifierAutorepeatable);
}
// convert ctrl-space to EKeyNull and clear PureKeycode modifier
if(aKeyData.iKeyCode==EKeySpace && iCurModifiers&EModifierCtrl)
{
aKeyData.iKeyCode=EKeyNull;
iCurModifiers&=~EModifierPureKeycode;
}
aKeyData.iModifiers=iCurModifiers;
iCurModifiers&=(KPersistentModifiers|KRotationModifiers); // only keep persistent and rotation modifiers
#if defined(__WINS__)
if (ret)
{
if (charCode && (iCurModifiers & KRotationModifiers))
{
TKeyData keyData = aKeyData;
keyData.iKeyCode = charCode;
aCaptureKeys.ProcessCaptureKeys(keyData);
// Pass the key capture data to the argument
aKeyData.iApp = keyData.iApp;
aKeyData.iHandle = keyData.iHandle;
aKeyData.iIsCaptureKey = keyData.iIsCaptureKey;
}
else
aCaptureKeys.ProcessCaptureKeys(aKeyData);
}
#else
if (ret)
aCaptureKeys.ProcessCaptureKeys(aKeyData);
#endif
return(ret);
}
//
// A miscellaneous collection of classes used in key translation
//
TCharExtended &TCharExtended::operator=(TUint aChar)
{
SetChar(aChar);
return *this;
}
//
TBool TCharExtended::IsDigitGivenRadix(TRadix aRadix) const
// Returns true if the character is a digit given the aRadix
{
switch (aRadix)
{
case EBinary:
return (TBool)((TUint(*this)==(TUint)'0') || (TUint(*this)==(TUint)'1'));
case EOctal:
return (TBool)(IsDigit() && (TUint(*this)!=(TUint)'8') && (TUint(*this)!=(TUint)'9'));
case EDecimal:
return IsDigit();
case EHex:
return IsHexDigit();
default:
return EFalse;
}
}
//
TBool TCharExtended::IsModifier() const
{
switch ((TUint)(*this))
{
case EKeyLeftShift:
case EKeyLeftFunc:
case EKeyLeftCtrl:
case EKeyLeftAlt:
case EKeyRightShift:
case EKeyRightFunc:
case EKeyRightCtrl:
case EKeyRightAlt:
case EKeyCapsLock:
case EKeyNumLock:
case EKeyScrollLock:
case EKeyKeyboardExtend:
return ETrue;
default:
return EFalse;
}
}
//
TInt TCharExtended::DigitValue() const
// Return the numeric value of the character if it is a digit, otherwise an errorcode
{
if (IsDigit())
return (TInt(*this))-48;
else if ((TInt(*this)>='A') && (TUint(*this)<='F'))
return (TInt(*this))+10-'A';
else if ((TInt(*this)>='a') && (TUint(*this)<='f'))
return (TInt(*this))+10-'a';
else
return KErrArgument;
}
//
TBool TCharExtended::MatchesPattern(const TKeyCodePattern &aKeyCodePattern, TRadix aRadix) const
// Return true if the character matches the given pattern
{
switch (aKeyCodePattern.iPattern)
{
case EAnyKey:
return ETrue;
case EAnyAlphaNumeric:
return IsAlphaDigit();
case EAnyAlpha:
return IsAlpha();
case EAnyAlphaLowerCase:
return IsLower();
case EAnyAlphaUpperCase:
return IsUpper();
case EAnyDecimalDigit:
return IsDigit();
case EAnyDigitGivenRadix:
return IsDigitGivenRadix(aRadix);
case EAnyModifierKey:
return IsModifier();
case EMatchLeftOrRight:
return (TBool)(TUint(*this)==aKeyCodePattern.iKeyCode || TUint(*this)==(aKeyCodePattern.iKeyCode+(TUint)1));
case EMatchKey:
return (TBool)(TUint(*this)==aKeyCodePattern.iKeyCode);
case EMatchKeyCaseInsens:
return (TBool)(User::LowerCase((TUint)*this)==User::LowerCase(aKeyCodePattern.iKeyCode));
default:
return EFalse;
}
}
//
typedef void (*TLibFnDataSetting)(TRadix &aRadix,TCtrlDigitsTermination &aCtrlDigitsTermination,TInt &aDefaultCtrlDigitsMaxCount,
TInt &aMaximumCtrlDigitsMaxCount);
void TCtrlDigits::Update(RLibrary aLibrary)
{
((TLibFnDataSetting)aLibrary.Lookup(EKeyDataSettings))(iRadix,iTermination,iMaxCount,iMaximumCtrlDigitsMaxCount);
iCount=0;
iErrorFlag=EFalse;
iDigits=0L;
};
//
TCtrlDigits::TCtrlDigits()
{
};
//
void TCtrlDigits::Reset()
// Reset to 0
{
iCount=0;
iErrorFlag=EFalse;
iDigits=0L;
};
//
void TCtrlDigits::AppendDigit(TUint aKeyCode, TUint aModifiers)
// Append the given digit to the current digits
{
TCharExtended ch=aKeyCode;
iCount++;
iDigits*=iRadix;
iDigits+=ch.DigitValue();
iErrorFlag=(TBool)(iErrorFlag
|| !ch.IsDigitGivenRadix(iRadix)
|| (iTermination==ETerminationByCtrlUp)
&& ((aModifiers&EModifierCtrl)==0));
}
//
TBool TCtrlDigits::Terminated(TInt aModifiers) const
// Return true if the digits have been terminated and are ready to return as a keyCode
{
return (TBool)( ((iTermination==ETerminationByCount) && (iCount>=iMaxCount))
|| ((iTermination==ETerminationByCtrlUp) && (aModifiers&EModifierCtrl)==0)
|| (iCount>=iMaximumCtrlDigitsMaxCount) );
}
//
TUint TCtrlDigits::SetStateToCtrlDigits() const
// Return either "EStateCtrlDigitsUntilCount" or "EStateCtrlDigitsUntilCtrlUp"
// according to the current termination type
{
switch (iTermination)
{
case ETerminationByCount:
return EStateCtrlDigitsUntilCount;
case ETerminationByCtrlUp:
return EStateCtrlDigitsUntilCtrlUp;
default:
return EStateNormal;
}
}
//
// Two classes that provide operations for accessing the keyboard configuration tables
//
typedef void (*TLibFnDataConv)(SConvTable &aConvTable, TUint &aConvTableFirstScanCode,TUint &aConvTableLastScanCode,
SScanCodeBlockList &aKeypadScanCode,SKeyCodeList &aNonAutorepKeyCodes);
//
void TConvTable::Update(RLibrary aLibrary)
#pragma warning (disable: 4705)
{
#pragma warning (default: 4705)
((TLibFnDataConv)aLibrary.Lookup(EKeyDataConv))(iConvTable,iFirstScanCode,iLastScanCode,iKeypadScanCodes,iNonAutorepKeyCodes);
}
//
//
TConvTable::TConvTable()
#pragma warning (disable: 4705)
{
#pragma warning (default: 4705)
}
//
TBool TConvTable::onKeypad(TUint aScanCode) const
// Return True if the given aScanCode is on the keypad
{
for (TUint i=0; i<iKeypadScanCodes.numBlocks; i++)
if ((aScanCode>=iKeypadScanCodes.pblocks[i].firstScanCode)
&& (aScanCode<=iKeypadScanCodes.pblocks[i].lastScanCode))
{
return ETrue;
}
return EFalse;
}
//
TBool TConvTable::autorepeatable(TUint aKeyCode) const
// Return True if the given aKeyCode is autorepeatable
{
for (TUint i=0; i<iNonAutorepKeyCodes.numKeyCodes; i++)
if (aKeyCode==iNonAutorepKeyCodes.pkeyCodes[i])
return EFalse;
return ETrue;
}
//
SConvKeyData TConvTable::Convert(TUint aScanCode, const TInt &aModifiers) const
// Convert the given aScanCode and aModifiers into a keyCode and aModifiers
{
SConvKeyData returnVal;
returnVal.keyCode=EKeyNull;
returnVal.modifiers=0;
returnVal.filler = 0;
for (TUint i=0; i<iConvTable.numNodes; i++)
{
if (MatchesMaskedValue(aModifiers,iConvTable.pnodes[i].maskedModifiers))
{
for (TUint j=0; j<iConvTable.pnodes[i].numSubTables; j++)
{
TUint offset=0;
for (TUint k=0; k<iConvTable.pnodes[i].ppsubTables[j]->scanCodes.numBlocks; k++)
{
if ((aScanCode>=iConvTable.pnodes[i].ppsubTables[j]->scanCodes.pblocks[k].firstScanCode) &&
(aScanCode<=iConvTable.pnodes[i].ppsubTables[j]->scanCodes.pblocks[k].lastScanCode))
{
returnVal.keyCode=iConvTable.pnodes[i].ppsubTables[j]->pkeyCode[offset+
(aScanCode-iConvTable.pnodes[i].ppsubTables[j]->scanCodes.pblocks[k].firstScanCode)];
if (onKeypad(aScanCode))
returnVal.modifiers|=(EModifierKeypad);
if (autorepeatable(returnVal.keyCode))
returnVal.modifiers|=(EModifierAutorepeatable);
// check if ctrl key pressed and keycode has not been modified due to ctrl key
if (aModifiers&EModifierCtrl && !(iConvTable.pnodes[i].maskedModifiers.iMask&EModifierCtrl))
returnVal.modifiers|=(EModifierPureKeycode);
return returnVal;
}
else
offset+=iConvTable.pnodes[i].ppsubTables[j]->scanCodes.pblocks[k].lastScanCode-
iConvTable.pnodes[i].ppsubTables[j]->scanCodes.pblocks[k].firstScanCode+1;
}
}
}
}
return returnVal;
}
//
SConvKeyData TConvTable::ConvertBaseCase(TUint aScanCode, const TInt &aModifiers) const
// As TConvTable::Convert above, except that all input aModifiers are ignored except for EModifierNumlock
{
if (aModifiers&EModifierNumLock)
return Convert(aScanCode, EModifierNumLock);
else
return Convert(aScanCode, 0);
}
typedef void (*TLibFnDataFunc)(SFuncTables &aFuncTables);
void TFuncTable::Update(RLibrary aLibrary)
#pragma warning (disable: 4705)
{
#pragma warning (default: 4705)
((TLibFnDataFunc)aLibrary.Lookup(EKeyDataFunc))(iFuncTables);
}
//
TFuncTable::TFuncTable()
#pragma warning (disable: 4705)
{
#pragma warning (default: 4705)
}
//
SFuncTableEntry TFuncTable::getDefault(const TCharExtended &aChar, const TInt &aModifiers) const
// Get the default table entry. Should be called if passing through a normal function-table did
// not trap these parameters.
{
TUint i=0;
while(i<iFuncTables.defaultTable.numEntries)
{
if (aChar.MatchesPattern(iFuncTables.defaultTable.pentries[i].keyCodePattern)
&& MatchesMaskedValue(aModifiers,iFuncTables.defaultTable.pentries[i].maskedModifiers))
{
break;
}
i++;
}
return iFuncTables.defaultTable.pentries[i];
}
SFunc TFuncTable::GetModifierFunc(const TCharExtended &aChar, const TInt &aModifiers) const
// Pass through the modifier table, returning the first table entry matching the given parameters.
{
SFuncTableEntry defaultTableEntry=getDefault(aChar, aModifiers);
SFunc returnVal = { 0, 0, 0 };
returnVal.func=defaultTableEntry.funcAndNewState.func;
returnVal.funcParam=defaultTableEntry.funcAndNewState.funcParam;
for (TUint i=0; i<iFuncTables.modifierTable.numEntries; i++)
if (aChar.MatchesPattern(iFuncTables.modifierTable.pentries[i].keyCodePattern)
&& MatchesMaskedValue(aModifiers,iFuncTables.modifierTable.pentries[i].maskedModifiers))
{
returnVal.func=iFuncTables.modifierTable.pentries[i].funcAndNewState.func;
returnVal.funcParam=iFuncTables.modifierTable.pentries[i].funcAndNewState.funcParam;
return returnVal;
}
return returnVal;
}
SFuncAndState TFuncTable::GetGeneralFuncAndState(const TCharExtended &aChar, const TInt &aModifiers,
TUint aCurState, TRadix aRadix) const
// Pass through the table corresponding to the current keyboard state, returning the first
// table entry matching the given parameters.
{
for (TUint i=0; i<iFuncTables.pgenFuncTables[aCurState].numEntries; i++)
if (aChar.MatchesPattern(iFuncTables.pgenFuncTables[aCurState].pentries[i].keyCodePattern, aRadix)
&& MatchesMaskedValue(aModifiers,iFuncTables.pgenFuncTables[aCurState].pentries[i].maskedModifiers))
{
return iFuncTables.pgenFuncTables[aCurState].pentries[i].funcAndNewState;
}
return getDefault(aChar, aModifiers).funcAndNewState;
}
TInt CKeyTranslatorX::ChangeKeyData(const TDesC& aLibName)
//
// change keydata
//
{
if(aLibName.Length()==0) // Back to default KeyData
{
if (!iIsdefaultKeyData)
{
_LIT(KEkData,"EKDATA.DLL");
TInt r=iDefaultKeyDataLib.Load(KEkData);
if (r!=KErrNone && r!=KErrAlreadyExists)
return r;
// Check for valid KeyboardData dll type
if(iDefaultKeyDataLib.Type()[2]!=KKeyboardDataUid)
{
iDefaultKeyDataLib.Close();
return(KErrCorrupt);//Only due to bad rom.
}
iConvTable.Update(iDefaultKeyDataLib);
iCurCtrlDigits.Update(iDefaultKeyDataLib);
iFuncTable.Update(iDefaultKeyDataLib);
iIsdefaultKeyData = ETrue; // EKeyData status
iKeyDataLib.Close(); // Close previously loaded keydata
}
return(KErrNone);
}
//
RLibrary lib;
TInt res=lib.Load(aLibName);
if (res!=KErrNone && res!=KErrAlreadyExists)
return(res);
//
// Check for valid KeyboardData dll type
//
if(lib.Type()[2]!=KKeyboardDataUid)
{
lib.Close();
return(KErrArgument);
}
// Close previously loaded keydata
if (iIsdefaultKeyData)
{
iIsdefaultKeyData = EFalse; // EKeyData status
iDefaultKeyDataLib.Close();
}
else
iKeyDataLib.Close();
iKeyDataLib=lib;
iConvTable.Update(lib);
iCurCtrlDigits.Update(lib);
iFuncTable.Update(lib);
return(KErrNone);
}