Update contrib.
1 // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32\ewsrv\ky_tran.cpp
15 // The main code for setting modifiers and translating raw scanCodes into
16 // keyCodes. Also traps capture-keys
26 enum {EDummy,EKeyDataConv,EKeyDataFunc,EKeyDataSettings};
28 EXPORT_C CKeyTranslator* CKeyTranslator::New()
30 // Return the actual key translator
34 CKeyTranslatorX* pS=new CKeyTranslatorX;
35 if (pS && pS->Initialise()!=KErrNone)
43 CKeyTranslatorX::CKeyTranslatorX()
44 #pragma warning (disable: 4705)
46 #pragma warning (default: 4705)
52 TInt CKeyTranslatorX::Initialise()
54 return (ChangeKeyData(_L(""))); //Set default keydata
57 TBool CKeyTranslatorX::currentlyUpperCase(void)
59 // Determines whether a letter should be returned as upper case given the
60 // current state of the modifiers. This is used for accented characters
61 // created, for example, by entering Ctrl-1 "a". Since the keyboard may be
62 // configured in different ways (e.g. shift AND capslock together may result
63 // in either upper or lower case letters), a dynamic function such as this
67 TInt modifiersAffectingUpperCase=0;
69 if (iCurModifiers&EModifierCapsLock)
70 modifiersAffectingUpperCase|=EModifierCapsLock;
72 if (iCurModifiers&EModifierShift)
73 modifiersAffectingUpperCase|=EModifierShift;
75 for (TUint i=iConvTable.FirstScanCode(); i<=iConvTable.LastScanCode(); i++)
77 TChar ch=iConvTable.Convert(i, modifiersAffectingUpperCase).keyCode;
80 else if (ch.IsLower())
86 TUint CKeyTranslatorX::executeFunctionsAndSetState(TCharExtended aChar)
88 // Looks up and carries out the function required for the given
89 // key-code/modifiers/state
92 TUint keyCode=EKeyNull;
93 SFunc modifierFunc=iFuncTable.GetModifierFunc(aChar, iCurModifiers);
94 SFuncAndState genFuncAndNewState=iFuncTable.GetGeneralFuncAndState(aChar, iCurModifiers, iCurState,
95 iCurCtrlDigits.GetRadix());
97 SetModifierState((TEventModifier)modifierFunc.funcParam,(TModifierState)modifierFunc.func);
99 if(!(iCurModifiers&(EModifierLeftAlt|EModifierRightAlt)))
100 iCurModifiers&=~EModifierAlt;
101 if(!(iCurModifiers&(EModifierLeftShift|EModifierRightShift)))
102 iCurModifiers&=~EModifierShift;
103 if(!(iCurModifiers&(EModifierLeftFunc|EModifierRightFunc)))
104 iCurModifiers&=~EModifierFunc;
105 if(!(iCurModifiers&(EModifierLeftCtrl|EModifierRightCtrl)))
106 iCurModifiers&=~EModifierCtrl;
108 switch (genFuncAndNewState.func)
115 case EPassSpecialKeyThru:
116 iCurCtrlDigits.Reset();
117 keyCode=(currentlyUpperCase())?
118 User::UpperCase(genFuncAndNewState.funcParam):
119 genFuncAndNewState.funcParam;
120 iCurModifiers|=(EModifierSpecial);
122 case EPassCtrlDigitsThru:
123 if (iCurCtrlDigits.WithinLimits())
125 keyCode=iCurCtrlDigits.GetDigits();
126 iCurModifiers|=(EModifierSpecial);
128 iCurCtrlDigits.Reset();
130 case EAddOnCtrlDigit:
131 iCurCtrlDigits.AppendDigit(aChar, iCurModifiers);
132 if (iCurCtrlDigits.Terminated(iCurModifiers) && !iCurCtrlDigits.Error() && iCurCtrlDigits.WithinLimits())
134 keyCode=iCurCtrlDigits.GetDigits();
135 iCurModifiers|=(EModifierSpecial);
140 switch (genFuncAndNewState.state)
142 case EStateUnchanged:
144 case EStateDerivedFromDigitEntered:
145 iCurState=aChar.DigitValue();
147 case EStateCtrlDigits:
148 if (iCurCtrlDigits.Terminated(iCurModifiers) || iCurCtrlDigits.Error())
150 iCurState=EStateNormal;
151 iCurCtrlDigits.Reset();
154 iCurState=iCurCtrlDigits.SetStateToCtrlDigits();
157 iCurState=genFuncAndNewState.state;
158 if (iCurState==EStateNormal)
159 iCurCtrlDigits.Reset();
165 TInt CKeyTranslatorX::GetModifierState()
167 // Return the current modifier state
171 return(iCurModifiers);
174 void CKeyTranslatorX::UpdateModifiers(TInt aModifiers)
180 if(aModifiers == EModifierCancelRotation || aModifiers & KRotationModifiers)
181 iCurModifiers &= KPersistentModifiers; // if a Rotation modifier is being updated, only keep persistent modifiers
183 iCurModifiers &= KPersistentModifiers|KRotationModifiers; // if not, keep Rotation modifiers also
184 iCurModifiers |= aModifiers;
185 iCurState = EStateNormal;
189 void CKeyTranslatorX::SetModifierState(TEventModifier aModifier,TModifierState aState)
191 // Change a modifier state
197 case ETurnOffModifier:
198 iCurModifiers&=~aModifier;
200 case ETurnOnModifier:
201 iCurModifiers|=aModifier;
203 case EToggleModifier:
204 iCurModifiers^=aModifier;
208 TBool CKeyTranslatorX::TranslateKey(TUint aScanCode, TBool aKeyUp,
209 const CCaptureKeys &aCaptureKeys, TKeyData &aKeyData)
211 // The function called for every keyup/keydown converting the aScanCode into a
212 // keyCode, carrying out the function specified in the keyboard configuration
213 // tables and setting the new state of the keyboard
217 #if defined(__WINS__)
218 // This code extracts the character code if there is one munged
219 // with the scan code. Code which does not take advantage of this
220 // new facility to pass a character code as part of aScanCode should
223 // extract the character code
224 TUint charCode=(aScanCode&0xFFFF0000)>>16;
225 // extract the scan code
226 aScanCode&=0x0000FFFF;
229 TUint oldState=iCurState;
232 iCurModifiers&=~(EModifierPureKeycode);
234 if(aScanCode<ESpecialKeyBase || aScanCode>=(ESpecialKeyBase+ESpecialKeyCount))
236 SConvKeyData convKeyData=(iCurState==EStateNormal)?
237 iConvTable.Convert(aScanCode, iCurModifiers):
238 iConvTable.ConvertBaseCase(aScanCode, iCurModifiers);
240 TMaskedModifiers convModifiers;
241 convModifiers.iMask=KConvTableSettableModifiers;
242 convModifiers.iValue=convKeyData.modifiers;
244 MergeModifiers(iCurModifiers,convModifiers);
245 ch=convKeyData.keyCode;
251 iCurModifiers|=(EModifierKeyUp);
253 iCurModifiers&=~(EModifierKeyUp);
255 aKeyData.iKeyCode=executeFunctionsAndSetState(ch);
257 ch=aKeyData.iKeyCode;
258 // prevent modifier keys returning as keypresses
261 aKeyData.iKeyCode=EKeyNull;
262 iCurModifiers&=~EModifierPureKeycode;
267 ret=(aKeyData.iKeyCode!=EKeyNull);
269 #if defined(__WINS__)
270 // see comments in __WINS__ block above
273 if (!(iCurModifiers & KRotationModifiers)) // if rotation modifiers not set we trust the WINDOWS translation
275 aKeyData.iKeyCode=charCode;
276 iCurModifiers|=EModifierAutorepeatable;
283 || (aKeyData.iKeyCode==EKeyNull)
284 || (iCurState!=EStateNormal)
285 || (iCurState!=oldState))
287 iCurModifiers&=~(EModifierAutorepeatable);
290 // convert ctrl-space to EKeyNull and clear PureKeycode modifier
291 if(aKeyData.iKeyCode==EKeySpace && iCurModifiers&EModifierCtrl)
293 aKeyData.iKeyCode=EKeyNull;
294 iCurModifiers&=~EModifierPureKeycode;
297 aKeyData.iModifiers=iCurModifiers;
299 iCurModifiers&=(KPersistentModifiers|KRotationModifiers); // only keep persistent and rotation modifiers
301 #if defined(__WINS__)
304 if (charCode && (iCurModifiers & KRotationModifiers))
306 TKeyData keyData = aKeyData;
307 keyData.iKeyCode = charCode;
308 aCaptureKeys.ProcessCaptureKeys(keyData);
309 // Pass the key capture data to the argument
310 aKeyData.iApp = keyData.iApp;
311 aKeyData.iHandle = keyData.iHandle;
312 aKeyData.iIsCaptureKey = keyData.iIsCaptureKey;
315 aCaptureKeys.ProcessCaptureKeys(aKeyData);
319 aCaptureKeys.ProcessCaptureKeys(aKeyData);
325 // A miscellaneous collection of classes used in key translation
327 TCharExtended &TCharExtended::operator=(TUint aChar)
333 TBool TCharExtended::IsDigitGivenRadix(TRadix aRadix) const
334 // Returns true if the character is a digit given the aRadix
339 return (TBool)((TUint(*this)==(TUint)'0') || (TUint(*this)==(TUint)'1'));
341 return (TBool)(IsDigit() && (TUint(*this)!=(TUint)'8') && (TUint(*this)!=(TUint)'9'));
351 TBool TCharExtended::IsModifier() const
353 switch ((TUint)(*this))
366 case EKeyKeyboardExtend:
373 TInt TCharExtended::DigitValue() const
374 // Return the numeric value of the character if it is a digit, otherwise an errorcode
378 return (TInt(*this))-48;
379 else if ((TInt(*this)>='A') && (TUint(*this)<='F'))
380 return (TInt(*this))+10-'A';
381 else if ((TInt(*this)>='a') && (TUint(*this)<='f'))
382 return (TInt(*this))+10-'a';
387 TBool TCharExtended::MatchesPattern(const TKeyCodePattern &aKeyCodePattern, TRadix aRadix) const
388 // Return true if the character matches the given pattern
390 switch (aKeyCodePattern.iPattern)
394 case EAnyAlphaNumeric:
395 return IsAlphaDigit();
398 case EAnyAlphaLowerCase:
400 case EAnyAlphaUpperCase:
402 case EAnyDecimalDigit:
404 case EAnyDigitGivenRadix:
405 return IsDigitGivenRadix(aRadix);
406 case EAnyModifierKey:
408 case EMatchLeftOrRight:
409 return (TBool)(TUint(*this)==aKeyCodePattern.iKeyCode || TUint(*this)==(aKeyCodePattern.iKeyCode+(TUint)1));
411 return (TBool)(TUint(*this)==aKeyCodePattern.iKeyCode);
412 case EMatchKeyCaseInsens:
413 return (TBool)(User::LowerCase((TUint)*this)==User::LowerCase(aKeyCodePattern.iKeyCode));
419 typedef void (*TLibFnDataSetting)(TRadix &aRadix,TCtrlDigitsTermination &aCtrlDigitsTermination,TInt &aDefaultCtrlDigitsMaxCount,
420 TInt &aMaximumCtrlDigitsMaxCount);
422 void TCtrlDigits::Update(RLibrary aLibrary)
425 ((TLibFnDataSetting)aLibrary.Lookup(EKeyDataSettings))(iRadix,iTermination,iMaxCount,iMaximumCtrlDigitsMaxCount);
431 TCtrlDigits::TCtrlDigits()
435 void TCtrlDigits::Reset()
444 void TCtrlDigits::AppendDigit(TUint aKeyCode, TUint aModifiers)
445 // Append the given digit to the current digits
448 TCharExtended ch=aKeyCode;
451 iDigits+=ch.DigitValue();
452 iErrorFlag=(TBool)(iErrorFlag
453 || !ch.IsDigitGivenRadix(iRadix)
454 || (iTermination==ETerminationByCtrlUp)
455 && ((aModifiers&EModifierCtrl)==0));
458 TBool TCtrlDigits::Terminated(TInt aModifiers) const
459 // Return true if the digits have been terminated and are ready to return as a keyCode
461 return (TBool)( ((iTermination==ETerminationByCount) && (iCount>=iMaxCount))
462 || ((iTermination==ETerminationByCtrlUp) && (aModifiers&EModifierCtrl)==0)
463 || (iCount>=iMaximumCtrlDigitsMaxCount) );
466 TUint TCtrlDigits::SetStateToCtrlDigits() const
467 // Return either "EStateCtrlDigitsUntilCount" or "EStateCtrlDigitsUntilCtrlUp"
468 // according to the current termination type
470 switch (iTermination)
472 case ETerminationByCount:
473 return EStateCtrlDigitsUntilCount;
474 case ETerminationByCtrlUp:
475 return EStateCtrlDigitsUntilCtrlUp;
481 // Two classes that provide operations for accessing the keyboard configuration tables
483 typedef void (*TLibFnDataConv)(SConvTable &aConvTable, TUint &aConvTableFirstScanCode,TUint &aConvTableLastScanCode,
484 SScanCodeBlockList &aKeypadScanCode,SKeyCodeList &aNonAutorepKeyCodes);
486 void TConvTable::Update(RLibrary aLibrary)
487 #pragma warning (disable: 4705)
489 #pragma warning (default: 4705)
490 ((TLibFnDataConv)aLibrary.Lookup(EKeyDataConv))(iConvTable,iFirstScanCode,iLastScanCode,iKeypadScanCodes,iNonAutorepKeyCodes);
494 TConvTable::TConvTable()
495 #pragma warning (disable: 4705)
497 #pragma warning (default: 4705)
500 TBool TConvTable::onKeypad(TUint aScanCode) const
501 // Return True if the given aScanCode is on the keypad
503 for (TUint i=0; i<iKeypadScanCodes.numBlocks; i++)
504 if ((aScanCode>=iKeypadScanCodes.pblocks[i].firstScanCode)
505 && (aScanCode<=iKeypadScanCodes.pblocks[i].lastScanCode))
513 TBool TConvTable::autorepeatable(TUint aKeyCode) const
514 // Return True if the given aKeyCode is autorepeatable
516 for (TUint i=0; i<iNonAutorepKeyCodes.numKeyCodes; i++)
517 if (aKeyCode==iNonAutorepKeyCodes.pkeyCodes[i])
523 SConvKeyData TConvTable::Convert(TUint aScanCode, const TInt &aModifiers) const
524 // Convert the given aScanCode and aModifiers into a keyCode and aModifiers
526 SConvKeyData returnVal;
527 returnVal.keyCode=EKeyNull;
528 returnVal.modifiers=0;
530 for (TUint i=0; i<iConvTable.numNodes; i++)
532 if (MatchesMaskedValue(aModifiers,iConvTable.pnodes[i].maskedModifiers))
534 for (TUint j=0; j<iConvTable.pnodes[i].numSubTables; j++)
537 for (TUint k=0; k<iConvTable.pnodes[i].ppsubTables[j]->scanCodes.numBlocks; k++)
539 if ((aScanCode>=iConvTable.pnodes[i].ppsubTables[j]->scanCodes.pblocks[k].firstScanCode) &&
540 (aScanCode<=iConvTable.pnodes[i].ppsubTables[j]->scanCodes.pblocks[k].lastScanCode))
542 returnVal.keyCode=iConvTable.pnodes[i].ppsubTables[j]->pkeyCode[offset+
543 (aScanCode-iConvTable.pnodes[i].ppsubTables[j]->scanCodes.pblocks[k].firstScanCode)];
544 if (onKeypad(aScanCode))
545 returnVal.modifiers|=(EModifierKeypad);
546 if (autorepeatable(returnVal.keyCode))
547 returnVal.modifiers|=(EModifierAutorepeatable);
549 // check if ctrl key pressed and keycode has not been modified due to ctrl key
550 if (aModifiers&EModifierCtrl && !(iConvTable.pnodes[i].maskedModifiers.iMask&EModifierCtrl))
551 returnVal.modifiers|=(EModifierPureKeycode);
555 offset+=iConvTable.pnodes[i].ppsubTables[j]->scanCodes.pblocks[k].lastScanCode-
556 iConvTable.pnodes[i].ppsubTables[j]->scanCodes.pblocks[k].firstScanCode+1;
564 SConvKeyData TConvTable::ConvertBaseCase(TUint aScanCode, const TInt &aModifiers) const
565 // As TConvTable::Convert above, except that all input aModifiers are ignored except for EModifierNumlock
567 if (aModifiers&EModifierNumLock)
568 return Convert(aScanCode, EModifierNumLock);
570 return Convert(aScanCode, 0);
573 typedef void (*TLibFnDataFunc)(SFuncTables &aFuncTables);
575 void TFuncTable::Update(RLibrary aLibrary)
576 #pragma warning (disable: 4705)
578 #pragma warning (default: 4705)
579 ((TLibFnDataFunc)aLibrary.Lookup(EKeyDataFunc))(iFuncTables);
582 TFuncTable::TFuncTable()
583 #pragma warning (disable: 4705)
585 #pragma warning (default: 4705)
588 SFuncTableEntry TFuncTable::getDefault(const TCharExtended &aChar, const TInt &aModifiers) const
589 // Get the default table entry. Should be called if passing through a normal function-table did
590 // not trap these parameters.
593 while(i<iFuncTables.defaultTable.numEntries)
595 if (aChar.MatchesPattern(iFuncTables.defaultTable.pentries[i].keyCodePattern)
596 && MatchesMaskedValue(aModifiers,iFuncTables.defaultTable.pentries[i].maskedModifiers))
602 return iFuncTables.defaultTable.pentries[i];
605 SFunc TFuncTable::GetModifierFunc(const TCharExtended &aChar, const TInt &aModifiers) const
606 // Pass through the modifier table, returning the first table entry matching the given parameters.
608 SFuncTableEntry defaultTableEntry=getDefault(aChar, aModifiers);
609 SFunc returnVal = { 0, 0, 0 };
610 returnVal.func=defaultTableEntry.funcAndNewState.func;
611 returnVal.funcParam=defaultTableEntry.funcAndNewState.funcParam;
613 for (TUint i=0; i<iFuncTables.modifierTable.numEntries; i++)
614 if (aChar.MatchesPattern(iFuncTables.modifierTable.pentries[i].keyCodePattern)
615 && MatchesMaskedValue(aModifiers,iFuncTables.modifierTable.pentries[i].maskedModifiers))
617 returnVal.func=iFuncTables.modifierTable.pentries[i].funcAndNewState.func;
618 returnVal.funcParam=iFuncTables.modifierTable.pentries[i].funcAndNewState.funcParam;
624 SFuncAndState TFuncTable::GetGeneralFuncAndState(const TCharExtended &aChar, const TInt &aModifiers,
625 TUint aCurState, TRadix aRadix) const
626 // Pass through the table corresponding to the current keyboard state, returning the first
627 // table entry matching the given parameters.
629 for (TUint i=0; i<iFuncTables.pgenFuncTables[aCurState].numEntries; i++)
630 if (aChar.MatchesPattern(iFuncTables.pgenFuncTables[aCurState].pentries[i].keyCodePattern, aRadix)
631 && MatchesMaskedValue(aModifiers,iFuncTables.pgenFuncTables[aCurState].pentries[i].maskedModifiers))
633 return iFuncTables.pgenFuncTables[aCurState].pentries[i].funcAndNewState;
635 return getDefault(aChar, aModifiers).funcAndNewState;
639 TInt CKeyTranslatorX::ChangeKeyData(const TDesC& aLibName)
645 if(aLibName.Length()==0) // Back to default KeyData
647 if (!iIsdefaultKeyData)
649 _LIT(KEkData,"EKDATA.DLL");
650 TInt r=iDefaultKeyDataLib.Load(KEkData);
651 if (r!=KErrNone && r!=KErrAlreadyExists)
653 // Check for valid KeyboardData dll type
654 if(iDefaultKeyDataLib.Type()[2]!=KKeyboardDataUid)
656 iDefaultKeyDataLib.Close();
657 return(KErrCorrupt);//Only due to bad rom.
659 iConvTable.Update(iDefaultKeyDataLib);
660 iCurCtrlDigits.Update(iDefaultKeyDataLib);
661 iFuncTable.Update(iDefaultKeyDataLib);
662 iIsdefaultKeyData = ETrue; // EKeyData status
663 iKeyDataLib.Close(); // Close previously loaded keydata
669 TInt res=lib.Load(aLibName);
670 if (res!=KErrNone && res!=KErrAlreadyExists)
673 // Check for valid KeyboardData dll type
675 if(lib.Type()[2]!=KKeyboardDataUid)
678 return(KErrArgument);
681 // Close previously loaded keydata
682 if (iIsdefaultKeyData)
684 iIsdefaultKeyData = EFalse; // EKeyData status
685 iDefaultKeyDataLib.Close();
691 iConvTable.Update(lib);
692 iCurCtrlDigits.Update(lib);
693 iFuncTable.Update(lib);