phonebookengines/contactsmodel/cntplsql/src/cpcskeymap.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 16 Apr 2010 14:53:18 +0300
changeset 25 76a2435edfd4
parent 24 0ba2181d7c28
child 27 de1630741fbe
permissions -rw-r--r--
Revision: 201011 Kit: 201015

/*
* Copyright (c) 2010 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.
*/

// INCLUDE FILES
#include "cpcskeymap.h"

#if defined(USE_ORBIT_KEYMAP)
#include <QLocale>
#include <hbinputlanguage.h>
#include <hbinputkeymap.h>
#include <hbinputkeymapfactory.h>
#endif // #if defined(USE_ORBIT_KEYMAP)


#if defined(_DEBUG)
#include <e32debug.h> // RDebug

#define PRINT(x)			RDebug::Print(x)
#define PRINT1(x,y)			RDebug::Print(x,y)
#define PRINT2(x,y,z)		RDebug::Print(x,y,z)
#define PRINT3(w,x,y,z)		RDebug::Print(w,x,y,z)
#else // #if defined(_DEBUG)
#define PRINT(x)            
#define PRINT1(x,y)         
#define PRINT2(x,y,z)       
#define PRINT3(w,x,y,z)
#endif // #if defined(_DEBUG)


#define KSpaceChar      ' '

#if defined(USE_ORBIT_KEYMAP)
#define KSeparatorChar  ' '
#endif // #if defined(USE_ORBIT_KEYMAP)

// Separator character stored in predictive search table columns
_LIT(KSeparator, " ");

#if defined(USE_ORBIT_KEYMAP)
// How many keys have mappings (keys 0..9 have mapping)
const TInt KAmountOfKeys = 10;

// The first key of the keyboard has value zero ('1' in the 12-key virtual keypad) 
enum TKeyId
    {
    EKey1 = 0,
    EKey2,
    EKey3,
    EKey4,
    EKey5,
    EKey6,
    EKey7,
    EKey8,
    EKey9,
	EKey0
    };
#endif // #if defined(USE_ORBIT_KEYMAP)

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

// ----------------------------------------------------------------------------
// CPcsKeyMap::NewL
// ----------------------------------------------------------------------------
CPcsKeyMap* CPcsKeyMap::NewL()
	{
    PRINT( _L("Enter CPcsKeyMap::NewL") );
    
    CPcsKeyMap* self = new ( ELeave ) CPcsKeyMap();
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );

    PRINT( _L("End CPcsKeyMap::NewL") );
    return self;
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::~CPcsKeyMap
// ----------------------------------------------------------------------------
CPcsKeyMap::~CPcsKeyMap()
    {
    PRINT( _L("Enter CPcsKeyMap::~CPcsKeyMap") );    
    PRINT( _L("End CPcsKeyMap::~CPcsKeyMap") );
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::GetNumericKeyStringL
// If aPlainConversion is EFalse, supports sub-string searches and space is
// converted to a separator character (not zero).
// ----------------------------------------------------------------------------
HBufC* CPcsKeyMap::GetNumericKeyStringL(const TDesC& aSource,
                                        TBool aPlainConversion) const
    {
    PRINT1( _L("Enter CPcsKeyMap::GetNumericKeyStringL input '%S'"), &aSource );    

    TInt length = aSource.Length();
    HBufC* destination = HBufC::NewL(length);
    TPtr ptr = destination->Des();

    for (TInt i = 0; i < aSource.Length(); ++i)
        {
        if (!aPlainConversion && aSource[i] == KSpaceChar)
            {
            ptr.Append(KSeparator);
            }
        else
            {
#if defined(USE_ORBIT_KEYMAP)
            ptr.Append(KeyForCharacter(aSource[i]));
#else
			TChar a = aSource[i];
			TChar b = a.GetUpperCase();
			ptr.Append(GetNumericValueForChar(b));
#endif
            }
        }

    PRINT1( _L("End CPcsKeyMap::GetNumericKeyStringL result '%S'"), destination );
    return destination;
    }

#if defined(USE_ORBIT_KEYMAP)
// ----------------------------------------------------------------------------
// CPcsKeyMap::Separator
// ----------------------------------------------------------------------------
QChar CPcsKeyMap::Separator() const
    {
    return KSeparatorChar;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::CPcsKeyMap
// Fill QList with empty strings
// ----------------------------------------------------------------------------
CPcsKeyMap::CPcsKeyMap() :
    iKeyMapping() 
	{    
    for (TInt i = 0; i < KAmountOfKeys; ++i)
        {
        iKeyMapping << QString("");
        }
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::ConstructL
// ----------------------------------------------------------------------------
void CPcsKeyMap::ConstructL()
	{
	ContructKeyboardMappingsL();
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::ContructKeyboardMappingsL
// Fetch keymap for every language/country pair present.
// 10.1 only has virtual 12 key ITU-T keyboard
// ----------------------------------------------------------------------------
void CPcsKeyMap::ContructKeyboardMappingsL()
	{
    PRINT( _L("Enter CPcsKeyMap::ContructKeyboardMappingsL") );

#if defined(_DEBUG)
    TInt count(0);
#endif
	QList<HbInputLanguage> languages = AvailableLanguages();

	// Calling HbKeymapFactory::keymap() causes no memory exception after
	// ~20 different language/variant combinations in emulator.
	// In text shell all languages can be handled successfully.
	// In device, already the first call to HbKeymapFactory::keymap()
	// crashes.
	const TInt KMaxLanguages = 30;
	TInt handleMaxLanguages = languages.size();
	if (handleMaxLanguages > KMaxLanguages)
	    {
        handleMaxLanguages = KMaxLanguages;
	    }
	PRINT1( _L("handle %d languages"), handleMaxLanguages ); // test

	for (TInt lang = 0; lang < handleMaxLanguages; ++lang)
		{
        PRINT1( _L("handle language %d"), languages[lang].language() ); // test
		if (IsLanguageSupported(languages[lang].language()))
			{
			PRINT2(_L("Constructing keymap for lang=%d,var=%d"),
				   languages[lang].language(),
				   languages[lang].variant());
#if 0
			const HbKeymap* keymap =
               HbKeymapFactory::instance()->keymap(languages[lang].language(),
												   languages[lang].variant());
#else
			const HbKeymap* keymap = GetKeymap(languages[lang]);
#endif
			if (keymap)
			    {
				for (TInt key = EKey1; key <= EKey0; ++key) 
                    {
                    PRINT1( _L("handle key(enum value %d)"), key ); // test
                    const HbMappedKey* mappedKey = keymap->keyForIndex(HbKeyboardVirtual12Key, key);
                    if (!mappedKey)
                        {
                        PRINT1(_L("Mapped key not found, key(%d)"), KeyIdToNumber(key));
                        User::Leave(KErrNotFound);
                        }
                    // Get both upper and lowercase letters
                    const QString lowerCase = mappedKey->characters(HbModifierNone); // e.g. "abc2.."
                    const QString upperCase = mappedKey->characters(HbModifierShiftPressed); // e.g. "ABC2.."
                    const QString charsForKey = lowerCase + upperCase; 
    
                    // Filter out duplicate characters
                    for (TInt i = charsForKey.length() - 1; i >= 0 ; --i) 
                        {
                        QChar ch = charsForKey[i];
                        // Key '1' is at index 0 in iKeyMapping, key '2' at index 1 etc.
                        // and key '0' at the last index.
                        TInt index = key - EKey1;
                        if (!iKeyMapping[index].contains(ch))
                            {
/*
                            PRINT3(_L("CPcsKeyMap: map key(%d) <-> char='%c'(0x%x)"),
                                   KeyIdToNumber(key),
                                   ch.toAscii(),
                                   ch.toAscii()); */
#if defined(_DEBUG)
                            ++count;
#endif
                            iKeyMapping[index] += ch;
                            }
                        }
                    }
			    }
			else
                {
                PRINT(_L("CPcsKeyMap: keymap not found"));
                }
			}
		}

#if defined(_DEBUG)
    PRINT1( _L("End CPcsKeyMap::ContructKeyboardMappingsL key map has %d chars"), count );
#endif
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::AvailableLanguages
// Put default language at the beginning of the language list, so that
// ContructKeyboardMappingsL handles it first. 
// ----------------------------------------------------------------------------
QList<HbInputLanguage> CPcsKeyMap::AvailableLanguages() const
    {
    PRINT( _L("Enter CPcsKeyMap::AvailableLanguages") );

    QLocale locale;
    QLocale::Language currentLanguage = locale.language();
    if (!IsLanguageSupported(currentLanguage))
        {
        PRINT( _L("current lang not supported, use english") ); //test
        currentLanguage = QLocale::English;
        }
    HbInputLanguage defaultLanguage(currentLanguage);

    QList<HbInputLanguage> languages = HbKeymapFactory::availableLanguages();
    if (languages.contains(defaultLanguage))
        {
        PRINT( _L("remove default lang") ); //test
        languages.removeOne(defaultLanguage);
        }
    PRINT( _L("insert default lang as first lang") ); //test
    languages.insert(0, defaultLanguage);

    PRINT1( _L("End CPcsKeyMap::AvailableLanguages found %d languages"),
            languages.count() );
    return languages;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::IsLanguageSupported
// ----------------------------------------------------------------------------
TBool CPcsKeyMap::IsLanguageSupported(QLocale::Language aLanguage) const
	{
	return (aLanguage != QLocale::Japanese && aLanguage != QLocale::Chinese);
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::KeyForCharacter
// Loop all QStrings of iKeyMapping to find one containing the character.
// If the character is not mapped, use the character itself.
// ----------------------------------------------------------------------------
TChar CPcsKeyMap::KeyForCharacter(const TChar& aChar) const
    {
    TUint charValue(aChar);
    QChar ch(charValue);
    
    for (TInt index = 0; index < KAmountOfKeys; ++index)
        {
        if (iKeyMapping[index].contains(ch))
            {
            return ArrayIndexToNumberChar(index);
            }
        }

    PRINT2( _L("CPcsKeyMap::KeyForCharacter no mapping for char '%c' (0x%x)"),
            (TUint)aChar, (TUint)aChar ); // test
    return aChar;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::KeyIdToNumber
// Map Orbit API's key id to the number that the key results when pressed. 
// ----------------------------------------------------------------------------
TInt CPcsKeyMap::KeyIdToNumber(TInt aKeyId) const
	{
	switch (aKeyId)
		{
		case EKey1:
		case EKey2:
		case EKey3:
		case EKey4:
		case EKey5:
		case EKey6:
		case EKey7:
		case EKey8:
		case EKey9:
			return aKeyId + 1;
		case EKey0:
			return 0;
		default:
		    PRINT1( _L("CPcsKeyMap::KeyIdToNumber invalid index %d"), aKeyId );
			User::Panic(_L("CPcsKeyMap::KeyIdToNumber"), KErrArgument);
			return 0;
		}
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::ArrayIndexToNumberChar
// Map index of iKeyMapping list, to the number char that the mapping is for.
// ----------------------------------------------------------------------------
TChar CPcsKeyMap::ArrayIndexToNumberChar(TInt aArrayIndex) const
	{
	__ASSERT_DEBUG(aArrayIndex < KAmountOfKeys,
				   User::Panic(_L("CPcsKeyMap::ArrayIndexToNumberChar"),
				   KErrOverflow));
	if (aArrayIndex == KAmountOfKeys - 1)
		{
		return '0';
		}
	return aArrayIndex + '1';
	}

const HbKeymap* CPcsKeyMap::GetKeymap(HbInputLanguage aLanguage) const
    {
    PRINT(_L("CPcsKeyMap::GetKeymap"));

    const HbKeymap* keymap(NULL);
    TInt err(KErrNone);
    // Catches C++ exception and converts it to Symbian error code
    QT_TRYCATCH_ERROR(err, keymap = HbKeymapFactory::instance()->keymap(aLanguage.language(),
                                                                        aLanguage.variant()));
    if (err != KErrNone)
        {
        // In emulator, trying to get the 20th keymap results KErrNoMemory 
        PRINT1(_L("factory->keymap threw exception, err=%d"), err);
        return NULL;
        }
    PRINT(_L("CPcsKeyMap::GetKeymap got keymap"));
    return keymap;
    }
#else // #if defined(USE_ORBIT_KEYMAP)
CPcsKeyMap::CPcsKeyMap()
	{
	}

void CPcsKeyMap::ConstructL()
	{   
	}

TChar CPcsKeyMap::GetNumericValueForChar(TChar input ) const
    {
	TChar ret = '0';
    switch (input)
        {
        case 'A': 
        case 'B': 
        case 'C':
               ret = '2';
               break;
        case 'D': 
        case 'E':
        case 'F':
            ret = '3';
            break;
            
        case 'G': 
        case 'H':
        case 'I':
            ret = '4';
            break;

        case 'J': 
        case 'K': 
        case 'L':
            ret = '5';
            break;

        case 'M': 
        case 'N': 
        case 'O':
            ret = '6';
            break;
      
        case 'P': 
        case 'Q':
        case 'R': 
        case 'S':
            ret = '7';
            break;

        case 'T':
        case 'U': 
        case 'V':
            ret = '8';
            break;

        case 'W':
        case 'X':
        case 'Y': 
        case 'Z':
            ret = '9';
            break;
            
		case ' ':
			ret = '0';
			break;

		default: // Other chars, e.g. numbers
			ret = input;
        }
    return ret;    
    }
#endif // #if defined(USE_ORBIT_KEYMAP)

// End of file