javauis/lcdui_akn/javalcdui/src/CMIDKeyTranslator.cpp
branchRCL_3
changeset 19 04becd199f91
--- /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 <jdebug.h>
+
+// 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;
+}
+