predictivesearch/PcsAlgorithm/Algorithm2/src/CPcsKeyMap.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 19 Aug 2010 09:41:07 +0300
branchRCL_3
changeset 18 d4f567ce2e7c
parent 7 b3431bff8c19
permissions -rw-r--r--
Revision: 201031 Kit: 201033

/*
* Copyright (c) 2007 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:  Retrieves the character map for each of the numeric keys.
*                Uses services provided by the PTI Engine.
*
*/

// INCLUDE FILES

#include "CPcsAlgorithm2.h"
#include "CPcsAlgorithm2Utils.h"
#include "FindUtilChineseECE.h"
#include "CPcsDebug.h"
#include "CPcsKeyMap.h"
#include "CPsQueryItem.h"
#include <PtiEngine.h>
#include <PtiKeyMapData.h>
#include <bldvariant.hrh>
#include <AknFepInternalCRKeys.h>


// Unnamed namespace for local definitions
namespace {

#ifdef _DEBUG
    enum TPanicCode
    {
        EPanicPreCond_MultipleSingleCharMatching = 1,
        EPanicPreCond_MultipleUIPriorityMatching = 2,
        EPanicPreCond_MultipleEnglishPriorityMatching = 3,
        EPanicPreCond_MultipleOthersPriorityMatching = 4,
        EPanic_OverflowInPoolIndex = 5,
        EPanic_InvalidKeyboardType = 6
   };

    void Panic(TInt aReason)
    {
        _LIT(KPanicText, "CPcsKeyMap");
        User::Panic(KPanicText, aReason);
    }
#endif // DEBUG

} // namespace


// ============================== MEMBER FUNCTIONS ============================

// ----------------------------------------------------------------------------
// CPcsKeyMap::NewL
// Two Phase Construction
// ----------------------------------------------------------------------------
CPcsKeyMap* CPcsKeyMap::NewL(CPcsAlgorithm2* aAlgorithm)
    {
    PRINT ( _L("Enter CPcsKeyMap::NewL") );

    CPcsKeyMap* self = new (ELeave) CPcsKeyMap();
    CleanupStack::PushL(self);
    self->ConstructL(aAlgorithm);
    CleanupStack::Pop(self);

    PRINT ( _L("End CPcsKeyMap::NewL") );

    return self;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::CPcsKeyMap
// Constructor
// ----------------------------------------------------------------------------
CPcsKeyMap::CPcsKeyMap()
    {
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::ConstructL
// 2nd Phase Constructor
// ----------------------------------------------------------------------------
void CPcsKeyMap::ConstructL(CPcsAlgorithm2* aAlgorithm)
    {
    iLanguageNotSupported.Append(ELangJapanese);
    iLanguageNotSupported.Append(ELangKorean);

    iAlgorithm = aAlgorithm;
    iPtiEngine = CPtiEngine::NewL();

    SetupKeyboardTypesL();
    ConstructKeymapL();
    SetSpaceAndZeroOnSameKey();
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::ReconstructKeymapL
// When the writing language is changed, the keymap needs reconstruct.
// ----------------------------------------------------------------------------
void CPcsKeyMap::ReconstructKeymapL()
    {
    // Clear the keymap data array first when reconstruct the keymap.
    ResetKeyMap();
    
    // Always add English mappings first
    AddKeyMapforConcreteKeyboardL( ELangEnglish );
    
    // Then append the mappings of the current input language
    TLanguage lang = iAlgorithm->FindUtilECE()->CurrentInputLanguage();
    if ( lang != ELangEnglish && IsLanguageSupportedL(lang) )
        {
        AddKeyMapforConcreteKeyboardL( lang );
        }
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::ConstructKeymapL
// 
// ----------------------------------------------------------------------------
void CPcsKeyMap::ConstructKeymapL()
    {
    ConstructConcreteKeyMapL();
    
    // Always add English mappings first
    AddKeyMapforConcreteKeyboardL( ELangEnglish );
    
    // Then append the mappings of the current input language
    TLanguage lang = iAlgorithm->FindUtilECE()->CurrentInputLanguage();
    if ( lang != ELangEnglish && IsLanguageSupportedL(lang) )
        {
        AddKeyMapforConcreteKeyboardL( lang );
        }
    
    PRINT ( _L("----------------------------------------"));
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::SetupKeyboardTypesL
// Initialise the keyboard type variables
// ----------------------------------------------------------------------------
void CPcsKeyMap::SetupKeyboardTypesL()
    {
    TInt physicalKeyboard = 0;
    CRepository* aknFepRepository = CRepository::NewL( KCRUidAknFep );
    aknFepRepository->Get( KAknFepPhysicalKeyboards, physicalKeyboard );
    delete aknFepRepository;

    PRINT1 ( _L("CPcsKeyMap::ConstructL: Physical keyboard support flag = 0x%02X"), physicalKeyboard );

    // Constants follow the definition of KAknFepPhysicalKeyboards
    const TInt KPtiKeyboard12Key = 0x01;
    const TInt KPtiKeyboardQwerty4x12 = 0x02;
    const TInt KPtiKeyboardQwerty4x10 = 0x04;
    const TInt KPtiKeyboardQwerty3x11 = 0x08;
    const TInt KPtiKeyboardHalfQwerty = 0x10;
    const TInt KPtiKeyboardCustomQwerty = 0x20; 

    // Setup ITU-T mode first.
    // Use always 12-key mode since all the supported devices should have at least
    // virtual ITU-T available.
    iItutKeyboardType = EPtiKeyboard12Key;
    // TODO: ITU-T type could be set to "none" if device does not have either
    // virtual keypad or hardware ITU-T available. This could be decided according
    // some cenrep value, feature flag, device model, or platform version.
    
    // Then setup QWERTY mode. On real-life devices there should never
    // be more than one QWERTY keyboard available but on emulator there can be several.
    // Use the first one found in the following precedence
    if ( physicalKeyboard & KPtiKeyboardQwerty3x11 )
        {
        iQwertyKeyboardType = EPtiKeyboardQwerty3x11;
        }
    else if ( physicalKeyboard & KPtiKeyboardQwerty4x10 )
        {
        iQwertyKeyboardType = EPtiKeyboardQwerty4x10;
        }
    else if ( physicalKeyboard & KPtiKeyboardQwerty4x12 )
        {
        iQwertyKeyboardType = EPtiKeyboardQwerty4x12;
        }
    else if ( physicalKeyboard & KPtiKeyboardCustomQwerty )
        {
        iQwertyKeyboardType = EPtiKeyboardCustomQwerty;
        }
    else if ( physicalKeyboard & KPtiKeyboardHalfQwerty )
        {
        iQwertyKeyboardType = EPtiKeyboardHalfQwerty;
        }
    else
        {
        iQwertyKeyboardType = EPtiKeyboardNone;
        }
    
    // Decide, which keyboard is used for the "default" matching mode.
    // If there is physical ITU-T available, or there's no physical QWERTY,
    // then ITU-T is default.
    iItutIsDefault = (physicalKeyboard & KPtiKeyboard12Key) || 
                     (iQwertyKeyboardType == EPtiKeyboardNone);
    
    PRINT1 ( _L("CPcsKeyMap::ConstructL: ITU-T Keyboard chosen for Predictive Search = %d"), iItutKeyboardType );
    PRINT1 ( _L("CPcsKeyMap::ConstructL: QWERTY Keyboard chosen for Predictive Search = %d"), iQwertyKeyboardType );
    }


// ----------------------------------------------------------------------------
// CPcsKeyMap::ConstructConcreteKeyMapL
// 
// ----------------------------------------------------------------------------
void CPcsKeyMap::ConstructConcreteKeyMapL()
    {
    if ( iItutKeyboardType != EPtiKeyboardNone )
        {
        // Construct for Itut keyboard by default
        PRINT ( _L("CPcsKeyMap::ConstructConcreteKeyMapL: Construct keymap for ITU-T"));
        ConstructForItutKeyboardL();
        }
    if ( iQwertyKeyboardType != EPtiKeyboardNone )
        {
        // Construct for any QWERTY keyboard
        PRINT1 ( _L("CPcsKeyMap::ConstructConcreteKeyMapL: Construct keymap for QWERTY keyboard type %d"), 
                 iQwertyKeyboardType );
        ConstructForQwertyKeyboardL( iQwertyKeyboardType );
        }
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::AddKeyMapforConcreteKeyboardL
// 
// ----------------------------------------------------------------------------
void CPcsKeyMap::AddKeyMapforConcreteKeyboardL( TLanguage aLanguage )
    {
    if ( iItutKeyboardType != EPtiKeyboardNone )
        {
        AddKeyMapforItutL( aLanguage );
        }
    
    if ( iQwertyKeyboardType != EPtiKeyboardNone )
        {
        AddKeyMapForQwertyKeyboardL( aLanguage, iQwertyKeyboardType );
        }
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::ResetKeyMap
// 
// ----------------------------------------------------------------------------
void CPcsKeyMap::ResetKeyMap()
    {
    const TInt ItutKeyMappingsCount = iItutKeyMappings.Count();
    const TInt qwertyKeyMappingsCount = iQwertyKeyMappings.Count();
    for (TInt i = 0; i < ItutKeyMappingsCount; i++)
        {
        iItutKeyMappings[i]->iKeyMappingArray.Reset();
        }
    for (TInt i = 0; i < qwertyKeyMappingsCount; i++)
        {
        iQwertyKeyMappings[i]->iKeyMappingArray.Reset();
        }
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::~CPcsKeyMap
// Destructor
// ----------------------------------------------------------------------------
CPcsKeyMap::~CPcsKeyMap()
    {
    ResetKeyMap();

    // Cleanup local arrays
    iLanguageNotSupported.Reset();
    iItutKeyMappings.ResetAndDestroy();
    iItutKeys.Close();
    iQwertyKeyMappings.ResetAndDestroy();
    iQwertyKeys.Close();
    delete iPtiEngine;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::GetMixedKeyStringForQueryL
// aDestStr will have the length as the number of items in aSrcQuery.
// ----------------------------------------------------------------------------
void CPcsKeyMap::GetMixedKeyStringForQueryL(
        CPsQuery& aSrcQuery, TDes& aDestStr) const
{
    PRINT ( _L("Enter CPcsKeyMap::GetMixedKeyStringForQueryL") ); 

    GetMixedKeyStringForDataL( aSrcQuery, aSrcQuery.QueryAsStringLC(), aDestStr );
    CleanupStack::PopAndDestroy(); //result of QueryAsStringLC

    PRINT ( _L("End CPcsKeyMap::GetMixedKeyStringForQueryL") );
}

// ----------------------------------------------------------------------------
// CPcsKeyMap::GetMixedKeyStringForDataL
// aDestStr will have the same length as aSrcData. aSrcQuery can be shorter.
// ----------------------------------------------------------------------------
void CPcsKeyMap::GetMixedKeyStringForDataL(
        CPsQuery& aSrcQuery, const TDesC& aSrcData, TDes& aDestStr) const
{
    PRINT ( _L("Enter CPcsKeyMap::GetMixedKeyStringForDataL") );

    const TInt srcDataLength = aSrcData.Length(); 
    for ( TInt i = 0; i < srcDataLength; ++i )
        {
        TChar character( aSrcData[i] );
        character.LowerCase();
        if ( i < aSrcQuery.Count() )
            {
            CPsQueryItem& currentItem = aSrcQuery.GetItemAtL(i);
            TKeyboardModes curMode = ResolveKeyboardMode( currentItem.Mode() );
            TPtiKey key = KeyForCharacter( aSrcData[i], curMode );
            // If a character is not mapped to any key or it's entered in non-predictive mode,
            // then append the character as exact.
            if ( EPtiKeyNone == key )
                {
                aDestStr.Append( character );
                }
            else
                {
                aDestStr.Append( DefaultCharForKey(key, curMode) );
                }
            }
        else
            {
            // characters over query length are taken as exact
            aDestStr.Append( character );
            }
        }

    PRINT1 ( _L("CPcsKeyMap::GetMixedKeyStringForDataL: Return string: \"%S\""),
             &aDestStr );

    PRINT ( _L("End CPcsKeyMap::GetMixedKeyStringForDataL") );
}

// ----------------------------------------------------------------------------
// CPcsKeyMap::KeyForCharacter
// 
// ----------------------------------------------------------------------------
TPtiKey CPcsKeyMap::KeyForCharacter(TText aChar, TKeyboardModes aKbMode) const
    {
    const RPointerArray<TKeyMappingData>* keyMappings = KeyMappings( aKbMode );
    
    // Don't return any key in the exact mode
    if ( !keyMappings )
        {
        return EPtiKeyNone;
        }
    
    TInt index = KErrNotFound;

    TText lChar = User::LowerCase(aChar);

    const TInt count = keyMappings->Count() - 1;

    for (TInt i = 0; i < count; i++)
        {
        index = (*keyMappings)[i]->iKeyMappingArray.Find(lChar);
        if (index != KErrNotFound)
            {
            return (*keyMappings)[i]->iKey;
            }
        }

    return EPtiKeyNone;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::AddKeyMapForQwertyKeyboardL
// 
// ----------------------------------------------------------------------------
void CPcsKeyMap::AddKeyMapForQwertyKeyboardL(TLanguage aLanguage, TPtiKeyboardType aKbType)
    {
#ifdef RD_INTELLIGENT_TEXT_INPUT
    iPtiEngine->ActivateLanguageL(aLanguage);
    iPtiEngine->SetKeyboardType(aKbType);

    // Make a language object based on current language
    CPtiCoreLanguage* coreLanguage = static_cast<CPtiCoreLanguage*>(iPtiEngine->GetLanguage( aLanguage ));

    //Perfrom the key mappings only if the corelanguage is available
    if (coreLanguage)
        {
        // Get the keyboard mappings for the language
        CPtiKeyMapData* ptiKeyMapData = coreLanguage->RawKeyMapData();

        const TInt qwertyKeyMappingsCount = iQwertyKeyMappings.Count() - 1;
        for (TInt i = 0; i < qwertyKeyMappingsCount; i++)
            {
            AddDataForQwertyKeyboardL( ptiKeyMapData, aKbType, 
                    iQwertyKeys[i], *(iQwertyKeyMappings[i]) );
            }
        }
#endif // RD_INTELLIGENT_TEXT_INPUT        
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::ConstructForQwertyKeyboardL
// Destructor
// ----------------------------------------------------------------------------
void CPcsKeyMap::ConstructForQwertyKeyboardL(TPtiKeyboardType aKbType)
    {
#ifdef RD_INTELLIGENT_TEXT_INPUT
    CreateKeyListFromKeyBindingTable( iQwertyKeys, aKbType );

    // Now add the keymap arrays to hold the keymap data
    const TInt qwertyKeysCount = iQwertyKeys.Count();
    for (TInt i = 0; i < qwertyKeysCount; i++)
        {
        TKeyMappingData* keyData = new (ELeave) TKeyMappingData;
        keyData->iKey = iQwertyKeys[i];
        iQwertyKeyMappings.Append(keyData);
        }

    PRINT ( _L("----------------------------------------"));
#endif //RD_INTELLIGENT_TEXT_INPUT
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::AddDataForQwertyKeyboardL
// 
// ----------------------------------------------------------------------------
void CPcsKeyMap::AddDataForQwertyKeyboardL(CPtiKeyMapData* aPtiKeyMapData,
                                           TPtiKeyboardType aKbType,
                                           TPtiKey aKey,
                                           TKeyMappingData& aKeyDataList)
    {
#ifdef RD_INTELLIGENT_TEXT_INPUT     	
    TPtiTextCase caseArray[] =
        {
        EPtiCaseUpper,
        EPtiCaseLower,
        EPtiCaseFnLower,
        EPtiCaseFnUpper,
        EPtiCaseChrLower,
        EPtiCaseChrUpper
        };
    
    for (TInt i = 0; i < sizeof(caseArray) / sizeof(TPtiTextCase); i++)
        {
        TPtrC result = aPtiKeyMapData->DataForKey(aKbType, aKey, caseArray[i]);

        const TInt resultLength = result.Length(); 
        for (TInt j = 0; j < resultLength; j++)
            aKeyDataList.iKeyMappingArray.Append(result[j]);

        PRINT2 ( _L("CPcsKeyMap: Mapping for Key %c = %S"), aKey, &result)
        }
#endif //RD_INTELLIGENT_TEXT_INPUT        
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::ContructForItutKeyboardL
// 
// ----------------------------------------------------------------------------
void CPcsKeyMap::ConstructForItutKeyboardL()
    {
    // Add the keys for Pool formation
    iItutKeys.Append(EPtiKey0);
    iItutKeys.Append(EPtiKey1);
    iItutKeys.Append(EPtiKey2);
    iItutKeys.Append(EPtiKey3);
    iItutKeys.Append(EPtiKey4);
    iItutKeys.Append(EPtiKey5);
    iItutKeys.Append(EPtiKey6);
    iItutKeys.Append(EPtiKey7);
    iItutKeys.Append(EPtiKey8);
    iItutKeys.Append(EPtiKey9);
    // one additional pool for special characters not mapped too any keys. 
    // This should always be the last one in the arrary
    iItutKeys.Append(EPtiKeyNone);

    // Now add the keymap arrays to hold the keymap data
    const TInt ltutKeysCount = iItutKeys.Count();
    for (TInt i = 0; i < ltutKeysCount; i++)
        {
        TKeyMappingData *keyData = new (ELeave) TKeyMappingData;
        keyData->iKey = iItutKeys[i];
        iItutKeyMappings.Append(keyData);
        }

    PRINT ( _L("----------------------------------------"));
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::AddKeyMapforItutLanguageL
// 
// ----------------------------------------------------------------------------
void CPcsKeyMap::AddKeyMapforItutL(TLanguage aLanguage)
    {
    // Activate given language and get corresponding language object
    iPtiEngine->ActivateLanguageL(aLanguage);
    CPtiCoreLanguage* coreLanguage = static_cast<CPtiCoreLanguage*> (iPtiEngine->GetLanguage(aLanguage));

    //Perfrom the key mappings only if the corelanguage is available
    if (coreLanguage)
        {
        // Get the keyboard mappings for the language
        CPtiKeyMapData* ptiKeyMapData = coreLanguage->RawKeyMapData();

        const TInt ltutKeyMappingsCount = iItutKeyMappings.Count() - 1;
        for (TInt i = 0; i < ltutKeyMappingsCount; i++)
            {
            AddDataForItutKeyboardL(ptiKeyMapData, iItutKeys[i], *(iItutKeyMappings[i]));
            }
        }

    if ( (aLanguage == ELangPrcChinese || aLanguage == ELangTaiwanChinese || aLanguage == ELangHongKongChinese) && 
         (iAlgorithm->FindUtilECE()->CurrentSearchMethod() == EAdptSearchStroke) )
        {
        (*(iItutKeyMappings[1])).iKeyMappingArray.Append(0x4E00); //heng
        (*(iItutKeyMappings[2])).iKeyMappingArray.Append(0x4E28); //shu
        (*(iItutKeyMappings[3])).iKeyMappingArray.Append(0x4E3F); //pie
        (*(iItutKeyMappings[4])).iKeyMappingArray.Append(0x4E36); //dian
        (*(iItutKeyMappings[5])).iKeyMappingArray.Append(0x4E5B); //zhe
        }

    }
// ----------------------------------------------------------------------------
// CPcsKeyMap::AddDataForItutKeyboardL
// 
// ----------------------------------------------------------------------------
void CPcsKeyMap::AddDataForItutKeyboardL(CPtiKeyMapData* aPtiKeyMapData, TPtiKey aKey, TKeyMappingData& aKeyDataList)
    {
    TPtiTextCase caseArray[] = { EPtiCaseUpper, EPtiCaseLower };
    for (TInt i = 0; i< sizeof(caseArray) / sizeof(TPtiTextCase); i++)
        {
        TPtrC result = aPtiKeyMapData->DataForKey(EPtiKeyboard12Key, aKey, caseArray[i]);
        const TInt resultLength =  result.Length();
        for (TInt j = 0; j < resultLength; j++)
            aKeyDataList.iKeyMappingArray.Append(result[j]);
        PRINT2 ( _L("CPcsKeyMap: Mapping for Key %c = %S"), aKey,&result)
        }
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::CreateKeyMapFromKeyBindingTable
//
// ----------------------------------------------------------------------------
void CPcsKeyMap::CreateKeyListFromKeyBindingTable( RArray<TPtiKey>& aKeyArray, 
        TPtiKeyboardType aKbType )
    {
    PRINT ( _L("Enter CPcsKeyMap::CreateKeyListFromKeyBindingTable") );

    // Use Eglish mappings to list the keys on the keyboard
    TRAP_IGNORE( iPtiEngine->ActivateLanguageL( ELangEnglish ) );
    CPtiCoreLanguage* ptiLang = 
            static_cast<CPtiCoreLanguage*>(iPtiEngine->GetLanguage( ELangEnglish ));

    if (ptiLang)
        {
        const CPtiKeyMapData* keyMapData = ptiLang->RawKeyMapData();
        const TPtiKeyBinding* table = NULL;
        TInt numItems = 0;
        if ( keyMapData )
            {
            table = keyMapData->KeyBindingTable(aKbType, numItems);
            }
        else
            {
            PRINT( _L("CPcsKeyMap::CreateKeyListFromKeyBindingTable: #### Failed to get RawKeyMapData ####") );
            }
        
        PRINT1 ( _L("CPcsKeyMap::CreateKeyListFromKeyBindingTable: Num of Items in KeyBindingTable is %d"), numItems );

        // Get from the key table the keys for constructing the pools
        if (table)
            {
            for (TInt i = 0; i < numItems; i++)
                {
                TPtiKey key = (TPtiKey) table[i].iScanCode;
                // Get all keys with same EPtiCaseLower or EPtiCaseUpper case
                // Only for one of the casing to avoid repetitions
                if ( (EPtiKeyNone != key) && (EPtiCaseLower == table[i].iCase) )
                    {
                    PRINT3 ( _L("CPcsKeyMap::CreateKeyListFromKeyBindingTable: Adding pool %d with key '%c' (0x%02X)"),
                            aKeyArray.Count(), key, key );
                    aKeyArray.Append( key );
                    }
                }
            }
        else
            {
            PRINT ( _L("CPcsKeyMap::CreateKeyListFromKeyBindingTable: ##### Failed to create Key List (KeyBindingTable) #####") );
            }
        }
    else
        {
        PRINT ( _L("CPcsKeyMap::CreateKeyListFromKeyBindingTable: ##### Failed to create Key List (Language) #####") );
        }

    // one additional pool for special characters not mapped too any keys. 
    // This should always be the last one in the arrary
    aKeyArray.Append(EPtiKeyNone);

    PRINT ( _L("End CPcsKeyMap::CreateKeyListFromKeyBindingTable") );
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::IsLanguageSupportedL
// Returns ETrue if this language is supported
// ----------------------------------------------------------------------------
TBool CPcsKeyMap::IsLanguageSupportedL(TUint32 aLang)
    {

    TBool flag = ETrue;
    const TInt languageNotSupportedCount = iLanguageNotSupported.Count();
    for (TInt i = 0; i < languageNotSupportedCount; i++)
        {
        if (iLanguageNotSupported[i] == aLang)
            {
            flag = EFalse;
            }
        }

    return flag;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::PoolIdForKey
//
// ----------------------------------------------------------------------------
TInt CPcsKeyMap::PoolIdForKey(TPtiKey aKey, TKeyboardModes aKbMode) const
    {
    __ASSERT_DEBUG( (aKbMode==EPredictiveItuT || aKbMode==EPredictiveQwerty),
                    Panic(EPanic_InvalidKeyboardType) );
    
    // From logical point of view, the Pool ID is an index of the key in
    // an array which is formed by concatenating QWERTY keys array in the end
    // of the ITU-T keys array.
    TInt poolId = KErrNotFound;
    if ( aKbMode == EPredictiveItuT && iItutKeys.Count() )
        {
        poolId = iItutKeys.Find(aKey);
        // IF the key is not found, then it should go to the special pool,
        // which is the pool of the dummy key in the ITU-T keys array
        if (KErrNotFound == poolId)
            {
            poolId = iItutKeys.Count() - 1;
            }
        }
    else if ( aKbMode == EPredictiveQwerty && iQwertyKeys.Count() )
        {
        poolId = iQwertyKeys.Find(aKey);
        // IF the key is not found, then it should go to the special pool,
        // which is the pool of the dummy key in the QWERTY keys array
        if (KErrNotFound == poolId)
            {
            poolId = iQwertyKeys.Count() - 1;
            }
        // Pools of QWERTY keys come after pools of ITU-T keys
        poolId += iItutKeys.Count();
        }

    // Pool ID must never exceed value 63, because CPcsCache class
    // stores these values as bitmask into 64 bit variable.
    __ASSERT_DEBUG( poolId < 64, Panic(EPanic_OverflowInPoolIndex) );
    return poolId;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::PoolIdForCharacter
// 
// ----------------------------------------------------------------------------
TInt CPcsKeyMap::PoolIdForCharacter( TChar aChar, TKeyboardModes aKbMode )
    {
    // Pools are formed according the predictive keyboard mapping(s).
    // When selecting pool for non-predictive mode, we use the pool of the
    // default keyboard. The non-predictive matches should be a sub set of the
    // predictive matches of the default keyboard, although strictly speaking,
    // there' no guarantee for this.
    if ( aKbMode == ENonPredictive || aKbMode == EPredictiveDefaultKeyboard )
        {
        aKbMode = ( iItutIsDefault ? EPredictiveItuT : EPredictiveQwerty );
        }

    // If character is a Chinese word character, then we select the
    // pool ID according the first character of the first spelling of the word.
    TRAP_IGNORE( aChar = FirstCharFromSpellingL( aChar ) );

    TPtiKey key = KeyForCharacter( aChar, aKbMode );
    TInt poolId = PoolIdForKey( key, aKbMode );

    return poolId;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::PoolCount
// 
// ----------------------------------------------------------------------------
TInt CPcsKeyMap::PoolCount()
    {
    return iItutKeyMappings.Count() + iQwertyKeyMappings.Count();
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::GetSpaceAndZeroOnSameKey
// 
// ----------------------------------------------------------------------------
TBool CPcsKeyMap::GetSpaceAndZeroOnSameKey( TKeyboardModes aMode )
    {
    // Resolve ambiguous keyboard mode
    aMode = ResolveKeyboardMode( aMode );
    
    if ( aMode == EPredictiveItuT )
        {
        return iSpaceAndZeroOnSameKeyOnItut;
        }
    else if ( aMode == EPredictiveQwerty )
        {
        return iSpaceAndZeroOnSameKeyOnQwerty;
        }
    else
        {
        return EFalse;
        }
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::SetSpaceAndZeroOnSameKey
// 
// ----------------------------------------------------------------------------
void CPcsKeyMap::SetSpaceAndZeroOnSameKey()
    {
    static const TInt KSpace = 0x20; // ASCII for " "
    static const TInt KZero  = 0x30; // ASCII for "0"

    TChar charSpace(KSpace);
    TChar charZero(KZero);

    TPtiKey keySpace;
    TPtiKey keyZero;
    
    // ITU-T mode
    keySpace = KeyForCharacter(charSpace, EPredictiveItuT);
    keyZero = KeyForCharacter(charZero, EPredictiveItuT);
    iSpaceAndZeroOnSameKeyOnItut = (keySpace == keyZero);
    
    // QWERTY mode
    keySpace = KeyForCharacter(charSpace, EPredictiveQwerty);
    keyZero = KeyForCharacter(charZero, EPredictiveQwerty);
    iSpaceAndZeroOnSameKeyOnQwerty = (keySpace == keyZero);
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::CPcsKeyMap::FirstCharFromSpellingL
// 
// ----------------------------------------------------------------------------
TChar CPcsKeyMap::FirstCharFromSpellingL( TChar aChar ) const
    {
    TChar translated( aChar );
    TBuf<1> temp;
    temp.Append( aChar );
    if ( iAlgorithm->FindUtilECE()->IsChineseWordIncluded( temp ) )
        {
        RPointerArray<HBufC> spellList;
        CleanupResetAndDestroyPushL( spellList );
        if (iAlgorithm->FindUtilECE()->DoTranslationL(aChar, spellList))
            {
            translated = (*spellList[0])[0];
            }
        CleanupStack::PopAndDestroy( &spellList ); // ResetAndDestroy
        }
    return translated;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::KeyMappings
//
// ----------------------------------------------------------------------------
const RPointerArray<TKeyMappingData>* CPcsKeyMap::KeyMappings( TKeyboardModes aMode ) const
    {
    const RPointerArray<TKeyMappingData>* mappings = NULL;
    
    if ( aMode == EPredictiveItuT )
        {
        mappings = &iItutKeyMappings;
        }
    else if ( aMode == EPredictiveQwerty )
        {
        mappings = &iQwertyKeyMappings;
        }
    else if ( aMode == ENonPredictive )
        {
        mappings = NULL;
        }
    else
        {
        mappings = NULL;
        __ASSERT_DEBUG( EFalse, Panic( EPanic_InvalidKeyboardType ) );
        }
    
    return mappings;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::ResolveKeyboardMode
// 
// ----------------------------------------------------------------------------
TKeyboardModes CPcsKeyMap::ResolveKeyboardMode( TKeyboardModes aKbMode ) const
    {
    TKeyboardModes resolvedMode = aKbMode;
    
    // Substitute "default predictive" mode with actual mode
    if ( resolvedMode == EPredictiveDefaultKeyboard )
        {
        resolvedMode = ( iItutIsDefault ? EPredictiveItuT : EPredictiveQwerty );
        }

    // Substitute predictive mode with non-predictive mode if corresponding
    // keyboard mappings are not available.
    if ( ( resolvedMode == EPredictiveItuT && iItutKeyboardType == EPtiKeyboardNone ) ||
         ( resolvedMode == EPredictiveQwerty && iQwertyKeyboardType == EPtiKeyboardNone ) )
        {
        PRINT1( _L("CPcsKeyMap::ResolveKeyboardMode: Mappings for requested mode %d unavailable. Falling back to non-predictive mode!"), aKbMode );
        resolvedMode = ENonPredictive;
        }
    
    return resolvedMode;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::DefaultCharForKey
// 
// ----------------------------------------------------------------------------
TText CPcsKeyMap::DefaultCharForKey( TPtiKey aKey, TKeyboardModes aKbMode ) const
    {
    // On ITU-T, the Pti key code can be directly interpreted as unicode character.
    // Thus, default characters for keys are 1,2,3,4,5,6,7,8,9,0,*,#.
    TText defChar = aKey;
    
    // On QWERTY, using PtiKey values directly is not safe since all PtiKey values are
    // not codepoints of printable Unicode characters.
    // Treating these arbitrary numerical values as Unicode characters could break 
    // the uniqueness of keys when collated comparison is used. Also, converting same
    // data multiple times to "compare format" would then break the data.
    if ( aKbMode == EPredictiveQwerty )
        {
        // Take first mapped character of the key and convert it to upper case.
        TInt index = iQwertyKeys.Find( aKey );
        if ( index != KErrNotFound )
            {
            const RArray<TInt>& mappings = iQwertyKeyMappings[index]->iKeyMappingArray;
            if ( mappings.Count() )
                {
                defChar = User::UpperCase( mappings[0] );
                }
            }
        }
    
    return defChar;
    }
// End of file