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