javauis/lcdui_akn/javalcdui/src/CMIDKeyTranslator.cpp
branchRCL_3
changeset 14 04becd199f91
equal deleted inserted replaced
13:f5050f1da672 14:04becd199f91
       
     1 /*
       
     2 * Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include "CMIDKeyTranslator.h"
       
    20 #include <jdebug.h>
       
    21 
       
    22 // Uncomment for loads of debug output
       
    23 //#define DEBUG_KEY_TRANSLATOR
       
    24 
       
    25 #ifndef DEBUG_KEY_TRANSLATOR
       
    26 
       
    27 #ifdef DEBUG_STR
       
    28 #undef DEBUG_STR
       
    29 #define DEBUG_STR(msg, str)
       
    30 #endif // def DEBUG_STR
       
    31 
       
    32 #ifdef DEBUG_INT
       
    33 #undef DEBUG_INT
       
    34 #define DEBUG_INT(msg,val)
       
    35 #endif // def DEBUG_INT
       
    36 
       
    37 #ifdef DEBUG_INT2
       
    38 #undef DEBUG_INT2
       
    39 #define DEBUG_INT2(msg,val1,val2)
       
    40 #endif // def DEBUG_INT2
       
    41 
       
    42 #endif // def DEBUG_KEY_TRANSLATOR
       
    43 
       
    44 #if defined(__WINS__) // from w32cmd.h
       
    45 // Under WINS character code is passed in as HIWORD of the scan code,
       
    46 // and will need to be removed in some situations
       
    47 #define SCANCODE(x) ((x) & 0xFFFF)
       
    48 #else
       
    49 #define SCANCODE(x) (x)
       
    50 #endif
       
    51 
       
    52 const TInt KMIDKeyEdit = -50;
       
    53 const TInt KMIDKeySelect = -5;
       
    54 
       
    55 inline TBool NonUnicodeKeyCode(TInt aKeyCode)
       
    56 {
       
    57     return (aKeyCode > CMIDKeyTranslator::KMaxUnicodeKeyCode) || (aKeyCode <= 0);
       
    58 }
       
    59 
       
    60 //
       
    61 // Record of translated keys.
       
    62 //
       
    63 
       
    64 CMIDKeyTranslator::CMIDKeyTranslator(MMIDEnv& aEnv)
       
    65         : iEnv(aEnv)
       
    66         , iKeyList(4) // granularity
       
    67         , iS60SelectionKeyCompatibility(EFalse)
       
    68 {
       
    69 }
       
    70 
       
    71 void CMIDKeyTranslator::ConstructL()
       
    72 {
       
    73 
       
    74     iS60SelectionKeyCompatibility = iEnv.MidletAttributeIsSetToVal(
       
    75                                         LcduiMidletAttributes::KAttribS60SelectionKeyCompatibility,
       
    76                                         LcduiMidletAttributeValues::KTrueValue
       
    77                                     );
       
    78 
       
    79 }
       
    80 
       
    81 CMIDKeyTranslator::~CMIDKeyTranslator()
       
    82 {
       
    83     iKeyList.Reset();
       
    84 }
       
    85 
       
    86 void CMIDKeyTranslator::SetUtils(MMIDUtils* aUtils)
       
    87 {
       
    88     iUtils = aUtils;
       
    89 }
       
    90 
       
    91 void CMIDKeyTranslator::Reset()
       
    92 {
       
    93     iKeyList.Reset();
       
    94 }
       
    95 
       
    96 /**
       
    97 DEBUG
       
    98 */
       
    99 TText EventCode(TEventCode aType)
       
   100 {
       
   101     switch (aType)
       
   102     {
       
   103     case EEventKeyDown:
       
   104         return L'D';
       
   105     case EEventKey:
       
   106         return L'C';
       
   107     case EEventKeyUp:
       
   108         return L'U';
       
   109     default:
       
   110         return L'?';
       
   111     }
       
   112 }
       
   113 
       
   114 TBool CMIDKeyTranslator::TranslateL(TMIDKeyEvent& aMIDPKeyEvent, const TKeyEvent& aWsEvent, TEventCode aEventCode)
       
   115 {
       
   116 #ifdef DEBUG_KEY_TRANSLATOR
       
   117     TBuf<64> buf;
       
   118     buf.Format(_L("[%C,%d,%d,%d]"), EventCode(aEventCode), SCANCODE(aWsEvent.iScanCode), aWsEvent.iCode, aWsEvent.iRepeats);
       
   119     DEBUG_STR("TKeyEvent: %S", buf);
       
   120 #endif
       
   121     ASSERT(iUtils);
       
   122 
       
   123     // check if this key should be sent to java
       
   124     if (!iUtils->IsJavaKey(SCANCODE(aWsEvent.iScanCode)))
       
   125     {
       
   126         DEBUG_INT("Non-Java scancode rejected: %d", SCANCODE(aWsEvent.iScanCode));
       
   127         return EFalse;
       
   128     }
       
   129 
       
   130     aMIDPKeyEvent.iEvents =0;
       
   131     aMIDPKeyEvent.iKeyCode=0;
       
   132     aMIDPKeyEvent.iRepeats=0;
       
   133 
       
   134     // check if key is already pressed
       
   135     TInt index = FindKeyRecord(SCANCODE(aWsEvent.iScanCode));
       
   136     if (index == KErrNotFound)
       
   137     {
       
   138         // new key press
       
   139         TKeyRecord record;
       
   140         record.iScanCode = SCANCODE(aWsEvent.iScanCode);
       
   141         record.iIsSpecialKey = EFalse;
       
   142         //store the value for some special key (non-unicode)
       
   143         TInt mappedCode = Map(record.iScanCode, aWsEvent.iCode);
       
   144         if (aWsEvent.iCode &&
       
   145                 (aWsEvent.iScanCode == EStdKeyLeftShift ||
       
   146                  aWsEvent.iScanCode == EStdKeyLeftFunc ||
       
   147                  aWsEvent.iScanCode == EStdKeySpace))
       
   148         {
       
   149             //If iCode has some non-zero value, the key was already mapped
       
   150             //via PTIEngine. Key code value is simply copied to record.
       
   151             //This step is because in Half-QWERTY keyboard layout, some keys
       
   152             //can have additionl characters.
       
   153             //E.g. Chr key on half-QWERTY keyboard has '*'.
       
   154             record.iKeyCode = aWsEvent.iCode;
       
   155             if (mappedCode == KMIDKeyEdit)
       
   156             {
       
   157                 //Some special keys (in different keyborad layouts) have
       
   158                 //additional key value. So we need to store information that
       
   159                 //special key was pressed.
       
   160                 record.iIsSpecialKey = ETrue;
       
   161             }
       
   162         }
       
   163         else
       
   164         {
       
   165             //If iCode is 0, this means, that special key was pressed
       
   166             //(e.g Fn or Shift) and it doesn't have any additional character
       
   167             //(so PTIEngine didn't do any mapping)
       
   168             record.iKeyCode = mappedCode;
       
   169         }
       
   170         record.iState = TKeyRecord::EStateInitial;
       
   171         User::LeaveIfError(iKeyList.Append(record));
       
   172         index = iKeyList.Count()-1;
       
   173     }
       
   174     TKeyRecord& record = iKeyList[index];
       
   175 
       
   176     if (record.iKeyCode == 0 && aEventCode == EEventKey)
       
   177     {
       
   178         record.iKeyCode = Map(record.iScanCode, aWsEvent.iCode);
       
   179     }
       
   180 
       
   181     // transition to next state...
       
   182     record.Transition(aEventCode, aMIDPKeyEvent, aWsEvent.iRepeats, iS60SelectionKeyCompatibility);
       
   183 
       
   184     if (record.iState == TKeyRecord::EStateInitial)
       
   185     {
       
   186         iKeyList.Remove(index);
       
   187     }
       
   188 
       
   189     return aMIDPKeyEvent.iEvents;   // non-zero == true post something
       
   190 
       
   191 }
       
   192 
       
   193 TInt CMIDKeyTranslator::FindKeyRecord(TInt aScanCode) const
       
   194 {
       
   195     for (TInt ii=iKeyList.Count(); ii--;)
       
   196     {
       
   197         if (iKeyList[ii].iScanCode==aScanCode)
       
   198             return ii;
       
   199     }
       
   200     return KErrNotFound;
       
   201 }
       
   202 
       
   203 
       
   204 TInt CMIDKeyTranslator::Map(TInt aScanCode, TInt aCode)
       
   205 {
       
   206     //
       
   207     // Fitler out some non-unicode keys - only rejects obviously
       
   208     // out of bounds unicode values. Any keys that should be
       
   209     // mapped to Java will be mapped in MapNonUnicodeKeyCode
       
   210     // below.
       
   211     //
       
   212     if (NonUnicodeKeyCode(aCode))
       
   213     {
       
   214         aCode = KInvalidKeyCode;
       
   215     }
       
   216 
       
   217     //
       
   218     // At this point keyCode can be any valid EPOC key code, some of which
       
   219     // will not be UNICODE values. To comply with the MIDP spec, all non
       
   220     // UNICODE keys must be mapped to negative values.
       
   221     //
       
   222     // Any keys for which we do not have a valid MIDP keyCode, will be
       
   223     // mapped to KInvalidKeyCode.
       
   224     //
       
   225     // We do the mapping here regardless of the return value of
       
   226     // NonUnicodeKeyCode() as that function may not remove all non-unicode
       
   227     // keycodes.
       
   228     //
       
   229     // The mapping is done from the scancode.
       
   230     //
       
   231     TInt specialKey = MapNonUnicodeKeyCode(aScanCode);
       
   232     if (KInvalidKeyCode != specialKey)
       
   233     {
       
   234         DEBUG_INT2("mapping non-unicode keycode: %d to %d", aCode, specialKey);
       
   235         aCode = specialKey;
       
   236     }
       
   237 
       
   238     DEBUG_INT("keycode = %d\n", aCode);
       
   239 
       
   240     return aCode;
       
   241 }
       
   242 
       
   243 TInt CMIDKeyTranslator::MapNonUnicodeKeyCode(TInt aScanCode)
       
   244 {
       
   245     ASSERT(iUtils);
       
   246     return iUtils->MapNonUnicodeKey(aScanCode);
       
   247 }
       
   248 
       
   249 TBool CMIDKeyTranslator::PostKeyEvent(MMIDComponent& aComponent, const TMIDKeyEvent& aEvent)
       
   250 {
       
   251     ASSERT(aEvent.iKeyCode);
       
   252     TBool posted(EFalse);
       
   253 
       
   254     if (aEvent.iEvents & TMIDKeyEvent::EPressed)
       
   255     {
       
   256         PostKeyEvent(aComponent, EKeyPressed, aEvent.iKeyCode, 0);
       
   257         posted=ETrue;
       
   258     }
       
   259 
       
   260     if (aEvent.iEvents & TMIDKeyEvent::ERepeated)
       
   261     {
       
   262         PostKeyEvent(aComponent, EKeyRepeated, aEvent.iKeyCode, aEvent.iRepeats);
       
   263         posted=ETrue;
       
   264     }
       
   265 
       
   266     if (aEvent.iEvents & TMIDKeyEvent::EReleased)
       
   267     {
       
   268         PostKeyEvent(aComponent, EKeyReleased, aEvent.iKeyCode, 0);
       
   269         posted=ETrue;
       
   270     }
       
   271 
       
   272     return posted;
       
   273 }
       
   274 
       
   275 void CMIDKeyTranslator::PostKeyEvent(MMIDComponent& aComponent, TEventType aType, TInt aKeyCode, TInt aRepeats)
       
   276 {
       
   277     ASSERT(aKeyCode != KInvalidKeyCode);
       
   278     DEBUG_INT2("PostKeyEvent[%d] (%d)", aType, aKeyCode);
       
   279     (void) iEnv.PostJavaEvent(
       
   280         aComponent,
       
   281         aComponent.Type() == MMIDComponent::ECustomItem ? EItem : EDisplayable,
       
   282         aType,
       
   283         aKeyCode,
       
   284         aRepeats,
       
   285         0
       
   286     );
       
   287 }
       
   288 
       
   289 void TKeyRecord::Transition(TEventCode aEventCode, TMIDKeyEvent& aMIDPKeyEvent, TInt aRepeats, TBool aS60SelectionKeyCompatibility)
       
   290 {
       
   291     // transition to next state...
       
   292     switch (iState)
       
   293     {
       
   294     case EStateInitial:
       
   295         StateInitial(aEventCode, aMIDPKeyEvent, aRepeats, aS60SelectionKeyCompatibility);
       
   296         break;
       
   297 
       
   298     case EStateDown:
       
   299         StateDown(aEventCode, aMIDPKeyEvent,aRepeats);
       
   300         break;
       
   301 
       
   302     case EStateDownTranslated:
       
   303         StateDownTranslated(aEventCode, aMIDPKeyEvent,aRepeats);
       
   304         break;
       
   305 
       
   306     case EStateKeyTranslated:
       
   307         StateKeyTranslated(aEventCode, aMIDPKeyEvent,aRepeats);
       
   308         break;
       
   309 
       
   310     case EStateKeyRepeated:
       
   311         StateKeyRepeated(aEventCode, aMIDPKeyEvent,aRepeats);
       
   312         break;
       
   313 
       
   314     case EStateDownRepeated:
       
   315         StateDownRepeated(aEventCode, aMIDPKeyEvent,aRepeats);
       
   316         break;
       
   317     }
       
   318 }
       
   319 
       
   320 void TKeyRecord::StateInitial(TEventCode aEventCode, TMIDKeyEvent& aMIDPKeyEvent, TInt aRepeats, TBool aS60SelectionKeyCompatibility)
       
   321 {
       
   322     switch (aEventCode)
       
   323     {
       
   324     case EEventKeyDown:
       
   325         // When canvas is not in full-screen mode then EEventKey event for Edit and
       
   326         // Select key-presses is catched in CEikCba::OfferKeyEventL. This function
       
   327         // returns EKeyWasConsumed and CCoeControlStack doesn't send EEvent to CMIDCanvas.
       
   328         // Therefore EEvent key never reach to CMIDCanvas::OfferKeyEventL.
       
   329         // This is why we use here EEventKeyDown for sending the key-press
       
   330         // events for Edit and Select to MIDlet.
       
   331         //
       
   332         // Special keys, like Edit key, can have also additional characters.
       
   333         // If special key carries the additional character (mapped by PTIEngine)
       
   334         // and it should be sent to Java, iIsSpecialKey is true and record
       
   335         // switches to EStateDownTranslated. This will guarantee, that event
       
   336         // will be sent to MIDlet.
       
   337         if (iKeyCode == KMIDKeyEdit ||
       
   338                 (iKeyCode == KMIDKeySelect && aS60SelectionKeyCompatibility) ||
       
   339                 (iIsSpecialKey)
       
   340            )
       
   341         {
       
   342             // have a -ve code, can post KeyPressed now
       
   343             KeyPressed(aMIDPKeyEvent);
       
   344             iState = EStateDownTranslated;
       
   345         }
       
   346         else
       
   347         {
       
   348             // must delay KeyPressed until have keyCode
       
   349             iState = EStateDown;
       
   350         }
       
   351         break;
       
   352 
       
   353     case EEventKey:
       
   354         // FEP
       
   355         KeyPressed(aMIDPKeyEvent);
       
   356         if (aRepeats > 0)
       
   357         {
       
   358             KeyRepeated(aMIDPKeyEvent,aRepeats);
       
   359         }
       
   360         KeyReleased(aMIDPKeyEvent);
       
   361         iState = EStateInitial;
       
   362         break;
       
   363 
       
   364     case EEventKeyUp:
       
   365         iState = EStateInitial;
       
   366         break;
       
   367 
       
   368     default:
       
   369         ASSERT(EFalse);
       
   370     }
       
   371 }
       
   372 
       
   373 void TKeyRecord::StateDown(TEventCode aEventCode, TMIDKeyEvent& aMIDPKeyEvent, TInt aRepeats)
       
   374 {
       
   375     // key code was previously NOT translated.
       
   376 
       
   377     switch (aEventCode)
       
   378     {
       
   379     case EEventKeyDown:
       
   380         // no-op
       
   381         DEBUG_INT("THIS SCANCODE REQUIRES MAPPING TO NEGATIVE KEYCODE: %d", iScanCode);
       
   382         break;
       
   383 
       
   384     case EEventKey:
       
   385         // now we have key code, can send key pressed
       
   386         KeyPressed(aMIDPKeyEvent);
       
   387         if (aRepeats > 0)
       
   388         {
       
   389             KeyRepeated(aMIDPKeyEvent,aRepeats);
       
   390         }
       
   391         iState = EStateDownTranslated;
       
   392         break;
       
   393 
       
   394     case EEventKeyUp:
       
   395         iState = EStateInitial;
       
   396         DEBUG_INT("THIS SCANCODE REQUIRES MAPPING TO NEGATIVE KEYCODE: %d", iScanCode);
       
   397         break;
       
   398 
       
   399     default:
       
   400         ASSERT(EFalse);
       
   401     }
       
   402 }
       
   403 
       
   404 void TKeyRecord::StateDownTranslated(TEventCode aEventCode, TMIDKeyEvent& aMIDPKeyEvent, TInt aRepeats)
       
   405 {
       
   406 
       
   407     switch (aEventCode)
       
   408     {
       
   409     case EEventKeyDown:
       
   410         KeyRepeated(aMIDPKeyEvent,1);
       
   411         iState = EStateDownRepeated;
       
   412         break;
       
   413 
       
   414     case EEventKey:
       
   415         if (aRepeats > 0)
       
   416         {
       
   417             KeyRepeated(aMIDPKeyEvent,aRepeats);
       
   418             iState= EStateKeyRepeated;
       
   419         }
       
   420         else
       
   421         {
       
   422             iState = EStateKeyTranslated;
       
   423         }
       
   424         break;
       
   425 
       
   426     case EEventKeyUp:
       
   427         KeyReleased(aMIDPKeyEvent);
       
   428         iState = EStateInitial;
       
   429         break;
       
   430 
       
   431     default:
       
   432         ASSERT(EFalse);
       
   433     }
       
   434 }
       
   435 
       
   436 void TKeyRecord::StateKeyTranslated(TEventCode aEventCode, TMIDKeyEvent& aMIDPKeyEvent, TInt aRepeats)
       
   437 {
       
   438     switch (aEventCode)
       
   439     {
       
   440     case EEventKeyDown:
       
   441         // no-op
       
   442         break;
       
   443     case EEventKey:
       
   444         KeyRepeated(aMIDPKeyEvent, aRepeats ? aRepeats : 1);
       
   445         iState=EStateKeyRepeated;
       
   446         break;
       
   447     case EEventKeyUp:
       
   448         KeyReleased(aMIDPKeyEvent);
       
   449         iState = EStateInitial;
       
   450         break;
       
   451     default:
       
   452         ASSERT(EFalse);
       
   453     }
       
   454 }
       
   455 
       
   456 void TKeyRecord::StateKeyRepeated(TEventCode aEventCode, TMIDKeyEvent& aMIDPKeyEvent, TInt aRepeats)
       
   457 {
       
   458     switch (aEventCode)
       
   459     {
       
   460     case EEventKeyDown:
       
   461         // no-op
       
   462         break;
       
   463     case EEventKey:
       
   464         KeyRepeated(aMIDPKeyEvent, aRepeats ? aRepeats : 1);
       
   465         iState=EStateKeyRepeated;
       
   466         break;
       
   467     case EEventKeyUp:
       
   468         KeyReleased(aMIDPKeyEvent);
       
   469         iState = EStateInitial;
       
   470         break;
       
   471     default:
       
   472         ASSERT(EFalse);
       
   473     }
       
   474 }
       
   475 
       
   476 void TKeyRecord::StateDownRepeated(TEventCode aEventCode, TMIDKeyEvent& aMIDPKeyEvent, TInt /*aRepeats*/)
       
   477 {
       
   478     switch (aEventCode)
       
   479     {
       
   480     case EEventKeyDown:
       
   481         KeyRepeated(aMIDPKeyEvent,1);
       
   482         break;
       
   483     case EEventKey:
       
   484         iState = EStateDownTranslated;
       
   485         break;
       
   486     case EEventKeyUp:
       
   487         KeyReleased(aMIDPKeyEvent);
       
   488         iState = EStateInitial;
       
   489         break;
       
   490     default:
       
   491         ASSERT(EFalse);
       
   492     }
       
   493 }
       
   494 
       
   495 
       
   496 void TKeyRecord::SetKeyCode(TMIDKeyEvent& aMIDPKeyEvent)
       
   497 {
       
   498     ASSERT(iKeyCode);
       
   499     if (0 == aMIDPKeyEvent.iKeyCode)
       
   500     {
       
   501         aMIDPKeyEvent.iKeyCode = iKeyCode;
       
   502     }
       
   503     ASSERT(aMIDPKeyEvent.iKeyCode == iKeyCode);
       
   504 }
       
   505 
       
   506 void TKeyRecord::KeyPressed(TMIDKeyEvent& aMIDPKeyEvent)
       
   507 {
       
   508     SetKeyCode(aMIDPKeyEvent);
       
   509     aMIDPKeyEvent.iEvents |= TMIDKeyEvent::EPressed;
       
   510     aMIDPKeyEvent.iRepeats = 0;
       
   511 }
       
   512 
       
   513 void TKeyRecord::KeyRepeated(TMIDKeyEvent& aMIDPKeyEvent, TInt aRepeats)
       
   514 {
       
   515     SetKeyCode(aMIDPKeyEvent);
       
   516     aMIDPKeyEvent.iEvents |=  TMIDKeyEvent::ERepeated;
       
   517     aMIDPKeyEvent.iRepeats = aRepeats;
       
   518 }
       
   519 
       
   520 void TKeyRecord::KeyReleased(TMIDKeyEvent& aMIDPKeyEvent)
       
   521 {
       
   522     SetKeyCode(aMIDPKeyEvent);
       
   523     aMIDPKeyEvent.iEvents |=  TMIDKeyEvent::EReleased;
       
   524     aMIDPKeyEvent.iRepeats = 0;
       
   525 }
       
   526