javauis/lcdui_akn/lcdui/src/CMIDUtils.cpp
branchRCL_3
changeset 19 04becd199f91
child 25 9ac0a0a7da70
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/lcdui_akn/lcdui/src/CMIDUtils.cpp	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,1596 @@
+/*
+* Copyright (c) 2002-2006 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:  Keymappings etc. customized for Series 60.
+*
+*/
+
+
+// INCLUDE FILES
+#include <eikenv.h>
+#include <eikappui.h>
+#include <coecntrl.h>
+#include <coeccntx.h>
+#include <coecobs.h>
+#include <bassnd.h>
+#include <coesndpy.h>
+#include <hal.h>
+#include <lcdui.rsg>
+#include <barsread.h>
+
+#include <aknappui.h>
+#include <aknsoundsystem.h>
+#include <avkon.hrh> // for Alert Sounds
+#include <hwrmlight.h> // backlight
+#include <hwrmvibra.h> // vibra
+// for layout data in BestImageSize function
+#include <aknlayoutscalable_avkon.cdl.h> // for layout data
+// API used Color function - mapping Java color type to Avkon-skinned color
+#include <AknsUtils.h>
+
+// CMIDKeyDecoder API in funcions related to keys
+#include "CMIDKeyDecoder.h"
+#include "CMIDUtils.h"
+#include "CMIDUIManager.h"
+
+#ifdef RD_SCALABLE_UI_V2
+#include <AknUtils.h>
+#endif // RD_SCALABLE_UI_V2
+
+#include <e32property.h>
+#include <AvkonInternalCRKeys.h>
+#include <centralrepository.h>
+#include <AknFepInternalCRKeys.h>
+
+#ifdef RD_INTELLIGENT_TEXT_INPUT
+#include <PtiEngine.h>
+#endif //RD_INTELLIGENT_TEXT_INPUT
+
+
+// macros definitions for outputing logs
+#include <j2me/jdebug.h>
+
+// LOCAL CONSTANTS AND MACROS
+
+/**
+ *Info messages for Wins Flashbacklight and Vibrate
+ *For development purpose only, not localized
+ */
+#if defined(__WINS__)
+_LIT(KMsgFlashBacklight,"Flash count:");
+_LIT(KMsgVibrate,"Vibrating for ");
+#endif
+
+// line feed, carriage return, line separator, paragraph separator
+_LIT(KSeparators, "\x000a\x000d\x2028\x2029");
+
+// keyboard types
+_LIT(KKeyboardNone,            "None");
+_LIT(KKeyboardPhoneKeypad,     "PhoneKeypad");
+_LIT(KKeyboardFullKeyboard,    "FullKeyboard");
+_LIT(KKeyboardLimited4x10,     "LimitedKeyboard4x10");
+_LIT(KKeyboardLimited3x11,     "LimitedKeyboard3x11");
+_LIT(KKeyboardHalfKeyboard,    "HalfKeyboard");
+_LIT(KKeyboardCustom,          "Custom");
+_LIT(KKeyboardUnknown,         "Unknown");
+
+
+// constants for color bits shifting (for creation of 0x00RRGGBB color value)
+const TInt KRedBitsShift = 16;
+const TInt KGreenBitsShift = 8;
+const TInt KBlueBitsShift = 0;
+
+// constant for result size used by PTI Engine for mapping keys, this value is
+// based e.g. on PtiXt9CandidateList implementation
+
+#ifdef RD_INTELLIGENT_TEXT_INPUT
+const TInt KPTIEngineResultSize = 32;
+#endif // RD_INTELLIGENT_TEXT_INPUT
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+//
+//
+// class MMIDUtils
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+MMIDUtils* CMIDUtils::NewL(MMIDEnv& aEnv, CMIDUIManager* aUIManager)
+{
+    CMIDUtils* utils = new(ELeave) CMIDUtils(aEnv, aUIManager);
+    CleanupStack::PushL(utils);
+    utils->ConstructL();
+    CleanupStack::Pop(utils);
+    return utils;
+}
+
+/**
+ * CAknKeySoundSystem is use to play sounds,
+ * emulator implementation, which does not support
+ * this feature.
+ */
+#if defined(__WINSCW__)
+TBool CMIDUtils::PlaySound(TInt /*aSoundType*/)
+{
+    return EFalse;
+}
+#else // __WINSCW__
+
+/**
+ * CAknKeySoundSystem is use to play sounds
+ */
+TBool CMIDUtils::PlaySound(TInt aSoundType)
+{
+    TInt toneType = -1;
+    switch (aSoundType)
+    {
+    case MMIDAlert::EAlarm:
+        toneType = (TInt) EAvkonSIDInformationTone;
+        break;
+    case MMIDAlert::EConfirmation:
+        toneType = (TInt) EAvkonSIDConfirmationTone;
+        break;
+    case MMIDAlert::EError:
+        toneType = (TInt) EAvkonSIDErrorTone;
+        break;
+    case MMIDAlert::EWarning:
+        toneType = (TInt) EAvkonSIDWarningTone;
+        break;
+    case MMIDAlert::EInfo:
+        toneType = (TInt) EAvkonSIDInformationTone;
+        break;
+    case MMIDAlert::ENone: // No Alerttype set
+    default:
+        toneType = (TInt) EAvkonSIDNoSound;
+        break;
+    }
+
+    CAknKeySoundSystem* soundSystem = iAvkonAppUi->KeySounds();
+    if (toneType  != -1)
+    {
+        soundSystem->PlaySound(toneType);
+    }
+    return ETrue;
+}
+#endif // __WINSCW__
+
+/**
+ * Determines if a key code should be sent to Canvas.keyPressed(int keyCode)
+ */
+TBool CMIDUtils::IsJavaKey(TInt aScanCode)
+{
+    ASSERT(iKeyDecoder);
+    return iKeyDecoder->IsJavaKey(aScanCode);
+}
+
+/**
+ * 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 CMIDUtils::MapNonUnicodeKey(TUint aScanCode)
+{
+    ASSERT(iKeyDecoder);
+    return iKeyDecoder->MapNonUnicodeKey(aScanCode);
+}
+
+/**
+ * Gets a key code that corresponds to the specified game action on the device.
+ *
+ * Returns zero if aGameAction is not a valid game action.
+ *
+ * @see CMIDKeyDecoder::GetKeyCode()
+ */
+TInt CMIDUtils::GetKeyCode(TInt aGameAction)
+{
+    ASSERT(iKeyDecoder);
+    return iKeyDecoder->GetKeyCode(aGameAction);
+}
+
+/**
+ * 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.
+ * @see CMIDKeyDecoder::GetKeyName()
+ */
+void CMIDUtils::GetKeyName(TDes& aText,TInt aKeyCode)
+{
+    ASSERT(iKeyDecoder);
+    return iKeyDecoder->GetKeyName(aText, aKeyCode);
+}
+
+/**
+* Gets the game action associated with the given key code of the device.
+*
+* Return zero if no game action is associated with this key code.
+*
+* @see CMIDKeyDecoder::GameAction()
+*/
+TInt CMIDUtils::GetGameAction(TInt aKeyCode)
+{
+    ASSERT(iKeyDecoder);
+    return iKeyDecoder->GameAction(aKeyCode);
+}
+
+void CMIDUtils::MapJavaToETextChars(HBufC* aText,TBool aSupportLineBreaks)
+{
+    TPtr text = aText->Des();
+    TInt pos = text.Length();
+    for (; pos>0;)
+    {
+        TText& ch=(text)[--pos];
+        switch (ch)
+        {
+        case '\n':
+            //From 3.0m onwards: If line breaks are not supported, returns ESpace instead of ETabCharacter
+            ch = (TText)(aSupportLineBreaks ? CEditableText::EParagraphDelimiter : CEditableText::ESpace);
+            break;
+        case '\f':
+            //From 3.0m onwards: If line breaks are not supported, returns ESpace instead of ETabCharacter
+            ch = (TText)(aSupportLineBreaks ? CEditableText::EPageBreak : CEditableText::ESpace);
+            break;
+        case '\t':
+            ch = CEditableText::ETabCharacter;
+            break;
+        }
+    }
+}
+
+void CMIDUtils::MapETextToJavaChars(HBufC* aText)
+{
+    if (!aText)
+        return;
+    TPtr text = aText->Des();
+    TInt pos = text.Length();
+    for (; pos>0;)
+    {
+        TText& ch=(text)[--pos];
+        switch (ch)
+        {
+        case CEditableText::EParagraphDelimiter:
+            ch = '\n';
+            break;
+        case CEditableText::EPageBreak:
+            ch = '\f';
+            break;
+        case CEditableText::ETabCharacter:
+            ch = '\t';
+            break;
+        }
+    }
+}
+
+/**
+ * Looks for first character which indicates text direction such as Arabic character meaning right-to-left.
+ * (similar code can be found in lcdgr)
+ */
+TBool CMIDUtils::IsStronglyRightToLeft(HBufC* aText)
+{
+    TPtr text = aText->Des();
+    TInt pos;
+    TInt len = text.Length();
+    for (pos = 0; pos < len; pos++)
+    {
+        TChar ch((text)[pos]);
+        TChar::TCharInfo info;
+        ch.GetInfo(info);
+        switch (info.iBdCategory)
+        {
+        case TChar::ERightToLeft:
+        case TChar::ERightToLeftArabic:
+        case TChar::ERightToLeftEmbedding:
+        case TChar::ERightToLeftOverride:
+        case TChar::EArabicNumber:
+            return true;
+        case TChar::ELeftToRight:
+            return false;
+        default:
+            ;
+        }
+    }
+    return false;
+}
+
+/**
+ * Reverses order of contents of array.
+ */
+void CMIDUtils::Reverse(HBufC* aText)
+{
+    TPtr text = aText->Des();
+    TInt s = 0;
+    TInt e = text.Length() - 1;
+    while (s < e)
+    {
+        TText t = text[s];
+        text[s] = text[e];
+        text[e] = t;
+        ++s;
+        --e;
+    }
+}
+
+/** Some key events should be ignored, for example when opening or closing a device. */
+TBool CMIDUtils::IgnoreKeyEvent(TUint aKeyEvent)
+{
+    return (aKeyEvent == EKeyGripOpen)   ||
+           (aKeyEvent == EKeyGripClose)  ||
+           (aKeyEvent == EKeyTwistOpen)  ||
+           (aKeyEvent == EKeyTwistClose) ||
+           (aKeyEvent == EKeyFlipOpen)   ||
+           (aKeyEvent == EKeyFlipClose)  ||
+           (aKeyEvent == EKeyQwertyOn)   ||
+           (aKeyEvent == EKeyQwertyOff);
+}
+
+
+/** Creates an identical copy of the given bitmap. This utility function is used instead
+of MMIDBitmapImage::CreateColorBitmapL() because this latter looses transparency information
+when the display mode is EColor16MA (it blits on a white bitmap...).
+*/
+CFbsBitmap* CMIDUtils::CopyBitmapL(CFbsBitmap* aSource)
+{
+    CFbsBitmap* target = NULL;
+
+    if (aSource)
+    {
+        target = new(ELeave) CFbsBitmap();
+        target->Create(aSource->SizeInPixels(), aSource->DisplayMode());
+
+        //if there is no memory for new bitmap, target has null adress pointer
+        //and calling Mem::Copy causes a panic.
+        //So if target->DataAdress() returns null pointer,
+        //function leave with KErrNoMemory -> java.lang.OutOfMemoryError is thrown
+        if (!target->DataAddress())
+        {
+            User::Leave(KErrNoMemory);
+        }
+
+        TInt nBytes = aSource->SizeInPixels().iHeight *
+                      aSource->ScanLineLength(aSource->SizeInPixels().iWidth, aSource->DisplayMode());
+
+        target->LockHeap();
+        Mem::Copy(target->DataAddress(), aSource->DataAddress(), nBytes);
+        target->UnlockHeap();
+    }
+
+    return target;
+}
+
+TBool CMIDUtils::IsLineSeparator(const TText aChar)
+{
+    return (KSeparators().Locate(aChar) != KErrNotFound);
+}
+
+TBool CMIDUtils::HasPointerEvents()
+{
+    return (HasPen() || HasMouse());
+}
+
+TBool CMIDUtils::HasPointerMotionEvents()
+{
+    return (HasPen() || HasMouse());
+}
+
+TBool CMIDUtils::HasRepeatEvents()
+{
+    return ETrue;
+}
+
+TBool CMIDUtils::HasPen()
+{
+#ifdef RD_SCALABLE_UI_V2
+    return AknLayoutUtils::PenEnabled();
+#else
+    TInt hasPen = EFalse;
+    return hasPen;
+#endif // RD_SCALABLE_UI_V2
+}
+
+TBool CMIDUtils::HasMouse()
+{
+    TInt hasMouse = EFalse;
+    return hasMouse;
+}
+
+TSize CMIDUtils::BestImageSize(TImageType aImageType) const
+{
+    TAknWindowLineLayout lineLayout;
+
+    switch (aImageType)
+    {
+    case EListImage:
+        lineLayout = AknLayoutScalable_Avkon::list_single_large_graphic_pane_g1(0).LayoutLine();
+        break;
+    case EChoiceImage:
+        lineLayout = AknLayoutScalable_Avkon::list_single_2graphic_pane_g1_cp4().LayoutLine();
+        break;
+    case EAlertImage:
+        lineLayout = AknLayoutScalable_Avkon::popup_midp_note_alarm_window_g1(0).LayoutLine();
+        break;
+    default:
+        return TSize();
+    }
+    return TSize(lineLayout.iW, lineLayout.iH);
+}
+
+
+/**
+ * Requests a flashing effect for the device's backlight
+ * Returns false as the emulator does not support this feature.
+ */
+#if defined(__WINSCW__)
+
+TBool CMIDUtils::FlashBacklightL(const TTimeIntervalMicroSeconds32& /*aDuration*/)
+{
+    return EFalse;
+}
+
+#else // __WINSCW__
+/**
+ * Requests a flashing effect for the device's backlight
+ * Must return true if the backlight can be controlled by the application
+ */
+TBool CMIDUtils::FlashBacklightL(const TTimeIntervalMicroSeconds32& aDuration)
+{
+    if (!iLight)
+    {
+        iLight = CHWRMLight::NewL();
+    }
+    // SupportedTargets() returns the supported targets as a bitmap.
+    if ((iLight->SupportedTargets() &
+            CHWRMLight::EPrimaryDisplayAndKeyboard) !=
+            CHWRMLight::EPrimaryDisplayAndKeyboard)
+    {
+        return EFalse;
+    }
+
+    TInt duration = aDuration.Int() / 1000;
+    if (!duration)
+    {
+        // 0 would be infinite
+        duration = 1;
+    }
+    iLight->LightBlinkL(CHWRMLight::EPrimaryDisplayAndKeyboard,
+                        duration);
+    return ETrue;
+}
+#endif // __WINSCW__
+
+
+/**
+ * There is no API for vibrate. Left to be customised according to each device
+ * Printing InfoMsg for the user for the duration given to vibrate
+ * Returns false in emulator builds as it does not support this feature.
+ */
+#if defined(__WINSCW__)
+TBool CMIDUtils::Vibrate(const TTimeIntervalMicroSeconds32& /*aDuration*/)
+{
+    return EFalse;
+}
+#else // __WINSCW__
+
+/**
+ * There is no API for vibrate. Left to be customised according to each device
+ * Printing InfoMsg for the user for the duration given to vibrate
+ * Must return true if the vibrator can be controlled by the application
+ */
+TBool CMIDUtils::Vibrate(const TTimeIntervalMicroSeconds32& aDuration)
+{
+    TInt duration = aDuration.Int() / 1000; // convert micro to milli
+
+    // as this method can't leave, and only returns a boolean, we must
+    // return false if anything goes wrong.
+
+    if (!iVibra)
+    {
+        TRAPD(err1, iVibra = CHWRMVibra::NewL());
+        if (err1 != KErrNone)
+        {
+            return EFalse;
+        }
+    }
+
+    TInt err2 = KErrNone;
+
+    if (duration)
+    {
+        TRAP(err2, iVibra->StartVibraL(duration));
+    }
+    else
+    {
+        TRAP(err2, iVibra->StopVibraL());
+    }
+
+    if (err2 == KErrNone)
+    {
+        return ETrue;
+    }
+    else
+    {
+        return EFalse;
+    }
+}
+#endif // __WINSCW__
+
+/**
+ * Mapping Java color type to Avkon-skinned color.
+ */
+TInt CMIDUtils::Color(TColorType aColorSpecifier)
+{
+    MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+    TRgb rgbColor = 0;
+    TInt result = KErrNone;
+
+    // get skinned color
+    switch (aColorSpecifier)
+    {
+    case EColorBackground:
+        result = AknsUtils::GetCachedColor(skin, rgbColor,
+                                           KAknsIIDQsnOtherColors, EAknsCIQsnOtherColorsCG10);
+        break;
+    case EColorForeground:
+        result = AknsUtils::GetCachedColor(skin, rgbColor,
+                                           KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG6);
+        break;
+    case EColorHighlightedBackground:
+        result = AknsUtils::GetCachedColor(skin, rgbColor,
+                                           KAknsIIDQsnOtherColors, EAknsCIQsnOtherColorsCG14);
+        break;
+    case EColorHighlightedForeground:
+        result = AknsUtils::GetCachedColor(skin, rgbColor,
+                                           KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG10);
+        break;
+    case EColorBorder:
+        result = AknsUtils::GetCachedColor(skin, rgbColor,
+                                           KAknsIIDQsnOtherColors, EAknsCIQsnOtherColorsCG12);
+        break;
+    case EColorHighlightedBorder:
+        result = AknsUtils::GetCachedColor(skin, rgbColor,
+                                           KAknsIIDQsnOtherColors, EAknsCIQsnOtherColorsCG15);
+        break;
+    default:
+        // wrong argument
+        return KErrArgument;
+    }
+
+    // check result
+    if (result == KErrNone)
+    {
+        return rgbColor.Red() << KRedBitsShift |
+               rgbColor.Green() << KGreenBitsShift |
+               rgbColor.Blue() << KBlueBitsShift;
+    }
+    else
+    {
+        // return black in case of some skinning related problem
+        return 0;
+    }
+}
+
+MMIDUtils::TGraphicsType CMIDUtils::BorderStyle(TBool aHighlighted)
+{
+    return (aHighlighted) ? ESolid : EDotted;
+}
+
+/**
+ * Return FontSpec for given Font Specifier, Font Spec is chosen for each specifier from exisiting.
+ */
+SFontSpec CMIDUtils::FontSpecifierSpecs(MMIDFont::TFontSpecifier aSpecifier)
+{
+    SFontSpec fontSpec;
+
+    if (aSpecifier == MMIDFont::EInputText)
+    {
+        fontSpec.iFace = MMIDFont::EProportional;
+        fontSpec.iStyle = MMIDFont::EBold;
+        fontSpec.iSize = MMIDFont::EMedium;
+    }
+    else
+    {
+        fontSpec.iFace = MMIDFont::EProportional;
+        fontSpec.iStyle = MMIDFont::EPlain;
+        fontSpec.iSize = MMIDFont::ESmall;
+    }
+    return fontSpec;
+}
+
+/**
+ * Function fills aText descriptor with name of actual keyboard layout.
+ * Keyboard layout is stored in central repository. Obtained TInt value
+ * is mapped to descriptor:
+ * 0 No Keyboard            -> "None"
+ * 1 Keyboard with 12 key   -> "PhoneKeypad"
+ * 2 QWERTY 4x12 layout     -> "FullKeyboard"
+ * 3 QWERTY 4x10 layout     -> "LimitedKeyboard4x10"
+ * 4 QWERTY 3 x 11 layout   -> "LimitedKeyboard3x11"
+ * 5 Half QWERTY            -> "HalfKeyboard"
+ * 6 Custom QWERTY          -> "Custom"
+ * In case of undefined value, aText is empty.
+ */
+void CMIDUtils::GetKeyboardTypeName(TDes* aText)
+{
+    TInt keyboardType = 0;
+    RProperty::Get(KCRUidAvkon, KAknKeyBoardLayout, keyboardType);
+
+    aText->Zero(); //empty the descriptor
+    switch (keyboardType)
+    {
+    case ENoKeyboard: //No Keyboard
+        aText->Append(KKeyboardNone);
+        break;
+    case EKeyboardWith12Key: //Keyboard with 12 key
+        aText->Append(KKeyboardPhoneKeypad);
+        break;
+    case EQWERTY4x12Layout: //QWERTY 4x12 layout
+        aText->Append(KKeyboardFullKeyboard);
+        break;
+    case EQWERTY4x10Layout: //QWERTY 4x10 layout
+        aText->Append(KKeyboardLimited4x10);
+        break;
+    case EQWERTY3x11Layout: //QWERTY 3 x 11 layout
+        aText->Append(KKeyboardLimited3x11);
+        break;
+    case EHalfQWERTY: //Half QWERTY
+        aText->Append(KKeyboardHalfKeyboard);
+        break;
+    case ECustomQWERTY: //Custom QWERTY
+        aText->Append(KKeyboardCustom);
+        break;
+    default:
+        aText->Append(KKeyboardUnknown);
+    }
+}
+
+/**
+ * Function sets the scan code of the latest key event.
+ */
+void CMIDUtils::SetLastKeyEvent(const TKeyEvent& aEvent)
+{
+    iLastScanCode = aEvent.iScanCode;
+    iModifier = aEvent.iModifiers;
+}
+
+/**
+ * Function returns the scan code of the latest key event.
+ */
+TInt CMIDUtils::GetKeyScanCode()
+{
+    return iLastScanCode;
+}
+
+/**
+ * Function returns modifier value of the latest key event.
+ */
+TInt CMIDUtils::GetKeyModifier()
+{
+    return iModifier;
+}
+
+void CMIDUtils::MappingDataForKey(TKeyEvent& aEvent, TEventCode aType)
+{
+    if (!iQwertyMode)
+    {
+        return;
+    }
+
+    TBool issticky = iStickyHandler.HandleKey(aEvent, aType);
+
+    TUint modifiers = iStickyHandler.Modifiers();
+
+    if (!issticky && modifiers == 0)
+    {
+        modifiers = aEvent.iModifiers;
+    }
+    if (!issticky && aType == EEventKeyUp)
+    {
+        iStickyHandler.Reset();
+    }
+
+
+#ifdef RD_INTELLIGENT_TEXT_INPUT
+    TPtiTextCase textCase = EPtiCaseLower;
+
+    if (modifiers & EModifierShift)
+    {
+        textCase = EPtiCaseUpper;
+    }
+    if (modifiers & EModifierRightFunc)
+    {//EModifierRightFunc in Fn key
+        textCase = EPtiCaseFnLower;
+    }
+    else if (modifiers & EModifierLeftFunc)
+    {
+        textCase = EPtiCaseChrLower;
+    }
+
+    //If Control key is held, don't use PtiEngine to map keyEvent.iCode
+    if (modifiers & EModifierLeftCtrl ||
+            modifiers & EModifierRightCtrl)
+    {
+        iStickyHandler.Reset();
+        return;
+    }
+
+    TBuf<KPTIEngineResultSize> mapData;
+
+    iPtiEngine->MappingDataForKey(
+        (TPtiKey)aEvent.iScanCode, mapData, textCase);
+
+    if (mapData.Length() > 0)
+    {
+        // set event code to the first mapped
+        aEvent.iCode = mapData[0];
+    }
+#endif // RD_INTELLIGENT_TEXT_INPUT
+
+}
+
+void CMIDUtils::UpdatePTIEngineStatusL()
+{
+
+#ifdef RD_INTELLIGENT_TEXT_INPUT
+
+    RProperty::Get(KCRUidAvkon, KAknQwertyInputModeActive, iQwertyMode);
+
+    // keyboard layout default value: 0 - No Keyboard
+    TInt keyboardLayout = 0;
+    // Read keyboard layout from central repository
+    RProperty::Get(KCRUidAvkon, KAknKeyBoardLayout, keyboardLayout);
+
+    TPtiEngineInputMode mode = EPtiEngineInputModeNone;
+    switch (keyboardLayout)
+    {
+    case EPtiKeyboard12Key:
+        mode = EPtiEngineMultitapping;
+#ifdef RD_JAVA_S60_RELEASE_5_0_IAD
+        CallToJavaPtiVariationL(keyboardLayout);
+#else
+        iPtiEngine->SetKeyboardType((TPtiKeyboardType)keyboardLayout);
+#endif
+        break;
+    case EPtiKeyboardQwerty4x12:
+    case EPtiKeyboardQwerty4x10:
+    case EPtiKeyboardQwerty3x11:
+#ifdef RD_JAVA_S60_RELEASE_5_0_IAD
+        CallToJavaPtiVariationL(keyboardLayout);
+#else
+        iPtiEngine->SetKeyboardType((TPtiKeyboardType)keyboardLayout);
+#endif
+        mode = EPtiEngineQwerty;
+        break;
+    case EPtiKeyboardHalfQwerty:
+#ifdef RD_JAVA_S60_RELEASE_5_0_IAD
+        CallToJavaPtiVariationL(keyboardLayout);
+#else
+        iPtiEngine->SetKeyboardType((TPtiKeyboardType)keyboardLayout);
+#endif
+        mode = EPtiEngineHalfQwerty;
+        break;
+    default:
+        break;
+    }
+    // input language default value: 0 (automatic)
+    TInt inputLang = 0;
+    if (iRepository)
+    {
+        TInt ret = iRepository->Get(KAknFepInputTxtLang, inputLang);
+    }
+
+    // Change input language to western, if input language is Chinese
+    // ELangPrcChinese      - 31
+    // ELangTaiwanChinese   - 29
+    // ELangHongKongChinese - 30
+    if (iQwertyMode)
+    {
+        if (inputLang == ELangPrcChinese ||
+                inputLang == ELangTaiwanChinese ||
+                inputLang == ELangHongKongChinese)
+        {
+            inputLang = ELangEnglish;
+        }
+    }
+    TRAPD(err, iPtiEngine->ActivateLanguageL(inputLang, mode));
+    if (KErrNone != err)
+    {
+        DEBUG_INT("CMIDUtils::UpdatePTIEngineStatusL - ActivateLanguageL leaved with error = %d", err);
+        return;
+    }
+
+
+#endif // RD_INTELLIGENT_TEXT_INPUT
+
+}
+
+
+void CMIDUtils::HandleResourceChangedL()
+{
+    UpdatePTIEngineStatusL();
+}
+
+void CMIDUtils::HandleForegroundL(TBool aForeground)
+{
+    if (aForeground)
+    {
+        UpdatePTIEngineStatusL();
+    }
+}
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+CMIDUtils::CMIDUtils(MMIDEnv& aEnv, CMIDUIManager* aUIManager)
+        : iEnv(&aEnv)
+        , iUIManager(aUIManager)
+        , iScalingData()
+        , iQwertyMode(EFalse)
+        , iStickyKey(0)
+        , iLastScanCode(0)
+        , iModifier(0)
+{}
+
+CMIDUtils::~CMIDUtils()
+{
+    delete iLight;
+    delete iVibra;
+
+#ifdef RD_INTELLIGENT_TEXT_INPUT
+
+#ifdef RD_JAVA_S60_RELEASE_5_0_IAD
+    iPtiSupportLib.Close();
+#endif //RD_JAVA_S60_RELEASE_5_0_IAD
+
+    delete iPtiEngine;
+    iPtiEngine = NULL;
+
+    delete iRepository;
+    iRepository = NULL;
+#endif //RD_INTELLIGENT_TEXT_INPUT
+
+}
+
+#ifdef RD_INTELLIGENT_TEXT_INPUT
+#ifdef RD_JAVA_S60_RELEASE_5_0_IAD
+void CMIDUtils::CallToJavaPtiVariationL(TInt aType)
+{
+    if (!iPtiSupportLib.Handle())
+    {
+        _LIT(KLibName, "javaptivariation.dll");
+        iPtiSupportLib.Load(KLibName);
+    }
+
+    if (iPtiSupportLib.Handle())
+    {
+        TJavaPtiVariationLibEntry libEntryL = (TJavaPtiVariationLibEntry)iPtiSupportLib.Lookup(1);
+        libEntryL(*iPtiEngine, aType);
+    }
+}
+#endif //   RD_JAVA_S60_RELEASE_5_0_IAD
+#endif // RD_INTELLIGENT_TEXT_INPUT 
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CMIDUtils::ConstructL()
+{
+    ASSERT(iUIManager);
+    iKeyDecoder = iUIManager->OpenKeyDecoderL();
+    iMenuHandler = iUIManager->GetMenuHandler();
+
+#ifdef RD_INTELLIGENT_TEXT_INPUT
+    iPtiEngine = CPtiEngine::NewL(ETrue);
+    iRepository = CRepository::NewL(KCRUidAknFep);
+    UpdatePTIEngineStatusL();
+#endif // RD_INTELLIGENT_TEXT_INPUT
+
+
+}
+
+TInt CMIDUtils::DoScaling(TInt aNonScaled, TInt aDirection)
+{
+    DEBUG("TInt CMIDUtils::DoScaling(TInt aNonScaled, TInt aDirection)");
+
+    // initial value of return structure
+    TInt scaled = aNonScaled;
+
+    // get of all needed values for scaling
+    TScalingData data = GetScalingData();
+
+    // scaling in entered direction
+    // no scaling if direction is not valid
+    if (aDirection == EHorizontal)
+    {
+        scaled *= data.iRatioX;
+    }
+    else if (aDirection == EVertical)
+    {
+        scaled *= data.iRatioY;
+    }
+
+    DEBUG_INT("DoScaling scaled %d", scaled);
+
+    // return of scaled value
+    return scaled;
+}
+
+TPoint CMIDUtils::DoScaling(TPoint aNonScaled)
+{
+    DEBUG("TPoint CMIDUtils::DoScaling(TPoint aNonScaled)");
+
+    // initial value of return structure
+    TPoint scaled = aNonScaled;
+
+    // get of all needed values for scaling
+    TScalingData data = GetScalingData();
+
+    // scaling of point
+    scaled.iX *= data.iRatioX;
+    scaled.iY *= data.iRatioY;
+
+    DEBUG_INT2("DoScaling scaled %d %d", scaled.iX, scaled.iY);
+
+    // return of scaled value
+    return scaled;
+}
+
+TPoint CMIDUtils::DoScalingAndPositioning(TPoint aNonScaled)
+{
+    DEBUG("TPoint CMIDUtils::DoScalingAndPositioning(TPoint aNonScaled)");
+
+    // initial value of return structure
+    TPoint scaled = aNonScaled;
+
+    // get of all needed values for scaling
+    TScalingData data = GetScalingData();
+
+    // scaling of point
+    scaled.iX *= data.iRatioX;
+    scaled.iY *= data.iRatioY;
+
+    // get of canvas origin
+    TSize subtract = data.iScreenSize - data.iCanvasSize;
+    TPoint canvasOrigin = TPoint(subtract.iWidth / 2, subtract.iHeight / 2);
+
+    // move according to canvas origin
+    scaled += canvasOrigin;
+
+    DEBUG_INT2("DoScalingAndPositioning scaled %d %d", scaled.iX, scaled.iY);
+
+    // return of scaled value
+    return scaled;
+}
+
+TRect CMIDUtils::DoScaling(TRect aNonScaled)
+{
+    DEBUG("TRect CMIDUtils::DoScaling(TRect aNonScaled)");
+
+    // initial value of return structure
+    TRect scaled = aNonScaled;
+
+    // get of all needed values for scaling
+    TScalingData data= GetScalingData();
+
+    // scaling of rect
+    scaled.iBr.iX *= data.iRatioX;
+    scaled.iBr.iY *= data.iRatioY;
+    scaled.iTl.iX *= data.iRatioX;
+    scaled.iTl.iY *= data.iRatioY;
+
+    DEBUG_INT4("DoScaling scaled %d %d", scaled.iBr.iX, scaled.iBr.iY, scaled.iTl.iX, scaled.iTl.iY);
+
+    // return of scaled value
+    return scaled;
+}
+
+TRect CMIDUtils::DoScalingAndPositioning(TRect aNonScaled)
+{
+    DEBUG("TRect CMIDUtils::DoScalingAndPositioning(TRect aNonScaled)");
+
+    // initial value of return structure
+    TRect scaled = aNonScaled;
+
+    // get of all needed values for scaling
+    TScalingData data = GetScalingData();
+
+    // scaling of rect
+    scaled.iBr.iX *= data.iRatioX;
+    scaled.iBr.iY *= data.iRatioY;
+    scaled.iTl.iX *= data.iRatioX;
+    scaled.iTl.iY *= data.iRatioY;
+
+    // get of canvas origin
+    TSize subtract = data.iScreenSize - data.iCanvasSize;
+    TPoint canvasOrigin = TPoint(subtract.iWidth / 2, subtract.iHeight / 2);
+
+    // move according to canvas origin
+    scaled.Move(canvasOrigin);
+
+    DEBUG_INT4("DoScalingAndPositioning scaled %d %d", scaled.iBr.iX, scaled.iBr.iY,
+               scaled.iTl.iX, scaled.iTl.iY);
+
+    // return of scaled value
+    return scaled;
+}
+
+TSize CMIDUtils::DoScaling(TSize aNonScaled)
+{
+    DEBUG("TSize CMIDUtils::DoScaling(TSize aNonScaled)");
+
+    // initial value of return structure
+    TSize scaled = aNonScaled;
+
+    // get of all needed values for scaling
+    TScalingData data = GetScalingData();
+
+    // scaling of size
+    scaled.iWidth *= data.iRatioX;
+    scaled.iHeight *= data.iRatioY;
+
+    DEBUG_INT2("DoScaling scaled %d %d", scaled.iWidth, scaled.iHeight);
+
+    // return of scaled value
+    return scaled;
+}
+
+TInt CMIDUtils::DoDescaling(TInt aNonScaled, TInt aDirection)
+{
+    DEBUG("TInt CMIDUtils::DoDescaling(TInt aNonScaled, TInt aDirection)");
+
+    // initial value of return structure
+    TInt scaled = aNonScaled;
+
+    // get of all needed values for scaling
+    TScalingData data = GetScalingData();
+
+    // descaling in entered direction
+    // no scaling if direction is not valid
+    if (aDirection == EHorizontal)
+    {
+        scaled /= data.iRatioX;
+    }
+    else if (aDirection == EVertical)
+    {
+        scaled /= data.iRatioY;
+    }
+
+    DEBUG_INT("DoDescaling scaled %d", scaled);
+
+    // return of descaled value
+    return scaled;
+}
+
+TPoint CMIDUtils::DoDescaling(TPoint aNonScaled)
+{
+    DEBUG("TPoint CMIDUtils::DoDescaling(TPoint aNonScaled)");
+
+    // initial value of return structure
+    TPoint scaled = aNonScaled;
+
+    // get of all needed values for scaling
+    TScalingData data = GetScalingData();
+
+    // descaling of point
+    scaled.iX /= data.iRatioX;
+    scaled.iY /= data.iRatioY;
+
+    DEBUG_INT2("DoDescaling scaled %d %d", scaled.iX, scaled.iY);
+
+    // return of descaled value
+    return scaled;
+}
+
+TPoint CMIDUtils::DoDescalingAndPositioning(TPoint aNonScaled)
+{
+    DEBUG("TPoint CMIDUtils::DoDescalingAndPositioning(TPoint aNonScaled)");
+
+    // initial value of return structure
+    TPoint scaled = aNonScaled;
+
+    // get of all needed values for scaling
+    TScalingData data = GetScalingData();
+
+    // get of canvas origin
+    TSize subtract = data.iScreenSize - data.iCanvasSize;
+    TPoint canvasOrigin = TPoint(subtract.iWidth / 2, subtract.iHeight / 2);
+
+    // move according to canvas origin
+    scaled -= canvasOrigin;
+
+    // descaling of point
+    scaled.iX /= data.iRatioX;
+    scaled.iY /= data.iRatioY;
+
+    DEBUG_INT2("DoDescalingAndPositioning scaled %d %d", scaled.iX, scaled.iY);
+
+    // return of descaled value
+    return scaled;
+}
+
+TRect CMIDUtils::DoDescaling(TRect aNonScaled)
+{
+    DEBUG("TRect CMIDUtils::DoDescaling(TRect aNonScaled)");
+
+    // initial value of return structure
+    TRect scaled = aNonScaled;
+
+    // get of all needed values for scaling
+    TScalingData data = GetScalingData();
+
+    // descaling of rect
+    scaled.iBr.iX /= data.iRatioX;
+    scaled.iBr.iY /= data.iRatioY;
+    scaled.iTl.iX /= data.iRatioX;
+    scaled.iTl.iY /= data.iRatioY;
+
+    DEBUG_INT4("DoDescaling scaled %d %d", scaled.iBr.iX, scaled.iBr.iY, scaled.iTl.iX, scaled.iTl.iY);
+
+    // return of descaled value
+    return scaled;
+}
+
+TRect CMIDUtils::DoDescalingAndPositioning(TRect aNonScaled)
+{
+    DEBUG("TRect CMIDUtils::DoDescalingAndPositioning(TRect aNonScaled)");
+
+    // initial value of return structure
+    TRect scaled = aNonScaled;
+
+    // get of all needed values for scaling
+    TScalingData data = GetScalingData();
+
+    // get of canvas origin
+    TSize subtract = data.iScreenSize - data.iCanvasSize;
+    TPoint canvasOrigin = TPoint(subtract.iWidth / 2, subtract.iHeight / 2);
+
+    // move according to canvas origin
+    scaled.Move(-canvasOrigin);
+
+    // descaling of rect
+    scaled.iBr.iX /= data.iRatioX;
+    scaled.iBr.iY /= data.iRatioY;
+    scaled.iTl.iX /= data.iRatioX;
+    scaled.iTl.iY /= data.iRatioY;
+
+    DEBUG_INT4("DoDescalingAndPositioning scaled %d %d", scaled.iBr.iX, scaled.iBr.iY, scaled.iTl.iX, scaled.iTl.iY);
+
+    // return of descaled value
+    return scaled;
+}
+
+TSize CMIDUtils::DoDescaling(TSize aNonScaled)
+{
+    DEBUG("TSize CMIDUtils::DoDescaling(TSize aNonScaled)");
+    TSize scaled = aNonScaled;
+
+    // get of all needed values for scaling
+    TScalingData data = GetScalingData();
+
+    // descaling of size
+    scaled.iWidth /= data.iRatioX;
+    scaled.iHeight /= data.iRatioY;
+
+    DEBUG_INT2("DoDescaling scaled %d %d", scaled.iWidth, scaled.iHeight);
+
+    // return of descaled value
+    return scaled;
+}
+
+CMIDUtils::TScalingData CMIDUtils::GetScalingData()
+{
+    // If iScalingData is not initialized, this method will initialized it.
+    if (iScalingData == TScalingData())
+    {
+        // Create local instance of TScalingData
+        TScalingData data = TScalingData();
+
+        // Get actual rect of screen without with eventual OSK.
+        TRect screenRect =iEnv->Current()->GetCanvasRectFromLaf();
+
+        // Traslate of rect of screen into size
+        data.iScreenSize = screenRect.Size();
+
+        // Check if scaling is is on now.
+        if (iMenuHandler->IsScalingEffectiveInCurrentScreen())
+        {
+
+            // Get original and target size from JAD attributes
+            data.iOriginalSize = iMenuHandler->GetScalingParameterOrgMIDletScrSize();
+            data.iTargetSize = iMenuHandler->GetScalingParameterTargetMIDletScrSize();
+
+            // Check if JAD attribute allows orientation change during scalling
+            // is present. If it is present, this switches orientation of original
+            // size, if it is needed.
+            if (iMenuHandler->GetScalingParameterScaleMIDletOnOrientSwitch())
+            {
+                // portait
+                if (data.iScreenSize.iWidth < data.iScreenSize.iHeight)
+                {
+                    data.iOriginalSize = TSize(Min(data.iOriginalSize.iHeight,
+                                                   data.iOriginalSize.iWidth),
+                                               Max(data.iOriginalSize.iHeight,
+                                                   data.iOriginalSize.iWidth));
+                }
+                // landscape
+                else
+                {
+                    data.iOriginalSize = TSize(Max(data.iOriginalSize.iHeight,
+                                                   data.iOriginalSize.iWidth),
+                                               Min(data.iOriginalSize.iHeight,
+                                                   data.iOriginalSize.iWidth));
+                }
+            }
+
+        }
+
+        if (data.iTargetSize != TSize())
+        {
+            // When target size is set, then possible horizontal and vertical
+            // scaling factor are various. And in this case canvas size is
+            //  equal to target size.
+            data.iRatioX = (TReal) data.iTargetSize.iWidth / data.iOriginalSize.iWidth;
+            data.iRatioY = (TReal) data.iTargetSize.iHeight / data.iOriginalSize.iHeight;
+            data.iCanvasSize = data.iTargetSize;
+        }
+        else if (data.iOriginalSize != TSize())
+        {
+            // When target size is not set, then only one scaling factor is present.
+            // It is smaller of horizontal and vertical scaling factors.
+            // And in this case canvas have size calculated according to
+            // the scaling factor.
+            data.iRatioX = (TReal) data.iScreenSize.iWidth / data.iOriginalSize.iWidth;
+            data.iRatioY = (TReal) data.iScreenSize.iHeight / data.iOriginalSize.iHeight;
+            TReal ratio = Min(data.iRatioX, data.iRatioY);
+            data.iRatioX = ratio;
+            data.iRatioY = ratio;
+            data.iCanvasSize = TSize(data.iOriginalSize.iWidth * ratio,
+                                     data.iOriginalSize.iHeight * ratio);
+        }
+        else
+        {
+            // When scaling is off, then canvas ocupied whole screen.
+            data.iCanvasSize = data.iScreenSize;
+        }
+
+        // Set local variable to iScalingData
+        iScalingData = data;
+    }
+
+    return iScalingData;
+}
+
+void CMIDUtils::ResetScalingData()
+{
+    // Firstly is needed set iScaling data to notinicialized value.
+    iScalingData = TScalingData();
+    // Now we can set new scaling data.
+    iScalingData = GetScalingData();
+}
+
+// ============================ TStickyKeysHandler ===========================
+
+CMIDUtils::TStickyKeysHandler::TStickyKeysHandler()
+{
+    ResetState();
+    iFnKeyState = EKeyNotActive;
+    iShiftKeyState = EKeyNotActive;
+}
+
+void  CMIDUtils::TStickyKeysHandler::Reset()
+{
+    ResetState();
+    iStickyModifier = 0;
+    // When reseting state, we must take locked sticky keys into account
+    // If Fn is locked, then after reset Fn still must be added to midifiers
+    if (iFnKeyState == EKeyLocked)
+    {
+        AddFnToStickyModifiers();
+    }
+    else
+    {
+        iFnKeyState = EKeyNotActive;
+    }
+
+    // Fn has higher priority than shift, and only one sticky key might
+    // be locked at the time
+    // For half QWERTY we need to process also shift as a regular key when Fn is active
+    if (iFnKeyState == EKeyNotActive)
+    {
+        // Pre-setting shift
+        switch (iShiftKeyState)
+        {
+        case EKeyLocked:
+            // Shift is locked, so add modifier
+            AddShiftToStickyModifiers();
+            break;
+        case EKeyActive:
+            // Shift wasn't locked
+            iShiftKeyState = EKeyNotActive;
+            break;
+        case EKeyNotActiveNext:
+            // Shift was locked, but should be deactivated for next keypress,
+            // so add it to modifiers...
+            AddShiftToStickyModifiers();
+            // .. and move back to locked state
+            iShiftKeyState = EKeyLocked;
+            break;
+        default:
+            iShiftKeyState = EKeyNotActive;
+            break;
+        }
+    }
+}
+
+TBool CMIDUtils::TStickyKeysHandler::HandleKey(
+    const TKeyEvent& aKeyEvent, TEventCode aType)
+{
+    if (!IsSticky(aKeyEvent))
+    {
+        // Check Fn key
+        if (aKeyEvent.iModifiers & EModifierRightFunc)
+        {
+            iStickyModifier = aKeyEvent.iModifiers;
+        }
+        ResetState();
+        return EFalse;
+    }
+
+    // Depending on sticky key state...
+    switch (iStickyKeyState)
+    {
+    case EKeyNotPressed:
+        // No sticky key was pressed
+        if (aType == EEventKeyDown)
+        {
+            // If key down event arrived, remember it's keycode and
+            // move to next state (sticky key pressed)
+            iLastStickyScanCode = aKeyEvent.iScanCode;
+            iStickyKeyState = EKeyWasPressed;
+        }
+        else
+        {
+            // Reset handler's state
+            Reset();
+        }
+        break;
+    case EKeyWasPressed:
+        // Sticky key was pressed before
+        if (aType == EEventKeyUp)
+        {
+            // If same sticky key was released as pressed in previous state,
+            // move to the next state (sticky key released)
+            if (iLastStickyScanCode == aKeyEvent.iScanCode)
+            {
+                iStickyKeyState = EKeyWasReleased;
+            }
+        }
+        else
+        {
+            // Reset handler's state
+            Reset();
+        }
+        break;
+    default:
+        Reset();
+        break;
+    }
+
+    TBool wasStickyKey = EFalse;
+    if (EKeyWasReleased == iStickyKeyState)
+    {
+        // Sticky key was pressed and released, so we need to get
+        // modifiers from scan code.
+        TUint modifier = ModifierFromScanCode(aKeyEvent.iScanCode);
+
+        // Add/remove modifier to/from stored modifiers
+        if (iStickyModifier & modifier)
+        {
+            iStickyModifier &= ~modifier;
+        }
+        else
+        {
+            iStickyModifier |= modifier;
+        }
+
+        ResetState();
+        HandleLockableKeys(modifier);
+        wasStickyKey = ETrue;
+    }
+
+    return wasStickyKey;
+}
+
+TInt  CMIDUtils::TStickyKeysHandler::Modifiers() const
+{
+    return iStickyModifier;
+}
+
+void  CMIDUtils::TStickyKeysHandler::ResetState()
+{
+    iLastStickyScanCode = 0;
+    iStickyKeyState = EKeyNotPressed;
+}
+
+TUint CMIDUtils::TStickyKeysHandler::ModifierFromScanCode(TInt aScanCode)
+{
+    switch (aScanCode)
+    {
+    case EStdKeyLeftShift:
+        return EModifierShift | EModifierLeftShift;
+    case EStdKeyRightShift:
+        return EModifierShift | EModifierRightShift;
+    case EStdKeyLeftAlt:
+        return EModifierAlt | EModifierLeftAlt;
+    case EStdKeyRightAlt:
+        return EModifierAlt | EModifierRightAlt;
+    case EStdKeyLeftCtrl:
+        return EModifierCtrl | EModifierLeftCtrl;
+    case EStdKeyRightCtrl:
+        return EModifierCtrl | EModifierRightCtrl;
+    case EStdKeyLeftFunc:
+        return EModifierLeftFunc;
+    case EStdKeyRightFunc:
+        return EModifierFunc | EModifierRightFunc;
+    default:
+        return 0;
+    }
+}
+
+
+TBool CMIDUtils::TStickyKeysHandler::IsSticky(const TKeyEvent& aKeyEvent)
+{
+    TBool isStickyKey = EFalse;
+    switch (aKeyEvent.iScanCode)
+    {
+    case EStdKeyLeftFunc:
+    case EStdKeyLeftShift:
+    case EStdKeyRightShift:
+        isStickyKey = !IsFnModifierOn(iStickyModifier) &&
+                      !(aKeyEvent.iModifiers & EModifierRightFunc);
+        break;
+    case EStdKeyLeftAlt:
+    case EStdKeyRightAlt:
+    case EStdKeyLeftCtrl:
+    case EStdKeyRightCtrl:
+    case EStdKeyRightFunc:
+        isStickyKey =  ETrue;
+        break;
+    default:
+        break;
+    }
+
+    return isStickyKey;
+}
+
+void CMIDUtils::TStickyKeysHandler::HandleLockableKeys(TUint aModifiers)
+{
+    if (IsFnModifierOn(aModifiers))
+    {
+        iActualFnModifierValue = 0;
+        if (aModifiers & EModifierLeftFunc)
+        {
+            iActualFnModifierValue = EModifierLeftFunc;
+        }
+        if (aModifiers & EModifierRightFunc)
+        {
+            iActualFnModifierValue = EModifierRightFunc;
+        }
+        HandleFnKey();
+    }
+
+    if (IsShiftModifierOn(aModifiers))
+    {
+        iActualShiftModifierValue = 0;
+        if (aModifiers & EModifierLeftShift)
+        {
+            iActualShiftModifierValue = EModifierLeftShift;
+        }
+        if (aModifiers & EModifierRightShift)
+        {
+            iActualShiftModifierValue = EModifierRightShift;
+        }
+        HandleShiftKey();
+    }
+}
+
+/**
+ * Handle event with modifier of Fn key
+ */
+void CMIDUtils::TStickyKeysHandler::HandleFnKey()
+{
+    switch (iFnKeyState)
+    {
+    case EKeyNotActive:
+        iFnKeyState = EKeyActive;
+        break;
+    case EKeyActive:
+        iFnKeyState = EKeyLocked;
+        AddFnToStickyModifiers();
+        break;
+    case EKeyLocked:
+        iFnKeyState = EKeyNotActive;
+        // If Fn lock is disabled, also disable Shift lock.
+        iShiftKeyState = EKeyNotActive;
+        Reset();
+        break;
+    }
+}
+
+/**
+ * Handle event with modifier of Shift key
+ */
+void CMIDUtils::TStickyKeysHandler::HandleShiftKey()
+{
+    switch (iShiftKeyState)
+    {
+    case EKeyNotActive:
+        iShiftKeyState = EKeyActive;
+        break;
+    case EKeyActive:
+        iShiftKeyState = EKeyLocked;
+        AddShiftToStickyModifiers();
+        break;
+    case EKeyLocked:
+        iStickyModifier = 0;
+        if (iFnKeyState == EKeyLocked)
+        {
+            AddFnToStickyModifiers();
+        }
+        iShiftKeyState = EKeyNotActiveNext;
+        break;
+    case EKeyNotActiveNext:
+        iShiftKeyState = EKeyNotActive;
+        Reset();
+        break;
+    }
+}
+
+void CMIDUtils::TStickyKeysHandler::AddShiftToStickyModifiers()
+{
+    iStickyModifier |= EModifierShift | iActualShiftModifierValue;
+}
+
+void CMIDUtils::TStickyKeysHandler::AddFnToStickyModifiers()
+{
+    //Chr key (EModifierLeftFunc) is not handled as sticky key because
+    //it should not function in any special way
+    if (iActualFnModifierValue != EModifierLeftFunc)
+    {
+        iStickyModifier |= EModifierFunc | iActualFnModifierValue;
+    }
+}
+
+inline TBool CMIDUtils::TStickyKeysHandler::IsFnModifierOn(
+    const TUint aModifiers) const
+{
+    return aModifiers & EModifierFunc ||
+           aModifiers & EModifierRightFunc;
+}
+
+
+inline TBool CMIDUtils::TStickyKeysHandler::IsShiftModifierOn(
+    const TUint aModifiers) const
+{
+    return aModifiers & EModifierShift ||
+           aModifiers & EModifierLeftShift ||
+           aModifiers & EModifierRightShift;
+}
+
+// End of File