diff -r f5050f1da672 -r 04becd199f91 javauis/lcdui_akn/lcdui/src/CMIDKeyDecoder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javauis/lcdui_akn/lcdui/src/CMIDKeyDecoder.cpp Tue Apr 27 16:30:29 2010 +0300 @@ -0,0 +1,715 @@ +/* +* Copyright (c) 2003 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: ?Description +* +*/ + +// CEikonEnv API used for retrieving resource (resId) in GetKeyName function +#include +// macros for resources +#include +// FeatureManager +#include +#include + +#include +/** +@page Key Mapping. +*/ + +// used for retrieving CR repository codes +#include +// S60 LCDUI Plugin internal keys +#include "S60LCDUIInternalCRKeys.h" + +#include "CMIDKeyDecoder.h" +// used for getting instance of ourselves from TlsStruct +#include "CMIDMenuHandler.h" +// using API for iRemConObserver initialization +#include "CMIDRemConObserver.h" +// using constants from enumeration TMediaKey (in InitSpecialKeysL) +#include "MMIDMediaKeysListener.h" +#include "CMIDDisplayable.h" +#include "CMIDUIManager.h" + +/** + * MIDP key codes for keys that have no corresponding + * Unicode character, as from MIDP specs negative values + * must be used. + * + * ALL characters with code >= ENonCharacterKeyBase + * should be mapped to -ve numbers (see e32keys.h) + */ +const TInt KMIDKeyUpArrow = -1; +const TInt KMIDKeyDownArrow = -2; +const TInt KMIDKeyLeftArrow = -3; +const TInt KMIDKeyRightArrow = -4; +const TInt KMIDKeyClear = -8; // Clear key +const TInt KMIDKeySelect = -5; // Selection key +const TInt KMIDKeyEdit = -50; // Edit Key +const TInt KMIDKeySend = -10; // Send Key +const TInt KMIDKeyCBA1 = -6; // Left CBA +const TInt KMIDKeyCBA2 = -7; // Right CBA +const TInt KMIDKeyEnd = -11; // End key +const TInt KMIDKeyApplications = -12; // Applications key +const TInt KMIDKeyVoiceKey = -13; // Voice key +//const TInt KMIDKeyClockWiseRotate = -16; // not used at the moment +//const TInt KMIDKeyCounterClockWiseRotate = -17; // not used at the moment +//const TInt KMIDKeyClockWiseFastRotate = -18; // not used at the moment +//const TInt KMIDKeyCounterClockWiseFastRotate = -19; // not used at the moment +const TInt KMIDKeyZoomIn = -EKeyZoomIn; // Negative value (-63582) +const TInt KMIDKeyZoomOut = -EKeyZoomOut; // Negative value (-63583) + +/** The number of game actions */ +const TInt KNumGameActions = 9; + +/** The max number of scan codes per game action */ +const TInt KMaxScanCodesPerAction = 16; + +/** The MIDP game action codes, this array must have the same index as + KDefaultActionScanCodes and KActionKeys.*/ +const TInt KActionCodes[KNumGameActions] = +{ + MMIDUtils::EActionUp, + MMIDUtils::EActionDown, + MMIDUtils::EActionLeft, + MMIDUtils::EActionRight, + MMIDUtils::EActionFire, + + MMIDUtils::EActionGameA, + MMIDUtils::EActionGameB, + MMIDUtils::EActionGameC, + MMIDUtils::EActionGameD +}; + + +/** The MIDP game action keys in the central repository. +These are used to override the default scan codes. +This array must have the same index as KActionCodes. +*/ +const TUint32 KActionKeys[KNumGameActions] = +{ + KScanCodeUp, + KScanCodeDown, + KScanCodeLeft, + KScanCodeRight, + KScanCodeFire, + KScanCodeGameA, + KScanCodeGameB, + KScanCodeGameC, + KScanCodeGameD +}; + + +/** Default scan codes for game actions. These are only used when + the scan codes in the central repository have not been set. + + Because for each action there can be one or more code, use a zero + to indicate that there are no more codes. + + This array must have the same index as KActionCodes. + + @see CR keys, ConstructL() + */ + +// ITU-T keypad with standard grid layout. +const TInt KDefaultActionScanCodes[] = +{ + EStdKeyUpArrow, '2', 0, // EActionUp + EStdKeyDownArrow, '8', 0, // EActionDown + EStdKeyLeftArrow, '4', 0, // EActionLeft + EStdKeyRightArrow, '6', 0, // EActionRight + EStdKeyDevice3, EStdKeyYes, '5', 0, // EActionFire + + '7', 0, // EActionGameA + '9', 0, // EActionGameB + EStdKeyNkpAsterisk, '*', 0, // EActionGameC + EStdKeyHash, 0 // EActionGameD +}; + +// Full QWERTY keyboard with screen in the middle (Table 14 in internal specs) +const TInt KDefaultQwertyActionScanCodes[] = +{ + EStdKeyUpArrow, 'R', 'P', 0, // EActionUp + EStdKeyDownArrow, 'V', EStdKeyForwardSlash, 0, // EActionDown + EStdKeyLeftArrow, 'D', 'L', 0, // EActionLeft + EStdKeyRightArrow, 'G', EStdKeySingleQuote, 0, // EActionRight + 'A', 'J', EStdKeyDevice3, 0, // EActionFire + + EStdKeyHash, 'H', 0, // EActionGameA + 'S', 'K', 0, // EActionGameB + 'Q', 'U', 0, // EActionGameC + 'Z', 'M', 0 // EActionGameD +}; + + + +/** Usual symbian two phase construction. @see ConstructL() */ +CMIDKeyDecoder* CMIDKeyDecoder::NewL(MMIDEnv& aEnv) +{ + CMIDKeyDecoder* self = new(ELeave) CMIDKeyDecoder(aEnv); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; +} + +/** */ +CMIDKeyDecoder::~CMIDKeyDecoder() +{ + DEBUG("< CMIDKeyDecoder::~CMIDKeyDecoder"); + iSpecialKeys.Close(); + iGameActions.ResetAndDestroy(); + + delete iCaptureKeys; + delete iKeyTranslator; + + delete iQwertyWatch; + + if (iUseCRScanCodes) + { + delete iActionScanCodes; + } + + FeatureManager::UnInitializeLib(); + + delete iRemConObserver; + + DEBUG("> CMIDKeyDecoder::~CMIDKeyDecoder"); +} + +/** */ +CMIDKeyDecoder::CMIDKeyDecoder(MMIDEnv& aEnv) + : iEnv(aEnv) + ,iMediaKeysEnabled(EFalse) +{ + DEBUG("< CMIDKeyDecoder::CMIDKeyDecoder"); + DEBUG("> CMIDKeyDecoder::CMIDKeyDecoder"); +} + +/** +Creates the key translator and another accessory, the capture keys +(needed by the key translator). The key translator can convert scan codes +into key codes. Calls CreateGameActionsL(), which will fill iGameActions: +for each action a set of key codes will be stored. These are MIDP key codes. +*/ +void CMIDKeyDecoder::ConstructL() +{ + DEBUG("< CMIDKeyDecoder::ConstructL"); + + iCaptureKeys = new(ELeave) CCaptureKeys; + iCaptureKeys->Construct(); + + iKeyTranslator = CKeyTranslator::New(); + + // If Select key mapping is defined in central repository an extra MIDP + // keycode will be used for Select key. + // Not all the devices have rocker in their keyboard, + // so other key can be defined instead. + CRepository* repository = NULL; + TInt err = KErrNone; + TRAP(err, repository = CRepository::NewL(KCRUidMidpLcdui)); + // 2 bytes in scan code + TBuf8<2> scanCodeBuffer; + CleanupStack::PushL(repository); + err = repository->Get(KAdditionalSelectKeyMapping,scanCodeBuffer); + CleanupStack::PopAndDestroy(repository); + if (err == KErrNone) + { + TUint8 scanCodeLeft = scanCodeBuffer[0]; + TUint8 scanCodeRight = scanCodeBuffer[1]; + TUint scanCode = (scanCodeLeft << 8) + scanCodeRight; + if (scanCode != 0) + { + iAdditionalSelectkeyMapping = scanCode; + } + } + + CreateQwertyWatchL(); + CreateGameActionsL(); + + FeatureManager::InitializeLibL(); + + if (iEnv.MidletAttributeContainsVal( + LcduiMidletAttributes::KAttribUIEnhancement, + LcduiMidletAttributeValues::KUIEnhMediaKeys)) + { + InitRemConObserverL(); + iMediaKeysEnabled = ETrue; + } + + DEBUG("> CMIDKeyDecoder::ConstructL"); +} + +/** +Special keys that require separate handling: these are +either non unicode keys or non standard unicode keys. +For standard unicode keys, the MIDP key code is the +unicode charactler. */ + +void CMIDKeyDecoder::InitSpecialKeysL() +{ + iSpecialKeys.Reset(); + + // Keys shared by ITU-T and QWERTY modes + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyLeftArrow, KMIDKeyLeftArrow, R_MIDP_KEY_LEFT))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyRightArrow, KMIDKeyRightArrow, R_MIDP_KEY_RIGHT))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyUpArrow, KMIDKeyUpArrow, R_MIDP_KEY_UP))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyDownArrow, KMIDKeyDownArrow, R_MIDP_KEY_DOWN))); + // If Select key mapping is defined in central repository an extra MIDP keycode will be used for Select key. + if (iAdditionalSelectkeyMapping != 0) + { + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(iAdditionalSelectkeyMapping, KMIDKeySelect, R_MIDP_KEY_SELECT))); + } + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyDevice3, KMIDKeySelect, R_MIDP_KEY_SELECT))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyRightShift, KMIDKeyEdit, R_MIDP_KEY_EDIT))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyLeftShift, KMIDKeyEdit, R_MIDP_KEY_EDIT))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyF21, KMIDKeyEdit, R_MIDP_KEY_EDIT))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyLeftFunc, KMIDKeyEdit, R_MIDP_KEY_EDIT))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyRightFunc, KMIDKeyEdit, R_MIDP_KEY_EDIT))); + + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyYes, KMIDKeySend, R_MIDP_KEY_SEND))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyDevice0, KMIDKeyCBA1, R_MIDP_KEY_LSK))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyDevice1, KMIDKeyCBA2, R_MIDP_KEY_RSK))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyNo, KMIDKeyEnd, R_MIDP_KEY_END))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyApplication0,KMIDKeyApplications, R_MIDP_KEY_APPS))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyDevice6, KMIDKeyVoiceKey, R_MIDP_KEY_VOICE))); + // QWERTY keys for qwerty and ITU-T mode with qwerty wireless keyboard. + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeySpace,EKeySpace, R_MIDP_KEY_SPACE))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyEscape,EKeyEscape, R_MIDP_KEY_ESC))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyTab,EKeyTab, R_MIDP_KEY_TAB))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyEnter, EKeyLineFeed, R_MIDP_KEY_ENTER))); + // Diagonal keys for 9-way Navigation Support + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyDevice10, EKeyLeftUpArrow, R_MIDP_KEY_LEFT))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyDevice11,EKeyRightUpArrow, R_MIDP_KEY_RIGHT))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyDevice12,EKeyRightDownArrow, R_MIDP_KEY_RIGHT))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyDevice13,EKeyLeftDownArrow, R_MIDP_KEY_LEFT))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyDelete,EKeyDelete, R_MIDP_KEY_DELETE))); + if (!iQwertyModeActive) + { // ITU-T keys with different behaviour + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyBackspace, KMIDKeyClear, R_MIDP_KEY_CLEAR))); + } + else + { // QWERTY keys with different behaviour + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyBackspace, EKeyBackspace, R_MIDP_KEY_BACKSPACE))); + } + + /* + // Keys defined in specs but not yet present in Series 60 + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyNull,EKeyFormFeed, R_MIDP_KEY_FORM_FEED))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyNull,EKeyLineFeed, R_MIDP_KEY_LINE_FEED))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyNull,EKeyBell, R_MIDP_KEY_BELL))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyNull,EKeyVerticalTab, R_MIDP_KEY_VERTICAL_TAB))); + + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyNull,KMIDKeyClockWiseRotate, R_MIDP_KEY_CLOCKWISE_ROTATE))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyNull,KMIDKeyCounterClockWiseRotate, R_MIDP_KEY_COUNTER_CLOCKWISE_ROTATE))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyNull,KMIDKeyClockWiseFastRotate, R_MIDP_KEY_CLOCKWISE_FAST_ROTATE))); + User::LeaveIfError(iSpecialKeys.Append(TMIDKey(EStdKeyNull,KMIDKeyCounterClockWiseFastRotate, R_MIDP_KEY_COUNTER_CLOCKWISE_FAST_ROTATE))); + */ + + // Add media keys. These are used only in GetKeyName method. + // EStdKeyNull used as a scancode as media keys don't have a real scancode. + User::LeaveIfError(iSpecialKeys.Append( + TMIDKey(EStdKeyNull, MMIDMediaKeysListener::EMIDMediaKeyPlay, R_MIDP_KEY_PLAY))); + User::LeaveIfError(iSpecialKeys.Append( + TMIDKey(EStdKeyNull, MMIDMediaKeysListener::EMIDMediaKeyPrevious, R_MIDP_KEY_PREVIOUS))); + User::LeaveIfError(iSpecialKeys.Append( + TMIDKey(EStdKeyNull, MMIDMediaKeysListener::EMIDMediaKeyNext, R_MIDP_KEY_NEXT))); + User::LeaveIfError(iSpecialKeys.Append( + TMIDKey(EStdKeyNull, MMIDMediaKeysListener::EMIDMediaKeyStop, R_MIDP_KEY_STOP))); + + // Zoom in and zoom out keys events support + User::LeaveIfError(iSpecialKeys.Append( + TMIDKey(EStdKeyApplicationC, KMIDKeyZoomIn, R_MIDP_KEY_ZOOM_IN))); + User::LeaveIfError(iSpecialKeys.Append( + TMIDKey(EStdKeyApplicationD, KMIDKeyZoomOut, R_MIDP_KEY_ZOOM_OUT))); +}; + + + +/** */ +void CMIDKeyDecoder::CreateQwertyWatchL() +{ + iQwertyWatch = CMIDQwertyWatch::NewL(this); +} + + +void CMIDKeyDecoder::InitRemConObserverL() +{ + if (!iRemConObserver) + { + iRemConObserver = CMIDRemConObserver::NewL(); + } +} + +/** */ +void CMIDKeyDecoder::NewQwertyValueL(TInt aNewValue) +{ + TBool oldQwertyMode = iQwertyModeActive; + + if (aNewValue == 1) + { + iQwertyModeActive = ETrue; + } + else + { + iQwertyModeActive = EFalse; + } + + if (iQwertyModeActive != oldQwertyMode) + { + CreateGameActionsL(); + } +} + +/** + * Gets a key code that corresponds to the specified game action on the device. + * The implementation is required to provide a mapping for every game action, + * so this method will always return a valid key code for every game action. + * + * Note that a key code is associated with at most one game action, whereas a + * game action may be associated with several key codes. + * + * Returns zero if aGameAction is not a valid game action + */ +TInt CMIDKeyDecoder::GetKeyCode(TInt aGameAction) +{ + DEBUG_INT("< CMIDKeyDecoder::GetKeyCode - game action is %D", aGameAction); + for (TInt i = 0; i < KNumGameActions; ++i) + { + if (iGameActions[i]->iActionCode == aGameAction) + { + DEBUG_INT("> CMIDKeyDecoder::GetKeyCode - return code %D", iGameActions[i]->iCodes[0]); + return iGameActions[i]->iCodes[0]; //just return the first code + } + } + + DEBUG_INT("> CMIDKeyDecoder::GetKeyCode - return code %D", 0); + return 0; +} + +/** + * Maps EPOC scan code to negative key code required by MIDP spec. + * For keys that have no corresponding Unicode character, + * the implementation must use negative values. + */ +TInt CMIDKeyDecoder::MapNonUnicodeKey(TUint aScanCode) +{ + DEBUG_INT("< CMIDKeyDecoder::MapNonUnicodeKey - scan code is %D", aScanCode); + TInt numSpecialKeys = iSpecialKeys.Count(); + for (TInt i = 0; i < numSpecialKeys; i++) + { + if (iSpecialKeys[i].iScanCode == aScanCode) + { + DEBUG_INT("> CMIDKeyDecoder::MapNonUnicodeKey - return code is %D", iSpecialKeys[i].iMIDPCode); + return iSpecialKeys[i].iMIDPCode; + } + } + + DEBUG_INT("> CMIDKeyDecoder::MapNonUnicodeKey - return code is %D", 0); + return 0; +} + +/** + * Gets an informative key string for a key. The string returned will resemble the text + * physically printed on the key. This string is suitable for displaying to the user. + * For example, on a device with function keys F1 through F4, calling this method on + * the keyCode for the F1 key will return the string "F1". A typical use for this string + * will be to compose help text such as "Press F1 to proceed." + * + * This method will return a non-empty string for every valid key code. + * + */ +void CMIDKeyDecoder::GetKeyName(TDes& aText,TInt aKeyCode) +{ + DEBUG_INT("< CMIDKeyDecoder::GetKeyName - key code is %D", aKeyCode); + aText.Zero(); + + TInt resId = R_MIDP_KEY_NON_CHARACTER; + TInt numSpecialKeys = iSpecialKeys.Count(); + for (TInt i = 0; i < numSpecialKeys; i++) + { + if (iSpecialKeys[i].iMIDPCode == aKeyCode) + { + resId = iSpecialKeys[i].iNameResId; + break; + } + } + + if ((resId == R_MIDP_KEY_NON_CHARACTER) && (IsUnicode(aKeyCode))) + { + aText.Append(TChar(aKeyCode)); + } + else + { + CEikonEnv::Static()->ReadResource(aText,resId); + } + + DEBUG_STR("> CMIDKeyDecoder::GetKeyName - key name is %S", aText); +} + + +TInt CMIDKeyDecoder::GameAction(TInt aKeyCode) +{ + DEBUG_INT("< CMIDKeyDecoder::GameAction - key code is %D", aKeyCode); + + for (TInt i = 0; i < KNumGameActions; ++i) + { + TInt numCodes = iGameActions[i]->iCodes.Count(); + for (TInt j = 0; j < numCodes; ++j) + { + if (iGameActions[i]->iCodes[j] == aKeyCode) + { + DEBUG_INT("> CMIDKeyDecoder::GameAction -game action is %D", iGameActions[i]->iActionCode); + return iGameActions[i]->iActionCode; + } + } + } + + DEBUG_INT("> CMIDKeyDecoder::GameAction -game action is %D", 0); + return 0; //invalid action +} + +/** + * Determines if a key code should be sent to MIDP applications. + */ +TBool CMIDKeyDecoder::IsJavaKey(TInt aScanCode) +{ + TBool ret = (ScanToMidpCode(aScanCode) != 0); + + DEBUG_INT2("<> CMIDKeyDecoder::IsJavaKey - return %D for scan code %D", ret, aScanCode); + return ret; +} + +TBool CMIDKeyDecoder::MediaKeysEnabled() const +{ + return iMediaKeysEnabled; +} + +CMIDRemConObserver* CMIDKeyDecoder::GetRemConObserver() +{ + return iRemConObserver; +} + +/** Create the game actions. This method is called at startup and +each time the qwerty availability changes. Because special keys +also depend on qwerty availability, call InitSpecialKeysL() - +which will reset special keys. The reset the actions and call +LoadGameActionCodesL() - which loads the correct codes. Then +for each action appens the codes stored in iActionScanCodes. +Action codes in this array are separated by a null byte. */ +void CMIDKeyDecoder::CreateGameActionsL() +{ + DEBUG("< CMIDKeyDecoder::CreateGameActionsL"); + + InitSpecialKeysL(); + iGameActions.ResetAndDestroy(); + + LoadGameActionCodesL(); + ASSERT(iActionScanCodes != NULL); + + TInt index = 0; + for (TInt i = 0; i < KNumGameActions; ++i) + { + TMIDGameAction* action = new(ELeave) TMIDGameAction(KActionCodes[i]); + CleanupStack::PushL(action); + + while (iActionScanCodes[index] != 0) + { + AddCodeToActionL(action, iActionScanCodes[index]); + index++; + } + index++; // skip null byte separating actions + + User::LeaveIfError(iGameActions.Append(action)); + CleanupStack::Pop(action); + } + + DEBUG("> CMIDKeyDecoder::CreateGameActionsL"); +} + +/** Load the game action codes: either the default ITU-T codes + if no qwerty input is available or load the codes + from Central Repository (if available and if + flag in CR indicates to do so) or load some default QWERTY codes. +*/ +void CMIDKeyDecoder::LoadGameActionCodesL() +{ + DEBUG("< CMIDKeyDecoder::LoadGameActionCodesL"); + + if (iUseCRScanCodes) + { + delete iActionScanCodes; + iUseCRScanCodes = EFalse; + } + + iActionScanCodes = NULL; + + if (!QwertyInputAvailable()) + { // if no qwerty always use default ITU-T codes + DEBUG(" CMIDKeyDecoder::LoadGameActionCodesL - use default ITU-T scan codes"); + iActionScanCodes = (TInt*)&KDefaultActionScanCodes[0]; + } + else + { // if there is qwerty either use CR repository codes or default qwerty codes + CRepository* repository = NULL; + TRAPD(crExists, repository = CRepository::NewL(KCRUidMidpLcdui)); + + if (crExists == KErrNone) + { + CleanupStack::PushL(repository); + repository->Get(KUseCustomGameActionScanCodes, iUseCRScanCodes); + } + + if (iUseCRScanCodes) + { // use CR QWERTY codes + DEBUG(" CMIDKeyDecoder::LoadGameActionCodesL - use central repository scan codes"); + LoadCentralRepositoryCodesL(repository); + } + else + { // use default QWERTY codes + DEBUG(" CMIDKeyDecoder::LoadGameActionCodesL - add default qwerty scan codes"); + iActionScanCodes = (TInt*)&KDefaultQwertyActionScanCodes[0]; + } + + if (crExists == KErrNone) + { + CleanupStack::PopAndDestroy(repository); + } + } + + DEBUG("> CMIDKeyDecoder::LoadGameActionCodesL"); +} + +/** Load the game action scan codes stored in the central repository + database. Two bytes are available per scan code, LSB is left. Max + number of codes per action is KMaxScanCodesPerAction. Allocate + some memory for iActionScanCodes. + */ +void CMIDKeyDecoder::LoadCentralRepositoryCodesL(CRepository* aRepository) +{ + DEBUG("< CMIDKeyDecoder::LoadCentralRepositoryCodesL"); + + ASSERT(aRepository != NULL); + ASSERT(iActionScanCodes == NULL); + + iActionScanCodes = new(ELeave) TInt[KNumGameActions*KMaxScanCodesPerAction]; + + TInt index = 0; + for (TInt i = 0; i < KNumGameActions; ++i) + { + //2 bytes per scan code + TBuf8 scanCodeBuffer; + aRepository->Get(KActionKeys[i],scanCodeBuffer); + + for (TInt j = 0; j < (scanCodeBuffer.Length() - 1); j++) + { + TUint8 scanCodeLeft = scanCodeBuffer[j++]; + TUint8 scanCodeRight = scanCodeBuffer[j]; + + TUint scanCode = (scanCodeLeft << 8) + scanCodeRight; + + if (scanCode != 0) + { + iActionScanCodes[index++] = scanCode; + } + } + + iActionScanCodes[index++] = 0; //indicates end of scan codes + } + + DEBUG("> CMIDKeyDecoder::LoadCentralRepositoryCodesL"); +} + +/** Return true if this device supports qwerty and the qwerty keyboard + is available */ +TBool CMIDKeyDecoder::QwertyInputAvailable() const +{ + return iQwertyModeActive; +} + +/** + Convert the scan code into a MIDP key code taking into account possible + modifiers. Add the resulting MIDP key codes to the action specified as long + as they are all different. + */ +void CMIDKeyDecoder::AddCodeToActionL(TMIDGameAction* aGameAction, TInt aScanCode) +{ + DEBUG_INT("< CMIDKeyDecoder::AddCodeToActionL - scan code is %D", aScanCode); + TInt midpCode = ScanToMidpCode(aScanCode); + + if (aGameAction->iCodes.Find(midpCode) == KErrNotFound && midpCode != 0) + { + DEBUG_INT(" CMIDKeyDecoder::AddCodeToActionL - adding midp code %D", midpCode); + User::LeaveIfError(aGameAction->iCodes.Append(midpCode)); + } + + if (IsUnicode(midpCode)) + { + midpCode = ScanToMidpCode(aScanCode | EModifierShift); + + if (aGameAction->iCodes.Find(midpCode) == KErrNotFound) + { + DEBUG_INT(" CMIDKeyDecoder::AddCodeToActionL - adding midp code %D", midpCode); + User::LeaveIfError(aGameAction->iCodes.Append(midpCode)); + } + } + + DEBUG("> CMIDKeyDecoder::AddCodeToActionL"); +} + +/** Take a scan code and convert it into a MIDP code. First see if it +is one of the special keys, otherwise ask the window server to convert it. */ +TInt CMIDKeyDecoder::ScanToMidpCode(TInt aScanCode) +{ + DEBUG_INT("< CMIDKeyDecoder::ScanToMidpCode - scan Code is %D", aScanCode); + TInt keyCode = MapNonUnicodeKey(aScanCode); + + if (keyCode == 0) + { + // fake a key down to convert scan code into key code + // Note: on WINS (and WINSCW) this conversion works only for QWERTY layout + // unless you specify the char code in the HI part of the scan code - which + // we cannot do - hence on the emulator only QWERTY layout works. + TKeyData keyData; + TBool translated = iKeyTranslator->TranslateKey(aScanCode,EFalse,*iCaptureKeys,keyData); + + if (translated) + { + DEBUG_INT(" CMIDKeyDecoder::ScanToMidpCode - ws translated code is %D", keyData.iKeyCode); + keyCode = IsUnicode(keyData.iKeyCode) ? keyData.iKeyCode : 0; + } + + // fake a key up to restore modifiers + iKeyTranslator->TranslateKey(aScanCode,ETrue,*iCaptureKeys,keyData); + } + + DEBUG_INT("> CMIDKeyDecoder::ScanToMidpCode - return key code %D", keyCode); + return keyCode; +} + +/** Return true if the key code corresponds to a unicode character */ +TBool CMIDKeyDecoder::IsUnicode(TInt aKeyCode) const +{ + TBool ret = (aKeyCode > 0) && (aKeyCode < ENonCharacterKeyBase || + aKeyCode >= (ENonCharacterKeyBase + ENonCharacterKeyCount)); + + DEBUG_INT2("<> CMIDKeyDecoder::IsUnicode - return %D for key code %D", ret, aKeyCode); + return ret; +} + +TInt CMIDKeyDecoder::AdditionalSelectionKeyMappingCode() +{ + return iAdditionalSelectkeyMapping; +}