diff -r f5050f1da672 -r 04becd199f91 javauis/lcdui_akn/javalcdui/src/CMIDKeyTranslator.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javauis/lcdui_akn/javalcdui/src/CMIDKeyTranslator.cpp Tue Apr 27 16:30:29 2010 +0300 @@ -0,0 +1,526 @@ +/* +* Copyright (c) 2002 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: +* +*/ + + +#include "CMIDKeyTranslator.h" +#include + +// Uncomment for loads of debug output +//#define DEBUG_KEY_TRANSLATOR + +#ifndef DEBUG_KEY_TRANSLATOR + +#ifdef DEBUG_STR +#undef DEBUG_STR +#define DEBUG_STR(msg, str) +#endif // def DEBUG_STR + +#ifdef DEBUG_INT +#undef DEBUG_INT +#define DEBUG_INT(msg,val) +#endif // def DEBUG_INT + +#ifdef DEBUG_INT2 +#undef DEBUG_INT2 +#define DEBUG_INT2(msg,val1,val2) +#endif // def DEBUG_INT2 + +#endif // def DEBUG_KEY_TRANSLATOR + +#if defined(__WINS__) // from w32cmd.h +// Under WINS character code is passed in as HIWORD of the scan code, +// and will need to be removed in some situations +#define SCANCODE(x) ((x) & 0xFFFF) +#else +#define SCANCODE(x) (x) +#endif + +const TInt KMIDKeyEdit = -50; +const TInt KMIDKeySelect = -5; + +inline TBool NonUnicodeKeyCode(TInt aKeyCode) +{ + return (aKeyCode > CMIDKeyTranslator::KMaxUnicodeKeyCode) || (aKeyCode <= 0); +} + +// +// Record of translated keys. +// + +CMIDKeyTranslator::CMIDKeyTranslator(MMIDEnv& aEnv) + : iEnv(aEnv) + , iKeyList(4) // granularity + , iS60SelectionKeyCompatibility(EFalse) +{ +} + +void CMIDKeyTranslator::ConstructL() +{ + + iS60SelectionKeyCompatibility = iEnv.MidletAttributeIsSetToVal( + LcduiMidletAttributes::KAttribS60SelectionKeyCompatibility, + LcduiMidletAttributeValues::KTrueValue + ); + +} + +CMIDKeyTranslator::~CMIDKeyTranslator() +{ + iKeyList.Reset(); +} + +void CMIDKeyTranslator::SetUtils(MMIDUtils* aUtils) +{ + iUtils = aUtils; +} + +void CMIDKeyTranslator::Reset() +{ + iKeyList.Reset(); +} + +/** +DEBUG +*/ +TText EventCode(TEventCode aType) +{ + switch (aType) + { + case EEventKeyDown: + return L'D'; + case EEventKey: + return L'C'; + case EEventKeyUp: + return L'U'; + default: + return L'?'; + } +} + +TBool CMIDKeyTranslator::TranslateL(TMIDKeyEvent& aMIDPKeyEvent, const TKeyEvent& aWsEvent, TEventCode aEventCode) +{ +#ifdef DEBUG_KEY_TRANSLATOR + TBuf<64> buf; + buf.Format(_L("[%C,%d,%d,%d]"), EventCode(aEventCode), SCANCODE(aWsEvent.iScanCode), aWsEvent.iCode, aWsEvent.iRepeats); + DEBUG_STR("TKeyEvent: %S", buf); +#endif + ASSERT(iUtils); + + // check if this key should be sent to java + if (!iUtils->IsJavaKey(SCANCODE(aWsEvent.iScanCode))) + { + DEBUG_INT("Non-Java scancode rejected: %d", SCANCODE(aWsEvent.iScanCode)); + return EFalse; + } + + aMIDPKeyEvent.iEvents =0; + aMIDPKeyEvent.iKeyCode=0; + aMIDPKeyEvent.iRepeats=0; + + // check if key is already pressed + TInt index = FindKeyRecord(SCANCODE(aWsEvent.iScanCode)); + if (index == KErrNotFound) + { + // new key press + TKeyRecord record; + record.iScanCode = SCANCODE(aWsEvent.iScanCode); + record.iIsSpecialKey = EFalse; + //store the value for some special key (non-unicode) + TInt mappedCode = Map(record.iScanCode, aWsEvent.iCode); + if (aWsEvent.iCode && + (aWsEvent.iScanCode == EStdKeyLeftShift || + aWsEvent.iScanCode == EStdKeyLeftFunc || + aWsEvent.iScanCode == EStdKeySpace)) + { + //If iCode has some non-zero value, the key was already mapped + //via PTIEngine. Key code value is simply copied to record. + //This step is because in Half-QWERTY keyboard layout, some keys + //can have additionl characters. + //E.g. Chr key on half-QWERTY keyboard has '*'. + record.iKeyCode = aWsEvent.iCode; + if (mappedCode == KMIDKeyEdit) + { + //Some special keys (in different keyborad layouts) have + //additional key value. So we need to store information that + //special key was pressed. + record.iIsSpecialKey = ETrue; + } + } + else + { + //If iCode is 0, this means, that special key was pressed + //(e.g Fn or Shift) and it doesn't have any additional character + //(so PTIEngine didn't do any mapping) + record.iKeyCode = mappedCode; + } + record.iState = TKeyRecord::EStateInitial; + User::LeaveIfError(iKeyList.Append(record)); + index = iKeyList.Count()-1; + } + TKeyRecord& record = iKeyList[index]; + + if (record.iKeyCode == 0 && aEventCode == EEventKey) + { + record.iKeyCode = Map(record.iScanCode, aWsEvent.iCode); + } + + // transition to next state... + record.Transition(aEventCode, aMIDPKeyEvent, aWsEvent.iRepeats, iS60SelectionKeyCompatibility); + + if (record.iState == TKeyRecord::EStateInitial) + { + iKeyList.Remove(index); + } + + return aMIDPKeyEvent.iEvents; // non-zero == true post something + +} + +TInt CMIDKeyTranslator::FindKeyRecord(TInt aScanCode) const +{ + for (TInt ii=iKeyList.Count(); ii--;) + { + if (iKeyList[ii].iScanCode==aScanCode) + return ii; + } + return KErrNotFound; +} + + +TInt CMIDKeyTranslator::Map(TInt aScanCode, TInt aCode) +{ + // + // Fitler out some non-unicode keys - only rejects obviously + // out of bounds unicode values. Any keys that should be + // mapped to Java will be mapped in MapNonUnicodeKeyCode + // below. + // + if (NonUnicodeKeyCode(aCode)) + { + aCode = KInvalidKeyCode; + } + + // + // At this point keyCode can be any valid EPOC key code, some of which + // will not be UNICODE values. To comply with the MIDP spec, all non + // UNICODE keys must be mapped to negative values. + // + // Any keys for which we do not have a valid MIDP keyCode, will be + // mapped to KInvalidKeyCode. + // + // We do the mapping here regardless of the return value of + // NonUnicodeKeyCode() as that function may not remove all non-unicode + // keycodes. + // + // The mapping is done from the scancode. + // + TInt specialKey = MapNonUnicodeKeyCode(aScanCode); + if (KInvalidKeyCode != specialKey) + { + DEBUG_INT2("mapping non-unicode keycode: %d to %d", aCode, specialKey); + aCode = specialKey; + } + + DEBUG_INT("keycode = %d\n", aCode); + + return aCode; +} + +TInt CMIDKeyTranslator::MapNonUnicodeKeyCode(TInt aScanCode) +{ + ASSERT(iUtils); + return iUtils->MapNonUnicodeKey(aScanCode); +} + +TBool CMIDKeyTranslator::PostKeyEvent(MMIDComponent& aComponent, const TMIDKeyEvent& aEvent) +{ + ASSERT(aEvent.iKeyCode); + TBool posted(EFalse); + + if (aEvent.iEvents & TMIDKeyEvent::EPressed) + { + PostKeyEvent(aComponent, EKeyPressed, aEvent.iKeyCode, 0); + posted=ETrue; + } + + if (aEvent.iEvents & TMIDKeyEvent::ERepeated) + { + PostKeyEvent(aComponent, EKeyRepeated, aEvent.iKeyCode, aEvent.iRepeats); + posted=ETrue; + } + + if (aEvent.iEvents & TMIDKeyEvent::EReleased) + { + PostKeyEvent(aComponent, EKeyReleased, aEvent.iKeyCode, 0); + posted=ETrue; + } + + return posted; +} + +void CMIDKeyTranslator::PostKeyEvent(MMIDComponent& aComponent, TEventType aType, TInt aKeyCode, TInt aRepeats) +{ + ASSERT(aKeyCode != KInvalidKeyCode); + DEBUG_INT2("PostKeyEvent[%d] (%d)", aType, aKeyCode); + (void) iEnv.PostJavaEvent( + aComponent, + aComponent.Type() == MMIDComponent::ECustomItem ? EItem : EDisplayable, + aType, + aKeyCode, + aRepeats, + 0 + ); +} + +void TKeyRecord::Transition(TEventCode aEventCode, TMIDKeyEvent& aMIDPKeyEvent, TInt aRepeats, TBool aS60SelectionKeyCompatibility) +{ + // transition to next state... + switch (iState) + { + case EStateInitial: + StateInitial(aEventCode, aMIDPKeyEvent, aRepeats, aS60SelectionKeyCompatibility); + break; + + case EStateDown: + StateDown(aEventCode, aMIDPKeyEvent,aRepeats); + break; + + case EStateDownTranslated: + StateDownTranslated(aEventCode, aMIDPKeyEvent,aRepeats); + break; + + case EStateKeyTranslated: + StateKeyTranslated(aEventCode, aMIDPKeyEvent,aRepeats); + break; + + case EStateKeyRepeated: + StateKeyRepeated(aEventCode, aMIDPKeyEvent,aRepeats); + break; + + case EStateDownRepeated: + StateDownRepeated(aEventCode, aMIDPKeyEvent,aRepeats); + break; + } +} + +void TKeyRecord::StateInitial(TEventCode aEventCode, TMIDKeyEvent& aMIDPKeyEvent, TInt aRepeats, TBool aS60SelectionKeyCompatibility) +{ + switch (aEventCode) + { + case EEventKeyDown: + // When canvas is not in full-screen mode then EEventKey event for Edit and + // Select key-presses is catched in CEikCba::OfferKeyEventL. This function + // returns EKeyWasConsumed and CCoeControlStack doesn't send EEvent to CMIDCanvas. + // Therefore EEvent key never reach to CMIDCanvas::OfferKeyEventL. + // This is why we use here EEventKeyDown for sending the key-press + // events for Edit and Select to MIDlet. + // + // Special keys, like Edit key, can have also additional characters. + // If special key carries the additional character (mapped by PTIEngine) + // and it should be sent to Java, iIsSpecialKey is true and record + // switches to EStateDownTranslated. This will guarantee, that event + // will be sent to MIDlet. + if (iKeyCode == KMIDKeyEdit || + (iKeyCode == KMIDKeySelect && aS60SelectionKeyCompatibility) || + (iIsSpecialKey) + ) + { + // have a -ve code, can post KeyPressed now + KeyPressed(aMIDPKeyEvent); + iState = EStateDownTranslated; + } + else + { + // must delay KeyPressed until have keyCode + iState = EStateDown; + } + break; + + case EEventKey: + // FEP + KeyPressed(aMIDPKeyEvent); + if (aRepeats > 0) + { + KeyRepeated(aMIDPKeyEvent,aRepeats); + } + KeyReleased(aMIDPKeyEvent); + iState = EStateInitial; + break; + + case EEventKeyUp: + iState = EStateInitial; + break; + + default: + ASSERT(EFalse); + } +} + +void TKeyRecord::StateDown(TEventCode aEventCode, TMIDKeyEvent& aMIDPKeyEvent, TInt aRepeats) +{ + // key code was previously NOT translated. + + switch (aEventCode) + { + case EEventKeyDown: + // no-op + DEBUG_INT("THIS SCANCODE REQUIRES MAPPING TO NEGATIVE KEYCODE: %d", iScanCode); + break; + + case EEventKey: + // now we have key code, can send key pressed + KeyPressed(aMIDPKeyEvent); + if (aRepeats > 0) + { + KeyRepeated(aMIDPKeyEvent,aRepeats); + } + iState = EStateDownTranslated; + break; + + case EEventKeyUp: + iState = EStateInitial; + DEBUG_INT("THIS SCANCODE REQUIRES MAPPING TO NEGATIVE KEYCODE: %d", iScanCode); + break; + + default: + ASSERT(EFalse); + } +} + +void TKeyRecord::StateDownTranslated(TEventCode aEventCode, TMIDKeyEvent& aMIDPKeyEvent, TInt aRepeats) +{ + + switch (aEventCode) + { + case EEventKeyDown: + KeyRepeated(aMIDPKeyEvent,1); + iState = EStateDownRepeated; + break; + + case EEventKey: + if (aRepeats > 0) + { + KeyRepeated(aMIDPKeyEvent,aRepeats); + iState= EStateKeyRepeated; + } + else + { + iState = EStateKeyTranslated; + } + break; + + case EEventKeyUp: + KeyReleased(aMIDPKeyEvent); + iState = EStateInitial; + break; + + default: + ASSERT(EFalse); + } +} + +void TKeyRecord::StateKeyTranslated(TEventCode aEventCode, TMIDKeyEvent& aMIDPKeyEvent, TInt aRepeats) +{ + switch (aEventCode) + { + case EEventKeyDown: + // no-op + break; + case EEventKey: + KeyRepeated(aMIDPKeyEvent, aRepeats ? aRepeats : 1); + iState=EStateKeyRepeated; + break; + case EEventKeyUp: + KeyReleased(aMIDPKeyEvent); + iState = EStateInitial; + break; + default: + ASSERT(EFalse); + } +} + +void TKeyRecord::StateKeyRepeated(TEventCode aEventCode, TMIDKeyEvent& aMIDPKeyEvent, TInt aRepeats) +{ + switch (aEventCode) + { + case EEventKeyDown: + // no-op + break; + case EEventKey: + KeyRepeated(aMIDPKeyEvent, aRepeats ? aRepeats : 1); + iState=EStateKeyRepeated; + break; + case EEventKeyUp: + KeyReleased(aMIDPKeyEvent); + iState = EStateInitial; + break; + default: + ASSERT(EFalse); + } +} + +void TKeyRecord::StateDownRepeated(TEventCode aEventCode, TMIDKeyEvent& aMIDPKeyEvent, TInt /*aRepeats*/) +{ + switch (aEventCode) + { + case EEventKeyDown: + KeyRepeated(aMIDPKeyEvent,1); + break; + case EEventKey: + iState = EStateDownTranslated; + break; + case EEventKeyUp: + KeyReleased(aMIDPKeyEvent); + iState = EStateInitial; + break; + default: + ASSERT(EFalse); + } +} + + +void TKeyRecord::SetKeyCode(TMIDKeyEvent& aMIDPKeyEvent) +{ + ASSERT(iKeyCode); + if (0 == aMIDPKeyEvent.iKeyCode) + { + aMIDPKeyEvent.iKeyCode = iKeyCode; + } + ASSERT(aMIDPKeyEvent.iKeyCode == iKeyCode); +} + +void TKeyRecord::KeyPressed(TMIDKeyEvent& aMIDPKeyEvent) +{ + SetKeyCode(aMIDPKeyEvent); + aMIDPKeyEvent.iEvents |= TMIDKeyEvent::EPressed; + aMIDPKeyEvent.iRepeats = 0; +} + +void TKeyRecord::KeyRepeated(TMIDKeyEvent& aMIDPKeyEvent, TInt aRepeats) +{ + SetKeyCode(aMIDPKeyEvent); + aMIDPKeyEvent.iEvents |= TMIDKeyEvent::ERepeated; + aMIDPKeyEvent.iRepeats = aRepeats; +} + +void TKeyRecord::KeyReleased(TMIDKeyEvent& aMIDPKeyEvent) +{ + SetKeyCode(aMIDPKeyEvent); + aMIDPKeyEvent.iEvents |= TMIDKeyEvent::EReleased; + aMIDPKeyEvent.iRepeats = 0; +} +