bluetoothengine/bthid/keyboard/src/keyboard.cpp
changeset 0 f63038272f30
child 11 f7fbeaeb166a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothengine/bthid/keyboard/src/keyboard.cpp	Mon Jan 18 20:28:57 2010 +0200
@@ -0,0 +1,1932 @@
+/*
+* Copyright (c) 2004 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:  This is the implementation of application class
+ *
+*/
+
+
+#include <e32std.h>
+#include <e32svr.h>
+#include <w32std.h>
+#include <coedef.h>
+#include <eiksvdef.h>
+#include <apgcli.h>
+#include <apgtask.h>
+#include <apacmdln.h>
+#include <e32property.h>
+
+#include "hidtranslate.h"
+#include "finder.h"
+#include "keyboard.h"
+#include "layoutmgr.h"
+#include "debug.h"
+#include "timeouttimer.h"
+#include "layoututils.h"
+#include "bthidPsKey.h"
+
+// ----------------------------------------------------------------------
+
+// Application UIDs for finding window groups.
+const TInt KIdleAppUid = 0x102750f0;
+const TInt KPhoneAppUid = 0x100058b3;
+const TInt KMenuAppUid = 0x101f4cd2;
+const TInt KSysApUid = 0x100058f3;
+const TInt KActiveNotesUid = 0x10281a31;
+const TInt KMessagingUid = 0x100058C5;
+const TInt KServicesUid = 0x10008D39;
+//const TInt KMultimediaMenuUid = 0x10281cfb;
+
+// Key repeat parameters to be configured
+const TInt KRepeatEndTimeout = 5000000; // 5 seconds
+
+const TInt KKeyRepeatDelay = 500000;
+const TInt KKeyRepeatInterval = 75000;
+_LIT(KAppName, "PaintCursor.exe");
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::CHidKeyboardDriver
+//----------------------------------------------------------------------------
+//
+CHidKeyboardDriver::CHidKeyboardDriver(MDriverAccess* aGenericHid) :
+    iDriverState(EUninitialised), iGenericHid(aGenericHid), iMmKeyDown(0)
+    {
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::CHidKeyboardDriver(0x%08x)"), aGenericHid));
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::NewLC
+//----------------------------------------------------------------------------
+//
+CHidKeyboardDriver* CHidKeyboardDriver::NewLC(MDriverAccess* aGenericHid)
+    {
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::NewLC(0x%08x)"), aGenericHid));
+    CHidKeyboardDriver* self = new (ELeave) CHidKeyboardDriver(aGenericHid);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    return self;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::NewL
+//----------------------------------------------------------------------------
+//
+CHidKeyboardDriver* CHidKeyboardDriver::NewL(MDriverAccess* aGenericHid)
+    {
+    CHidKeyboardDriver* self = CHidKeyboardDriver::NewLC(aGenericHid);
+    CleanupStack::Pop();
+    return self;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::ConstructL
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::ConstructL()
+    {
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver{0x%08x}::ConstructL()"), this));
+
+    User::LeaveIfNull(iGenericHid);
+
+    // Create a session with the window server:
+    User::LeaveIfError(iWsSession.Connect());
+
+    // Create a session with the layout manager:
+    User::LeaveIfError(iLayoutMgr.Connect());
+
+    // We also need a key repeat timer:
+    iRepeatTimer = CPeriodic::NewL(CActive::EPriorityStandard);
+
+    // repeat ending timer
+    iRepeatEndTimer = CTimeOutTimer::NewL(EPriorityNormal, *this);
+    iAppMenuId = AppMenuId();
+    iPhoneAppId = PhoneAppId();
+    iIdleAppId = IdleAppId();
+
+    iComboDevice = EFalse;
+
+    iSettings = CBtHidSettings::NewL();
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::~CHidKeyboardDriver
+//----------------------------------------------------------------------------
+//
+CHidKeyboardDriver::~CHidKeyboardDriver()
+    {
+        TRACE_INFO( (_L("[HID]\t~CHidKeyboardDriver() 0x%08x"), this));
+
+    CancelAllKeys();
+    delete iRepeatTimer;
+    delete iRepeatEndTimer;
+    iWsSession.Close();
+    iLayoutMgr.Close();
+
+    for (TInt i = 0; i < KNumInputFieldTypes; ++i)
+        {
+        iKeys[i].Reset();
+        }
+
+    iPointBufQueue.Close();
+
+    if (iComboDevice)
+        {
+        RProperty::Set( KPSUidBthidSrv, KBTMouseCursorState, ECursorHide );
+        }
+
+    if (iSettings)
+        delete iSettings;
+    }
+
+void CHidKeyboardDriver::MoveCursor(const TPoint& aPoint)
+    {
+    DBG(RDebug::Print(
+                    _L("CHidKeyboard::MoveCursor")));
+
+    PostPointer(aPoint);
+    }
+// ---------------------------------------------------------------------------
+// CHidMouseDriver::PostPointer
+// Save the event to the buffer
+// ---------------------------------------------------------------------------
+//
+TInt CHidKeyboardDriver::PostPointer(const TPoint& aPoint)
+    {
+    DBG(RDebug::Print(_L("CHidKeyboard::PostPointer")));
+    iPointerBuffer.iPoint[iPointerBuffer.iNum] = aPoint;
+    iPointerBuffer.iType[iPointerBuffer.iNum] = KBufferPlainPointer;
+    iPointerBuffer.iNum++;
+    TInt ret = KErrNone;
+
+    if (iPointerBuffer.iNum > KPMaxEvent)
+        {
+        ret = iPointBufQueue.Send(iPointerBuffer);
+        iPointerBuffer.iNum = 0;
+        }
+    return ret;
+    }
+
+TInt CHidKeyboardDriver::SendButtonEvent(TBool aButtonDown)
+    {
+    DBG(RDebug::Print(
+                    _L("CHidKeyboard::SendButtonEvent")));
+    iPointerBuffer.iPoint[iPointerBuffer.iNum] = TPoint(0, 0);
+    iPointerBuffer.iType[iPointerBuffer.iNum] = aButtonDown
+                                                            ? KBufferPenDown
+                                                               : KBufferPenUp;
+    iPointerBuffer.iNum++;
+    TInt ret = iPointBufQueue.Send(iPointerBuffer);
+    iPointerBuffer.iNum = 0;
+    return ret;
+    }
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver:::StartL
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::StartL(TInt aConnectionId)
+    {
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::StartL")));
+    aConnectionId = aConnectionId;
+    // No keys are pressed:
+    iModifiers = 0;
+    for (TInt i = 0; i < KNumInputFieldTypes; ++i)
+        {
+        if (iField[i])
+            {
+            // Reset the keys pressed array to all zeros
+            RArray<TInt>& keys = iKeys[i];
+
+            for (TInt j = 0; j < keys.Count(); j++)
+                {
+                keys[j] = 0;
+                }
+            }
+        }
+
+    // Start up with Num Lock active:
+    iLockState = ENumLock;
+    SetKeyboardLeds();
+
+    //In case of reconnection, try to initialize the Keybord driver...
+    InitialiseL(aConnectionId);
+
+    // Reset the state of the layout decoder:
+    iLayoutMgr.Reset();
+
+    TInt initialLayout;
+    User::LeaveIfError(iLayoutMgr.GetLayout(initialLayout));
+    iLastSelectedLayout = iSettings->LoadLayoutSetting();
+    TBool sameCategory = CLayoutUtils::SameCategory(
+            static_cast<THidKeyboardLayoutId> (initialLayout),
+            iLastSelectedLayout);
+    if (sameCategory)
+        {
+        //Used the layoutID from CenRep
+        iLayoutMgr.SetLayout(iLastSelectedLayout);
+        }
+    TInt err = iPointBufQueue.OpenGlobal(KMsgBTMouseBufferQueue);   
+    if (err == KErrNotFound)
+        {
+        User::LeaveIfError(iPointBufQueue.CreateGlobal(KMsgBTMouseBufferQueue, KPointQueueLen));    
+        }
+    else
+        {
+        User::LeaveIfError( err );
+        }    
+
+    // Ready to process keyboard events:
+    iDriverState = EInitialised;
+
+    if (iComboDevice)
+        {
+        LaunchApplicationL(KAppName);
+        RProperty::Set( KPSUidBthidSrv, KBTMouseCursorState, ECursorShow );
+        }
+
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::InitialiseL
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::InitialiseL(TInt aConnectionId)
+    {
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::InitialiseL(%d)"),
+                        aConnectionId));
+
+    // Store the connection ID:
+    iConnectionId = aConnectionId;
+
+    // Initialise the layout manager:
+    TInt country = iGenericHid->CountryCodeL(aConnectionId);
+    TInt vendor = iGenericHid->VendorIdL(aConnectionId);
+    TInt product = iGenericHid->ProductIdL(aConnectionId);
+
+        TRACE_INFO( (
+                        _L("[HID]\t  Country = %d, vendor = %d, product = %d"),
+                        country, vendor, product));
+
+    User::LeaveIfError(iLayoutMgr.SetInitialLayout(country, vendor, product));
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::Stop
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::Stop()
+    {
+    iDriverState = EDisabled;
+    CancelAllKeys();
+    if (iComboDevice)
+        {
+        RProperty::Set( KPSUidBthidSrv, KBTMouseCursorState, ECursorHide );
+        }
+    }
+
+//----------------------------------------------------------------------------
+// CHidMouseDriver::LaunchApplicationL
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::LaunchApplicationL(const TDesC& aName)
+    {
+    //Check if application is already running in the background
+    TApaTaskList tasks(iWsSession);
+    TApaTask task = tasks.FindApp(aName);
+    if (task.Exists())
+        {
+        // Application is active, so just bring to foreground
+        }
+    else
+        {
+        // If application is not running, then create a new one
+        CApaCommandLine* cmd = CApaCommandLine::NewLC();
+        cmd->SetExecutableNameL(aName);
+        cmd->SetCommandL(EApaCommandBackground); // EApaCommandRun
+
+        RApaLsSession arcSession;
+        //connect to AppArc server
+        User::LeaveIfError(arcSession.Connect());
+        CleanupClosePushL(arcSession);
+        User::LeaveIfError(arcSession.StartApp(*cmd));
+        arcSession.Close();
+        CleanupStack::PopAndDestroy(2);
+        }
+
+    }
+
+// ----------------------------------------------------------------------
+// CHidDriver mandatory functions:
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::DataIn
+//----------------------------------------------------------------------------
+//
+TInt CHidKeyboardDriver::DataIn(CHidTransport::THidChannelType aChannel,
+        const TDesC8& aPayload)
+    {
+    TInt err = KErrNone;
+    switch (aChannel)
+        {
+        case CHidTransport::EHidChannelInt:
+            if (EInitialised == iDriverState)
+                {
+                if (iComboDevice)
+                    {
+                    TInt mouseStatus;
+                    TInt err = RProperty::Get( KPSUidBthidSrv, KBTMouseCursorState, mouseStatus );
+                    if ( !err && (static_cast<THidMouseCursorState>(mouseStatus) == ECursorHide) )
+                        {
+                        err = RProperty::Set( KPSUidBthidSrv, KBTMouseCursorState, ECursorShow );
+                        }
+                    }
+                InterruptData(aPayload);
+                }
+            break;
+
+        case CHidTransport::EHidChannelCtrl:
+            break;
+
+        default:
+            break;
+        }
+    return err;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::CommandResult
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::CommandResult(TInt /*aCmdAck*/)
+    {
+    // No implementation as we don't issue any requests to be acknowledged
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::Disconnected
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::Disconnected(TInt aReason)
+    {
+    RDebug::Print(_L("CHidKeyboardDriver::Disconnected(%d)"), aReason);
+    Stop();
+    }
+
+void CHidKeyboardDriver::UpdateXY(TInt aFieldIndex, const TDesC8& aReport)
+    {
+    //    DBG(RDebug::Print(_L("[HID]\tCHidMouseDriver::UpdateModifiers()")));
+
+    // Translate the HID usage values into a boot protocol style
+    // modifier bitmask:
+    //
+    TReportTranslator report(aReport, iMouseField[aFieldIndex]);
+
+    TInt Xvalue = 0;
+    TInt Yvalue = 0;
+
+    TInt errX = report.GetValue(Xvalue, EGenericDesktopUsageX);
+    TInt errY = report.GetValue(Yvalue, EGenericDesktopUsageY);
+
+    DBG(RDebug::Print(_L("[HID]\tCHidMouseDriver::UpdateXY (%d,%d)"), Xvalue, Yvalue));
+    if ((Xvalue != 0) || (Yvalue != 0))
+        {
+        MoveCursor(TPoint(Xvalue, Yvalue));
+        }
+    }
+
+void CHidKeyboardDriver::UpdateWheel(TInt aFieldIndex, const TDesC8& aReport)
+    {
+    TReportTranslator report(aReport, iMouseField[aFieldIndex]);
+
+    TInt Yvalue = 0;
+
+    TInt errY = report.GetValue(Yvalue, EGenericDesktopUsageWheel);
+    DBG(RDebug::Print(_L("[HID]\tCHidMouseDriver::UpdateWheel (%d)"), Yvalue));
+    TInt absValue(Abs(Yvalue));
+    if ((errY == KErrNone) && (absValue >= 1))
+        {
+        TRawEvent rawEvent;
+        for (TInt ii = 0; ii < absValue; ii++)
+            {
+            rawEvent.Set(TRawEvent::EKeyDown,
+                    (Yvalue > 0) ? EStdKeyUpArrow : EStdKeyDownArrow);
+            UserSvr::AddEvent(rawEvent);
+            rawEvent.Set(TRawEvent::EKeyUp,
+                    (Yvalue > 0) ? EStdKeyUpArrow : EStdKeyDownArrow);
+            UserSvr::AddEvent(rawEvent);
+            }
+        }
+    DBG(RDebug::Print(_L("[HID]\t  new iModifiers = %02x"), iModifiers));
+    }
+
+void CHidKeyboardDriver::UpdateButtons(TInt aFieldIndex,
+        const TDesC8& aReport)
+    {
+    DBG(RDebug::Print(_L("[HID]\tCHidMouseDriver::UpdateButtons()")));
+    // Translate the HID usage values into a boot protocol style
+    // modifier bitmask:
+    //
+    const TInt KButton1 = 1;
+    const TInt KButton2 = 2;
+    const TInt KButton3 = 3;
+
+    TBool buttonPressed(EFalse);
+
+    DBG(RDebug::Print(_L("[HID]\tCHidMouseDriver::UpdateButtons() %d, %d, %d"),
+                    iMouseField[aFieldIndex]->UsagePage(),
+                    iMouseField[aFieldIndex]->UsageMin(),
+                    iMouseField[aFieldIndex]->UsageMax()));
+    (void) aFieldIndex;
+    // Hack but works
+    // We dont come here if the report is wrong?
+    TInt buttonByte = aReport[1];
+    if (KButton1 == buttonByte)
+        {
+        DBG(RDebug::Print(_L("[HID]\tCHidMouseDriver::UpdateButtons() Button1")));
+        buttonPressed = ETrue;
+        }
+
+    if (KButton2 == buttonByte)
+        {
+        DBG(RDebug::Print(_L("[HID]\tCHidMouseDriver::UpdateButtons() Button2")));
+        if (!iButton2Down)
+            {
+            iButton2Down = ETrue;
+            TRawEvent rawEvent;
+            rawEvent.Set(TRawEvent::EKeyDown, EStdKeyApplication0);
+            UserSvr::AddEvent(rawEvent);
+            }
+        }
+    else
+        {
+        if (iButton2Down)
+            {
+            iButton2Down = EFalse;
+            TRawEvent rawEvent;
+            rawEvent.Set(TRawEvent::EKeyUp, EStdKeyApplication0);
+            UserSvr::AddEvent(rawEvent);
+            }
+        }
+
+    if (KButton3 == buttonByte)
+        {
+        DBG(RDebug::Print(_L("[HID]\tCHidMouseDriver::UpdateButtons() Button3")));
+        buttonPressed = ETrue;
+        }
+
+    if (buttonPressed)
+        {
+        if (!iButtonDown)
+            {
+            iButtonDown = ETrue;
+            SendButtonEvent(ETrue);//Send Mouse Button Down
+            }
+        }
+    else
+        {
+        if (iButtonDown)
+            {
+            iButtonDown = EFalse;
+            SendButtonEvent(EFalse); //Send Mouse Button Up
+            }
+        }
+    }
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::InterruptData
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::InterruptData(const TDesC8& aPayload)
+    {
+    // If the report has a report ID, it is in the first byte.
+    // If not, this value is ignored (see CField::IsInReport()).
+    //
+    TInt firstByte = aPayload[0];
+
+        TRACE_INFO( (
+                        _L("[HID]\tCHidKeyboardDriver::InterruptData(), report %d, length %d"),
+                        firstByte, aPayload.Length()));
+#ifdef _DEBUG
+
+    for (TInt ii = 0; ii < aPayload.Length(); ii++)
+        {
+        TInt nextByte = aPayload[ii];
+        DBG(RDebug::Print(
+                        _L("[HID]\tCHidKeyboardDriver::InterruptData()  report[%d] =  %d"),
+                        ii, nextByte));
+        }
+#endif
+    TBool mouseEvent(EFalse);
+    if (iMouseField[EMouseXY] && iMouseField[EMouseXY]->IsInReport(firstByte))
+        {
+        UpdateXY(EMouseXY, aPayload);
+        mouseEvent = ETrue;
+        }
+
+    if (iMouseField[EMouseButtons] && iMouseField[EMouseButtons]->IsInReport(
+            firstByte))
+        {
+        UpdateButtons(EMouseButtons, aPayload);
+        mouseEvent = ETrue;
+        }
+    if (iMouseField[EMouseXY] && iMouseField[EMouseXY]->IsInReport(firstByte))
+        {
+        UpdateWheel(EMouseWheel, aPayload);
+        mouseEvent = ETrue;
+        }
+    DBG(RDebug::Print(_L("[HID]\tCHidKeyboardDriver::InterruptData()  mouseevent %d"),
+                    mouseEvent));
+    if (mouseEvent)
+        {
+        return;
+        }
+    // First check for any rollover errors:
+    //
+    TInt i;
+    for (i = 0; i < KNumInputFieldTypes; ++i)
+        {
+        if (iField[i] && iField[i]->IsInReport(firstByte)
+                && (iField[i]->UsagePage() == EUsagePageKeyboard))
+            {
+            if (IsRollover(i, aPayload))
+                {
+                CancelAllKeys();
+                iLayoutMgr.Reset();
+                return;
+                }
+            }
+        }
+
+    // Update the modifier state:
+    //
+    if (iField[EModifierKeys] && iField[EModifierKeys]->IsInReport(firstByte))
+        {
+        UpdateModifiers(EModifierKeys, aPayload);
+        }
+
+    // Finally, look for key events in all fields in this report:
+    //
+    for (i = 0; i < KNumInputFieldTypes; ++i)
+        {
+        if (iField[i] && iField[i]->IsInReport(firstByte))
+            {
+            ProcessKeys(i, aPayload);
+            }
+        }
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::IsRollover
+//
+// IsRollover() checks to see if the keyboard is in a rollover state
+// (where too many keys are pressed to be able to give a sensible
+// report).
+//
+// Rollover can only happen for fields with usage page 0x07.
+//
+// Returns ETrue if the keyboard is in a rollover state
+//----------------------------------------------------------------------------
+//
+TBool CHidKeyboardDriver::IsRollover(TInt aFieldIndex, const TDesC8& aReport) const
+    {
+    TBool rollover = ETrue;
+
+    TReportTranslator report(aReport, iField[aFieldIndex]);
+
+    for (TInt i = 0; rollover && (i < report.Count()); ++i)
+        {
+        const TInt KRolloverError = 1;
+        TInt usage;
+
+        if (KErrNone == report.GetUsageId(usage, i) && usage
+                != KRolloverError)
+            {
+            rollover = EFalse;
+            }
+        }
+
+    return rollover;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::ProcessKeys
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::ProcessKeys(TInt aFieldIndex, const TDesC8& aReport)
+    {
+        TRACE_FUNC
+    ((_L("[HID]\tCHidKeyboardDriver::ProcessKeys()")));
+
+    // Get the appropriate field and key press array
+    const CField* field = iField[aFieldIndex];
+    RArray<TInt>& keysPressed = iKeys[aFieldIndex];
+
+    TInt bufferSize = keysPressed.Count();
+    TReportTranslator report(aReport, field);
+
+        // 1. For each key that appeared in the last report but does
+        //    not appear in this report, send a key UP event.
+
+        TRACE_FUNC
+    ((_L("[HID]\t  Testing for keys up")));
+
+    TInt i;
+    for (i = 0; i < bufferSize; ++i)
+        {
+        TInt key = keysPressed[i];
+
+        if (key)
+            {
+            TInt pressed = EFalse;
+
+            if ((report.GetValue(pressed, key) == KErrNone) && (!pressed))
+                {
+                    TRACE_INFO( (_L("[HID]\t  Key up: %d [0x%04x]"), key, key));
+                KeyUp(key, field->UsagePage());
+                }
+            }
+        }
+
+        // 2. For each key that appears in this report, but does
+        //    not appear in the last report, send a key DOWN event.
+
+        TRACE_FUNC
+    ((_L("  Testing for keys down")));
+
+    for (i = 0; i < report.Count(); ++i)
+        {
+        TInt key;
+
+        if ((KErrNone == report.GetUsageId(key, i)) && (key != 0))
+            {
+            // Was the key present (pressed) in the last report?
+            TBool match = EFalse;
+
+            for (TInt j = 0; !match && (j < bufferSize); ++j)
+                {
+                match = (key == keysPressed[j]);
+                }
+
+            // If it's a newly-pressed key then send a KeyDown
+            if (!match)
+                {
+                    TRACE_INFO( (_L("[HID]\t  Key down: %d [0x%02x]"), key, key));
+                if (iInputHandlingReg->AllowedToHandleEvent(
+                        EUsagePageKeyboard, key))
+                    {
+                    iInputHandlingReg->AddHandledEvent(
+                            EUsagePageGenericDesktop, key);
+                    KeyDown(key, field->UsagePage());
+                    UpdateLockState(key);
+                    }
+                }
+            }
+        }
+
+    // 3. Finally, record what keys are down:
+
+    TInt index = 0;
+    for (i = 0; (i < report.Count()) && (index < bufferSize); ++i)
+        {
+        TInt key;
+
+        if (KErrNone == report.GetUsageId(key, i) && key != 0)
+            {
+            keysPressed[index++] = key;
+            }
+        }
+    while (index < bufferSize)
+        {
+        keysPressed[index++] = 0;
+        }
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::KeyEvent
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::KeyEvent(TBool aIsKeyDown, TInt aHidKey,
+        TInt aUsagePage)
+    {
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::KeyEvent(%d, %d, %d)"), aIsKeyDown,
+                        aUsagePage, aHidKey));
+
+    // Any type of key event will cancel a repeating key:
+    //
+    if (iRepeatTimer->IsActive())
+        {
+        iRepeatTimer->Cancel();
+        }
+
+    if (iRepeatEndTimer->IsActive())
+        {
+        iRepeatEndTimer->Cancel();
+        }
+
+    // Pass the key info to the keyboard layout translator:
+    //
+    TDecodedKeyInfo decodedKeys;
+    TInt err = iLayoutMgr.KeyEvent(aIsKeyDown, aHidKey, aUsagePage,
+            iModifiers, TLockKeys(iLockState & ECapsLock, iLockState
+                    & ENumLock), decodedKeys);
+
+    TTranslatedKey& key = decodedKeys.iEvent[0];
+    if (err == KErrNone)
+        {
+        // Send the "key down" or "key up" event to the system:
+        // Handle special application launch key combinations
+        TRAPD( err, HandleApplicationLaunchKeysL(decodedKeys.iScanCode, aIsKeyDown, iModifiers));
+        if (KErrNone != err)
+            {
+                TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::KeyEvent:Launch failed")));
+            }
+
+        //check if the key is multimedia key that needs to be sent as RawEvent and send it.
+        // if key event is consumed don't send it anymore.
+        if (!HandleMultimediaKeys(decodedKeys.iScanCode, aIsKeyDown,
+                iModifiers)) //check if the key is multimedia key that needs to be sent as RawEvent and send it.
+            {
+            if (decodedKeys.iScanCode != EStdKeyNull)
+                {
+                TKeyEvent event =
+                        TKeyEventFromScanCode(decodedKeys.iScanCode);
+
+                // remove other modifiers than autorepeat.
+                if (event.iScanCode == EStdKeyDevice3)
+                    {
+                    event.iModifiers &= EModifierAutorepeatable;
+                    }
+
+                    //Number key events to phone app are handled differently.
+                    TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::KeyEvent: ScanCode: %d %c"), decodedKeys.iScanCode, decodedKeys.iScanCode));
+                TInt unikey = key.iUnicode;
+                //Send key codes differently to idle app
+                if ((IsDigitKey(decodedKeys.iScanCode) || IsSpecialHandleKey(
+                        unikey) || decodedKeys.iScanCode == EStdKeyYes
+                        || decodedKeys.iScanCode == EStdKeyBackspace)
+                        && IsPhoneAppTopMost())
+                    {
+                        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::KeyEvent: Send event %c to idle editor"), unikey));
+                    HandleTelephoneAppKeys(decodedKeys.iScanCode, unikey,
+                            aIsKeyDown);
+                    }
+                else
+                    SendToWindowGroup(event, aIsKeyDown
+                                                        ? EEventKeyDown
+                                                           : EEventKeyUp);
+                }
+
+            // Send any "key press" events to the system, if applicable:
+            //
+            for (TInt i = 0; i < decodedKeys.iCount; ++i)
+                {
+                TTranslatedKey & key = decodedKeys.iEvent[i];
+
+                SendKeyPress(key.iUnicode, key.iUsagePage, key.iScanCode,
+                        key.iIsRepeatingKey);
+                }
+            }
+        }
+    else
+        {
+            TRACE_FUNC
+        ((_L("[HID]\tKeyboard event translation failed!")));
+        }
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::TKeyEventFromScanCode
+//----------------------------------------------------------------------------
+//
+TKeyEvent CHidKeyboardDriver::TKeyEventFromScanCode(TInt aScanCode) const
+    {
+    TKeyEvent event;
+
+    event.iScanCode = aScanCode;
+    event.iModifiers = KeyEventModifiers();
+
+    // The following are always zero for a key down or key up event:
+    event.iCode = 0;
+    event.iRepeats = 0;
+
+    return event;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::IsDigitKey
+//----------------------------------------------------------------------------
+//
+TBool CHidKeyboardDriver::IsDigitKey(TInt aScanCode)
+    {
+    TBool ret = EFalse;
+
+    if (aScanCode >= '0' && aScanCode <= '9')
+        {
+        ret = ETrue;
+        }
+
+    return ret;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::IsDigit
+//----------------------------------------------------------------------------
+//
+TBool CHidKeyboardDriver::IsSpecialHandleKey(TInt aUniCode)
+    {
+    TBool ret = EFalse;
+
+    if (aUniCode == '+' || aUniCode == '*' || aUniCode == '#' || aUniCode
+            == 'w' || aUniCode == 'p')
+        {
+        ret = ETrue;
+        }
+
+    return ret;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::HandleTelephoneAppKeys
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::HandleTelephoneAppKeys(TInt aScanCode,
+        TInt aUniCode, TBool aIsKeyDown)
+    {
+    // Telephone view / idle view can't handle proper key events, but the key events must be sent as
+    // raw events.
+    TRawEvent rawEvent;
+    TUint modifier = 0;
+    TInt scancode = aScanCode;
+    switch (aUniCode)
+        {
+        case '+':
+        case EStdKeyNkpPlus:
+            scancode = EStdKeyNkpPlus;
+            modifier = EModifierLeftShift | EModifierShift;
+            break;
+        case '*':
+            //case EStdKeyNkpAsterisk:
+            scancode = EStdKeyNkpAsterisk;
+            modifier = 0; //EModifierLeftShift | EModifierShift;
+            break;
+        case '#':
+            //case EStdKeyHash:
+            scancode = EStdKeyHash;
+            modifier = EModifierLeftShift | EModifierShift;
+            break;
+        case 'w':
+            modifier = EModifierLeftShift | EModifierShift;
+            break;
+        case 'p':
+            modifier = EModifierLeftShift | EModifierShift;
+            break;
+        default:
+            break;
+        }
+        TRACE_INFO( (_L("[HID]\tHIDKeyboard: HandleTelephoneAppKeys: Overridden Scancode: %d, Modifier: %d"), scancode, modifier));
+        TRACE_INFO( (_L("[HID]\tHIDKeyboard: HandleTelephoneAppKeys: Original unicode: %d"), aUniCode));
+
+    if (aIsKeyDown)
+        rawEvent.Set(TRawEvent::EKeyDown, scancode);
+    else
+        rawEvent.Set(TRawEvent::EKeyUp, scancode); //This will never be called for +,* and #
+
+    TEventModifier ab = (TEventModifier) -1; //all bits set to 1.
+    TModifierState ba = (TModifierState) modifier;
+        TRACE_INFO( (_L("[HID]\t   modifiers %d, modifierState: %d"), ab, (TUint)ba));
+
+    iWsSession.SetModifierState(ab, ba);
+    iWsSession.SimulateRawEvent(rawEvent);
+    iWsSession.Flush();
+        TRACE_FUNC
+    ((_L("[HID]\tHIDKeyboard: HandleTelephoneAppKeys: Event sent!")));
+    // Plus, Asterix and Hash keys need to send separate KeyUp event too.
+    if (aUniCode == '+' || aUniCode == '*' || aUniCode == '#' || aUniCode
+            == 'p' || aUniCode == 'w')
+        {
+        rawEvent.Set(TRawEvent::EKeyUp, scancode);
+        iWsSession.SimulateRawEvent(rawEvent); //Key up event
+        iWsSession.Flush();
+            TRACE_FUNC
+        ((_L("[HID]\tHIDKeyboard: HandleTelephoneAppKeys: Separate Key up event sent!")));
+        }
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::CancelKeysForField
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::CancelKeysForField(TInt aFieldIndex)
+    {
+    //TRACE_FUNC((_L("[HID]\tCHidKeyboardDriver::CancelKeysForField(%d)"),
+    if (iField[aFieldIndex])
+        {
+        for (TInt i = 0; i < iField[aFieldIndex]->Count(); ++i)
+            {
+            TInt key = iKeys[aFieldIndex][i];
+            //TRACE_FUNC((_L("[HID]\t    Cancel key@%d=%02x (%d)"),
+            //        i, key, key));
+            if (key != 0)
+                {
+                KeyUp(key, iField[aFieldIndex]->UsagePage());
+                iKeys[aFieldIndex][i] = 0;
+                }
+            }
+        }
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::CancelAllKeys
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::CancelAllKeys()
+    {
+        TRACE_FUNC
+    ((_L("[HID]\tCHidKeyboardDriver::CancelAllKeys()")));
+
+    // Stop the key repeat timer:
+    if (iRepeatTimer->IsActive())
+        {
+        iRepeatTimer->Cancel();
+        }
+
+    // Stop the key repeat safety timer:
+    if (iRepeatEndTimer->IsActive())
+        {
+        iRepeatEndTimer->Cancel();
+        }
+
+    // Send key up events for any pressed keys:
+    for (TInt i = 0; i < KNumInputFieldTypes; ++i)
+        {
+        CancelKeysForField(i);
+        }
+
+    // No modifier keys pressed:
+    iModifiers = 0;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::UpdateModifiers
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::UpdateModifiers(TInt aFieldIndex,
+        const TDesC8& aReport)
+    {
+        TRACE_FUNC
+    ((_L("[HID]\tCHidKeyboardDriver::UpdateModifiers()")));
+        TRACE_INFO( (_L("[HID]\t  old iModifiers = %02x"), iModifiers));
+
+    const TInt KLeftControl = 224; // => bit 0 of modifier bitmask
+    const TInt KRightGui = 231; // => bit 7
+
+    TUint8 newModifiers = 0;
+
+    // Translate the HID usage values into a boot protocol style
+    // modifier bitmask:
+    //
+    TReportTranslator report(aReport, iField[aFieldIndex]);
+    for (TInt i = KLeftControl; i <= KRightGui; i++)
+        {
+        TInt value;
+
+        if (KErrNone == report.GetValue(value, i) && value)
+            {
+            newModifiers |= (1 << (i - KLeftControl));
+            }
+        }
+
+    // Finally, record the new state:
+    //
+    iModifiers = newModifiers;
+
+        TRACE_INFO( (_L("[HID]\t  new iModifiers = %02x"), iModifiers));
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::UpdateLockState
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::UpdateLockState(TInt aHidKey)
+    {
+    const TInt KHidCapsLock = 57;
+    const TInt KHidScrollLock = 71;
+    const TInt KHidNumLock = 83;
+
+    TUint oldLockState = iLockState;
+
+    switch (aHidKey)
+        {
+        case KHidNumLock:
+            iLockState ^= ENumLock;
+            break;
+        case KHidCapsLock:
+            iLockState ^= ECapsLock;
+            break;
+        case KHidScrollLock:
+            iLockState ^= EScrollLock;
+            break;
+        }
+
+    if (oldLockState != iLockState)
+        {
+            TRACE_INFO( (_L("[HID]\tChanged lock state: %d -> %d"),
+                            oldLockState, iLockState));
+        SetKeyboardLeds();
+        }
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::KeyEventModifiers
+//----------------------------------------------------------------------------
+//
+TUint32 CHidKeyboardDriver::KeyEventModifiers() const
+    {
+    // Modifier state:
+
+    const TInt KNumModifierKeys = 8;
+
+    const TUint32 KModifierMask[KNumModifierKeys] =
+        {
+        EModifierLeftCtrl | EModifierCtrl, // 0x  A0  (report bit 0)
+                EModifierLeftShift | EModifierShift, // 0x 500
+                EModifierLeftAlt | EModifierAlt, // 0x  14
+                EModifierLeftFunc | EModifierFunc, // 0x2800
+                EModifierRightCtrl | EModifierCtrl, // 0x  C0
+                EModifierRightShift | EModifierShift, // 0x 600
+                EModifierRightAlt | EModifierAlt, // 0x  18
+                EModifierRightFunc | EModifierFunc
+        // 0x3000  (report bit 7)
+            };
+
+    TUint32 result = 0;
+
+    TUint bitPosn = 1;
+    for (TInt i = 0; i < KNumModifierKeys; ++i)
+        {
+        if (iModifiers & bitPosn)
+            {
+            result |= KModifierMask[i];
+            }
+        bitPosn <<= 1;
+        }
+
+    // Lock state:
+
+    if (iLockState & ECapsLock)
+        {
+        result |= EModifierCapsLock; // 0x 4000
+        }
+
+    if (iLockState & ENumLock)
+        {
+        result |= EModifierNumLock; // 0x 8000
+        }
+
+    if (iLockState & EScrollLock)
+        {
+        result |= EModifierScrollLock; // 0x10000
+        }
+
+    // Flag used by the FEP to identify events from the HID keyboard
+    const TUint KHidKeyboardFepFlag = 0x00200000;
+    result |= KHidKeyboardFepFlag;
+
+    return result;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::SetKeyboardLeds
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::SetKeyboardLeds() const
+    {
+    // Not supported at present
+    }
+
+// ----------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::OnKeyRepeat
+// Key repeat call-back:
+//----------------------------------------------------------------------------
+//
+TInt CHidKeyboardDriver::OnKeyRepeat()
+    {
+    // Send another key-press event:
+    iLastKey.iRepeats = 1;
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::OnKeyRepeat() event [%d, %d, 0x%06x, %d]"),
+                        iLastKey.iCode, iLastKey.iScanCode,
+                        iLastKey.iModifiers, iLastKey.iRepeats));
+    SendToWindowGroup(iLastKey, EEventKey);
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CBTRCCVolumeLevelController::VolumePSChangeTimedoutCallback
+// -----------------------------------------------------------------------------
+//
+TInt CHidKeyboardDriver::TimerFiredOnKeyRepeat(TAny* aThis)
+    {
+    return reinterpret_cast<CHidKeyboardDriver*> (aThis)->OnKeyRepeat();
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::SendKeyPress
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::SendKeyPress(TUint16 aUnicodeKey, TInt aUsagePage,
+        TInt aScanCode, TBool aIsRepeatingKey)
+    {
+
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::SendKeyPress([%d], %d, %d)"),
+                        aUnicodeKey, aScanCode, aIsRepeatingKey));
+
+#ifdef _DEBUG
+    //Please the compiler
+    //TBuf<256> winGroupName;
+    //iWsSession.GetWindowGroupNameFromIdentifier(iWsSession.GetFocusWindowGroup(), winGroupName);
+    //TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver: Focused Window group:<%S>"), winGroupName));
+#endif
+
+    //Number entry to Telephone app is handled differently.
+    if ((IsDigitKey(aScanCode) || IsSpecialHandleKey(aUnicodeKey))
+            && IsPhoneAppTopMost())
+        return;
+
+    TKeyEvent event = TKeyEventFromScanCode(aScanCode);
+    event.iCode = aUnicodeKey;
+
+    if (aIsRepeatingKey)
+        {
+        event.iModifiers |= EModifierAutorepeatable;
+        }
+
+    // Cancel any current key repeat:
+    if (iRepeatTimer->IsActive())
+        {
+        iRepeatTimer->Cancel();
+        }
+
+    // Send the key press event:
+
+    const TInt KConsumerControlPage = 0x0c;
+
+    // Number entry in telephony does not activate unless we send the key event through WindowServer.
+    if (aUsagePage == KConsumerControlPage)
+
+        {
+        // Send media keys using RWsSession::SimulateKeyEvent() so
+        // that the window server "capture key" function will
+        // operate. Note that this means that media keys won't have
+        // standard repeat key functionality because we can't set
+        // the iRepeats member using SimulateKeyEvent().
+        SendToWindowServer(event);
+        }
+    else
+        {
+        //If Chr-key, send '*' to open Special Character Dialog, but not if idle app (telephone).
+        if (event.iCode == EKeyApplication2)
+            {
+                TRACE_FUNC
+            ((_L("[HID]\tCHidKeyboardDriver::SendKeyPress, AltGr pressed")));
+            if (IsPhoneAppTopMost()) //If idle app top-most, don't send '*'.
+                return;
+            event.iCode = '*';
+            event.iScanCode = EStdKeyNkpAsterisk;
+            event.iModifiers = 0;
+            }
+        //If Enter-key, check if AppMenu or Phone/Idle is topmost --> make it Selection key!
+        if (event.iCode == EKeyEnter)
+            {
+            if (IsApplicationMenuTopMost() || IsPhoneAppTopMost())
+                {
+                    TRACE_FUNC
+                ((_L("[HID]\tCHidKeyboardDriver::SendKeyPress, Change enter to selection")));
+                event.iCode = EKeyDevice3;
+                event.iScanCode = EStdKeyDevice3;
+                }
+            }
+
+        // remove other modifiers than autorepeat.
+        if (event.iScanCode == EStdKeyDevice3)
+            {
+            event.iModifiers &= EModifierAutorepeatable;
+            }
+
+        // Send all other keys using RWsSession::SendEventToWindowGroup():
+        SendToWindowGroup(event, EEventKey);
+
+        // Set up a key repeat timer, if necessary:
+        if (aIsRepeatingKey)
+            {
+            iLastKey = event;
+            TTimeIntervalMicroSeconds32 KDefaultDelay = KKeyRepeatDelay;
+            TTimeIntervalMicroSeconds32 KDefaultRate = KKeyRepeatInterval;
+            iRepeatTimer->Start(KDefaultDelay, KDefaultRate, TCallBack(
+                    CHidKeyboardDriver::TimerFiredOnKeyRepeat, this));
+            if (!iRepeatEndTimer->IsActive())
+                {
+                DBG(RDebug::Print(_L("[HID]\tCHidKeyboardDriver::SendKeyPress, start repeat ending timer")));
+                iRepeatEndTimer->After(KRepeatEndTimeout);
+                }
+            }
+        }
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::IsPhoneAppTopMost
+// Check if Application Menu is the active application receiving the key presses
+//----------------------------------------------------------------------------
+//
+TBool CHidKeyboardDriver::IsApplicationMenuTopMost()
+    {
+    TBool ret = EFalse;
+    if (iAppMenuId == KErrNotFound) //was not found earlier in Constructor (WKB app launched at boot)
+        iAppMenuId = AppMenuId(); //if in constructor the AppMenu was not active, then ask is it now
+    TInt focusedId = iWsSession.GetFocusWindowGroup();
+    if (focusedId == iAppMenuId)
+        ret = ETrue;
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::IsApplicationMenuTopMost(): %d"), ret ));
+    return ret;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::IsPhoneAppTopMost
+//----------------------------------------------------------------------------
+//
+TBool CHidKeyboardDriver::IsPhoneAppTopMost()
+    {
+    TBool ret = EFalse;
+    if (iPhoneAppId == KErrNotFound) //was not found earlier in Constructor (WKB app launched at boot)
+        iPhoneAppId = PhoneAppId(); //if in constructor the AppMenu was not active, then ask is it now
+    if (iIdleAppId == KErrNotFound)
+        iIdleAppId = IdleAppId();
+
+    TInt focusedId = iWsSession.GetFocusWindowGroup();
+    if (focusedId == iPhoneAppId || focusedId == iIdleAppId) //KPhoneIdleViewUid || focusedId == KIdleAppUid)
+        ret = ETrue;
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::IsPhoneAppTopMost(): %d"), ret ));
+    return ret;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::AppMenuId
+//----------------------------------------------------------------------------
+//
+TInt CHidKeyboardDriver::AppMenuId()
+    {
+    TApaTaskList taskList(iWsSession);
+    TApaTask task = taskList.FindApp(TUid::Uid(KMenuAppUid));
+    TInt Id = task.WgId();
+    DBG(if (KErrNotFound == Id) RDebug::Print(_L("[HID]\tCHidKeyboardDriver::AppMenuId(): Menu not found!")));
+
+    return Id;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::PhoneAppId
+//----------------------------------------------------------------------------
+//
+TInt CHidKeyboardDriver::PhoneAppId()
+    {
+
+    TApaTaskList taskList(iWsSession);
+    TApaTask task = taskList.FindApp(TUid::Uid(KPhoneAppUid));
+    TInt Id = task.WgId();
+    DBG(if (KErrNotFound == Id) RDebug::Print(_L("[HID]\tCHidKeyboardDriver::PhoneAppId(): Phone not found!")));
+
+    return Id;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::IdleAppId
+//----------------------------------------------------------------------------
+//
+TInt CHidKeyboardDriver::IdleAppId()
+    {
+    TApaTaskList taskList(iWsSession);
+    TApaTask task = taskList.FindApp(TUid::Uid(KIdleAppUid));
+    TInt Id = task.WgId();
+    DBG(if (KErrNotFound == Id) RDebug::Print(_L("[HID]\tCHidKeyboardDriver::IdleAppId(): Idle not found!")));
+
+    return Id;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::SendToWindowServer
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::SendToWindowServer(TKeyEvent aKeyEvent)
+    {
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::SendToWindowServer, event: kc 0x%08x, sc 0x%08x, mod 0x%06x, rep %d]"),
+                        aKeyEvent.iCode, aKeyEvent.iScanCode,
+                        aKeyEvent.iModifiers, aKeyEvent.iRepeats));
+
+    // Prevent the window server generating key repeats as we do this ourselves
+    aKeyEvent.iModifiers &= ~EModifierAutorepeatable;
+    iWsSession.SimulateKeyEvent(aKeyEvent);
+    iWsSession.Flush();
+        TRACE_FUNC
+    ((_L("[HID]\tCHidKeyboardDriver::SendToWindowServer, Event sent!")));
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::SendToWindowGroup
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::SendToWindowGroup(const TKeyEvent& aKeyEvent,
+        TEventCode aType)
+    {
+
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::SendToWindowGroup, Event: type %d, kc 0x%08x, sc 0x%08x, mod 0x%06x, rep %d]"),
+                        aType, aKeyEvent.iCode, aKeyEvent.iScanCode,
+                        aKeyEvent.iModifiers, aKeyEvent.iRepeats));
+
+    // Using RWsSession::SendEventToWindowGroup() bypasses the normal
+    // key handling in the window server, and so capture keys don't
+    // work.  Therefore we check for the known captured keys in
+    // WindowGroupForKeyEvent().
+
+    TInt wGroup = WindowGroupForKeyEvent(aKeyEvent, aType);
+
+    if (0 < wGroup)
+        {
+            TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::SendToWindowGroup: Send event to window group %d"), wGroup));
+
+        TWsEvent event;
+
+        event.SetType(aType);
+        event.SetHandle(0);
+
+        *(event.Key()) = aKeyEvent;
+
+        // Remove shift modifiers from call key events because
+        // the phone application ignores them otherwise
+        //
+        if (EStdKeyYes == aKeyEvent.iScanCode || EStdKeyNo
+                == aKeyEvent.iScanCode)
+            {
+            event.Key()->iModifiers &= ~(EModifierLeftShift
+                    | EModifierRightShift | EModifierShift);
+            }
+
+        // don't send ctrl and shift keys.
+        if (EStdKeyLeftShift != aKeyEvent.iScanCode && EStdKeyRightShift
+                != aKeyEvent.iScanCode && EStdKeyLeftCtrl
+                != aKeyEvent.iScanCode && EStdKeyRightCtrl
+                != aKeyEvent.iScanCode)
+            {
+            iWsSession.SendEventToWindowGroup(wGroup, event);
+            iWsSession.Flush();
+                TRACE_FUNC
+            ((_L("[HID]\tCHidKeyboardDriver::SendToWindowGroup: Event sent!")));
+            }
+        else
+            TRACE_FUNC
+        ((_L("[HID]\tCHidKeyboardDriver::SendToWindowGroup: Shift or ctrl not sent!")));
+
+        }
+
+    // Keypresses should reset the backlight timer:
+    User::ResetInactivityTime();
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::WindowGroupForKeyEvent
+// Determine which window group a key event should be sent to.
+// Except for special cases this is the window group with the focus.
+//----------------------------------------------------------------------------
+//
+TInt CHidKeyboardDriver::WindowGroupForKeyEvent(const TKeyEvent& aKeyEvent,
+        TEventCode aType)
+    {
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::WindowGroupForKeyEvent: type %d, kc 0x%08x, sc 0x%08x, mod 0x%06x, rep %d]"),
+                        aType, aKeyEvent.iCode, aKeyEvent.iScanCode,
+                        aKeyEvent.iModifiers, aKeyEvent.iRepeats));
+    _LIT(KBackDrop, "*EiksrvBackdrop*");
+
+    if (EStdKeyApplication0 == aKeyEvent.iScanCode && (EEventKeyDown == aType
+            || EEventKeyUp == aType))
+        {
+        // Application key up/down events go to the Eikon server
+        // Use this old way for application key
+        TInt result = iWsSession.FindWindowGroupIdentifier(0, KBackDrop); //This was in A2.x __EIKON_SERVER_NAME
+        DBG(if (KErrNotFound == result) RDebug::Print(_L("[HID]\tCHidKeyboardDriver::WindowGroupForKeyEvent(): BackDropWindowGroup Name not found!")));
+        return result;
+        }
+
+    if (EKeyDevice2 == aKeyEvent.iCode && EEventKey == aType)
+        {
+        // Power key press events go to SysAp
+        TApaTaskList taskList( iWsSession );
+        TApaTask task = taskList.FindApp( TUid::Uid( KSysApUid ) );
+        TInt result = task.WgId();
+        DBG(if (KErrNotFound == result) RDebug::Print(_L("[HID]\tCHidKeyboardDriver::WindowGroupForKeyEvent(): SysApWindowGroup Name not found!")))
+        ;
+        return result;
+        }
+
+    if (EStdKeyNo == aKeyEvent.iScanCode
+            && (EEventKeyDown == aType || EEventKeyUp == aType))
+        {
+        // End key up/down events go to the phone app
+        TApaTaskList taskList( iWsSession );
+        TApaTask task = taskList.FindApp( TUid::Uid( KPhoneAppUid ) );
+        TInt result = task.WgId();
+        DBG(if (KErrNotFound == result) RDebug::Print(_L("[HID]\tCHidKeyboardDriver::WindowGroupForKeyEvent(): PhoneAppWindowGroup Name not found!")))
+        ;
+        return result;
+        }
+
+    // All other key events go to the window group with the keyboard focus
+    return iWsSession.GetFocusWindowGroup();
+    }
+
+// ----------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::ResetArrayToSize
+//----------------------------------------------------------------------------
+//
+TInt CHidKeyboardDriver::ResetArrayToSize(RArray<TInt>& aArray, TInt aSize)
+    {
+    TInt err = KErrNone;
+
+    aArray.Reset();
+
+    for (TInt i = 0; !err && (i < aSize); ++i)
+        {
+        err = aArray.Append(0);
+        }
+
+    return err;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::CanHandleReportL
+//----------------------------------------------------------------------------
+//
+TInt CHidKeyboardDriver::CanHandleReportL(CReportRoot* aReportRoot)
+    {
+        TRACE_INFO( (_L("[HID]\tCHidKeyboard::CanHandleReport(0x%08x)"),
+                        aReportRoot));
+    iSupportedFieldCount = 0;
+    // Look for keyboard reports:
+
+    THidFieldSearch search;
+
+    TKeyboardFinder finder;
+    search.SearchL(aReportRoot, &finder);
+    iField[EStandardKeys] = finder.StandardKeyField();
+    iField[EModifierKeys] = finder.ModifierKeyField();
+    iLedField = finder.LedField();
+
+    TConsumerKeysFinder mmFinder;
+    search.SearchL(aReportRoot, &mmFinder);
+    iField[EMediaKeys] = mmFinder.ConsumerKeysField();
+
+    TPowerKeysFinder pwrFinder;
+    search.SearchL(aReportRoot, &pwrFinder);
+    iField[EPowerKeys] = pwrFinder.PowerKeysField();
+
+    for (TInt i = 0; i < KNumInputFieldTypes; ++i)
+        {
+        if (iField[i])
+            {
+            iSupportedFieldCount++;
+            User::LeaveIfError(ResetArrayToSize(iKeys[i], iField[i]->Count()));
+            }
+        }
+
+    TInt valid = KErrHidUnrecognised;
+
+    // We only require standard and modifier key reports; the
+    // LED and consumer keys are optional:
+
+    if ((iField[EStandardKeys] != 0) && (iField[EModifierKeys] != 0))
+        {
+        valid = KErrNone;
+        }
+
+    TMouseFinder mousefinder;
+    search.SearchL(aReportRoot, &mousefinder);
+    iMouseField[EMouseButtons] = mousefinder.ButtonsField();
+    iMouseField[EMouseXY] = mousefinder.XYField();
+    iMouseField[EMouseWheel] = mousefinder.WheelField();
+
+    if ((iMouseField[EMouseButtons] != 0) && (iMouseField[EMouseXY] != 0))
+        {
+        iComboDevice = ETrue;
+        }
+
+        TRACE_INFO( (
+                        _L("CHidKeyboard::CanHandleReport() returning %d"), valid));
+
+    return valid;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::HandleApplicationLaunchKeysL
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::HandleApplicationLaunchKeysL(TUint16 aScancodeKey,
+        TBool aIsKeyDown, TUint8 aHIDModifiers)
+    {
+    // Note that aHIDModifier is not Symbian Modifier bits, but in below format: (from HID spec)
+    /*    const TUint32 KModifierMask[KNumModifierKeys] =
+     {
+     EModifierLeftCtrl   | EModifierCtrl,   // 0x  A0  (report bit 0)
+     EModifierLeftShift  | EModifierShift,  // 0x 500       
+     EModifierLeftAlt    | EModifierAlt,    // 0x  14
+     EModifierLeftFunc   | EModifierFunc,   // 0x2800
+     EModifierRightCtrl  | EModifierCtrl,   // 0x  C0
+     EModifierRightShift | EModifierShift,  // 0x 600
+     EModifierRightAlt   | EModifierAlt,    // 0x  18
+     EModifierRightFunc  | EModifierFunc    // 0x3000  (report bit 7)
+     };
+     */
+    const TUint KHIDModifierAlt = 0x04;
+
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::HandleApplicationLaunchKeys: scancode 0x%08x, HIDmodifiers 0x%08x"), aScancodeKey, aHIDModifiers));
+
+    switch (aScancodeKey)
+        {
+        // Alt-m launches MultimediaMenu
+        case 'm':
+        case 'M':
+            {
+            if (aHIDModifiers & KHIDModifierAlt)
+                {
+                    TRACE_FUNC
+                ((_L("Launch multimediamenu")));
+                //LaunchApplicationL( KMultimediaMenuUid );
+                TInt err = SendRawEvent(EStdKeyApplication6, aIsKeyDown, 0);
+                if (KErrNone != err)
+                    {
+                        TRACE_FUNC
+                    ((_L("[HID]\t    Event sending failed")));
+                    }
+                }
+            break;
+            }
+
+            // Alt-n launches ActiveNotes
+        case 'n':
+        case 'N':
+            {
+            if (aHIDModifiers & KHIDModifierAlt)
+                {
+                    TRACE_FUNC
+                ((_L("[HID]\t   Launch active notes")));
+                LaunchApplicationL(KActiveNotesUid);
+                }
+            break;
+            }
+        case EStdKeyF1:
+            {
+            DBG(RDebug::Print(_L("[HID]\t   Launch Web service")));
+            LaunchApplicationL(KServicesUid);
+            }
+            break;
+        case EStdKeyF2:
+            {
+            DBG(RDebug::Print(_L("[HID]\t   Launch messages")));
+            LaunchApplicationL(KMessagingUid);
+            }
+            break;
+        default:
+            break;
+        }
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::LaunchApplicationL
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::LaunchApplicationL(TInt aAppUid)
+    {
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::LaunchApplication: UID 0x%08x"), aAppUid));
+
+    TApaTaskList taskList(iWsSession);
+    TUid uid = TUid::Uid(aAppUid);
+    TApaTask task = taskList.FindApp(uid);
+    if (task.Exists())
+        {
+        // Application is active, so just bring to foreground
+        task.BringToForeground();
+        }
+    else
+        {
+        RApaLsSession appArcSession;
+        // connect to AppArc server
+        User::LeaveIfError(appArcSession.Connect());
+
+        CleanupClosePushL(appArcSession);
+
+        TThreadId threadID;
+
+        // Launch the application with no params.
+        User::LeaveIfError(appArcSession.StartDocument(KNullDesC, uid,
+                threadID));
+
+        CleanupStack::Pop(1); // appArcSession
+
+        appArcSession.Close();
+        }
+
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::HandleNokiaMultimediaKeys
+// Takes some Multimedia keyevents from HID and converts them to Nokia raw events format
+// to simulate as if the key presses came from phone keypad (volume +/-, play, pause, frwd, rewind)
+//
+// This is temporary solution that shall be replaced by "proper" RemCon Bearer solution.
+// Because the keycodes used here may change in future terminal!
+// Note that aHIDModifier is not Symbian Modifier bits, but in below format: (from HID spec)
+//    const TUint32 KModifierMask[KNumModifierKeys] =
+//        {
+//        EModifierLeftCtrl   | EModifierCtrl,   // 0x  A0  (report bit 0)
+//        EModifierLeftShift  | EModifierShift,  // 0x 500
+//        EModifierLeftAlt    | EModifierAlt,    // 0x  14
+//        EModifierLeftFunc   | EModifierFunc,   // 0x2800
+//        EModifierRightCtrl  | EModifierCtrl,   // 0x  C0
+//        EModifierRightShift | EModifierShift,  // 0x 600
+//        EModifierRightAlt   | EModifierAlt,    // 0x  18
+//        EModifierRightFunc  | EModifierFunc    // 0x3000  (report bit 7)
+//        };
+//----------------------------------------------------------------------------
+//
+
+TBool CHidKeyboardDriver::HandleMultimediaKeys(TUint16 aScancodeKey,
+        TBool aIsKeyDown, TUint8 aHIDModifiers)
+    {
+    TBool ret = HandleMultimediaKeysForNokia(aScancodeKey, aIsKeyDown,
+            aHIDModifiers);
+
+    if (!ret)
+        {
+        ret = HandleMultimediaKeysForStandard(aScancodeKey, aIsKeyDown,
+                aHIDModifiers);
+        }
+    return ret;
+    }
+
+void CHidKeyboardDriver::ResetBitmap(TBool aIsKeyDown,
+        TMmKeyDown aBitmapToReset)
+    {
+    if (aIsKeyDown)
+        {
+        iMmKeyDown = (iMmKeyDown | aBitmapToReset);
+        }
+    else
+        {
+        iMmKeyDown = (iMmKeyDown & !aBitmapToReset);
+        }
+    }
+
+TBool CHidKeyboardDriver::HandleMultimediaKeysForNokia(TUint16 aScancodeKey,
+        TBool aIsKeyDown, TUint8 aHIDModifiers)
+    {
+    const TUint KHidModifierCtrl = 0x01;
+    const TUint KHidModifierCtrlRight = 0x10;
+    const TUint KHidModifierAlt = 0x04;
+
+    //	const TUint KHidModifierAltGr = 0x64;
+    TInt scancode = 0;
+    TUint modifier = 0;
+    TBool isMmKey = EFalse;
+
+    TMmKeyDown bitmapToReset;
+
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::HandleNokiaMultimediaKeys: scancode 0x%08x, HIDmodifiers 0x%08x"), aScancodeKey, aHIDModifiers));
+
+    switch (aScancodeKey)
+        {
+
+        // Mappings for Nokia SU-8W
+        // Key down events are stored into bitmap in order to detect if keys are released in reverse order, which caused jamming.
+        // For example: control key released before arrow key.
+
+        case EStdKeyUpArrow:
+            {
+            if (aHIDModifiers & (KHidModifierCtrl | KHidModifierCtrlRight)
+                    || iMmKeyDown & EVolUp)
+                {
+                scancode = EStdKeyIncVolume; //Volume Up = Ctrl + ArrowUp
+                isMmKey = ETrue;
+                // Set or reset flag bit
+
+                bitmapToReset = EVolUp;
+                    TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::HandleNokiaMultimediaKeys: Volume up %d"), aIsKeyDown));
+                }
+            break;
+            }
+
+        case EStdKeyDownArrow:
+            {
+            if (aHIDModifiers & (KHidModifierCtrl | KHidModifierCtrlRight)
+                    || iMmKeyDown & EVolDown)
+                {
+                scancode = EStdKeyDecVolume; //Volume Down = Ctrl + ArrowDown
+                isMmKey = ETrue;
+                bitmapToReset = EVolDown;
+                    TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::HandleNokiaMultimediaKeys: Volume down %d"), aIsKeyDown));
+                }
+            break;
+            }
+
+        case EStdKeyRightArrow:
+            {
+            if (aHIDModifiers & KHidModifierAlt || iMmKeyDown & EPlay)
+                {
+                scancode = EStdKeyApplication2; //Play = Alt + ArrowRight
+                isMmKey = ETrue;
+                bitmapToReset = EPlay;
+
+                    TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::HandleNokiaMultimediaKeys: Play %d"), aIsKeyDown));
+                }
+            else if (aHIDModifiers & (KHidModifierCtrl
+                    | KHidModifierCtrlRight) || iMmKeyDown & ENext)
+                {
+                scancode = EStdKeyApplication4; //Next = Ctrl + ArrowRight
+                isMmKey = ETrue;
+                bitmapToReset = ENext;
+                    TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::HandleNokiaMultimediaKeys: Next %d"), aIsKeyDown));
+                }
+            break;
+            }
+
+        case EStdKeyLeftArrow:
+            {
+            if (aHIDModifiers & KHidModifierAlt || iMmKeyDown & EStop)
+                {
+                scancode = EStdKeyApplication3; //Stop	= Alt + ArrowLeft
+                isMmKey = ETrue;
+                bitmapToReset = EStop;
+                    TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::HandleNokiaMultimediaKeys: Stop %d"), aIsKeyDown));
+                }
+            else if (aHIDModifiers & (KHidModifierCtrl
+                    | KHidModifierCtrlRight) || iMmKeyDown & EPrev)
+                {
+                scancode = EStdKeyApplication5; //Prev	= Ctrl + ArrowLeft
+                isMmKey = ETrue;
+                bitmapToReset = EPrev;
+                    TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::HandleNokiaMultimediaKeys: Prev %d"), aIsKeyDown));
+                }
+            break;
+            }
+
+        default:
+            break;
+        }
+
+    if (isMmKey)
+        {
+        ResetBitmap(aIsKeyDown, bitmapToReset);
+        SendRawEvent(scancode, aIsKeyDown, modifier);
+        }
+    return isMmKey;
+    }
+
+TBool CHidKeyboardDriver::HandleMultimediaKeysForStandard(
+        TUint16 aScancodeKey, TBool aIsKeyDown, TUint8 aHIDModifiers)
+    {
+    TInt scancode = 0;
+    TUint modifier = 0;
+    TBool isMmKey = EFalse;
+
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::HandleNokiaMultimediaKeys: scancode 0x%08x, HIDmodifiers 0x%08x"), aScancodeKey, aHIDModifiers));
+    //please complier...
+    (void) aHIDModifiers;
+
+    switch (aScancodeKey)
+        {
+        // Mappings for standard keyboards
+
+        case EStdKeyApplication2: //Play
+            {
+            scancode = EStdKeyApplication2;
+            isMmKey = ETrue;
+                TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::HandleNokiaMultimediaKeys: Play %d"), aIsKeyDown));
+            break;
+            }
+
+        case EStdKeyApplication3: //Stop
+            {
+            scancode = EStdKeyApplication3;
+            isMmKey = ETrue;
+                TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::HandleNokiaMultimediaKeys: Stop %d"), aIsKeyDown));
+            break;
+            }
+
+        case EStdKeyApplication4: //Next
+            {
+            scancode = EStdKeyApplication4;
+            isMmKey = ETrue;
+                TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::HandleNokiaMultimediaKeys: Next %d"), aIsKeyDown));
+            break;
+            }
+
+        case EStdKeyApplication5: //Prev
+            {
+            scancode = EStdKeyApplication5;
+            isMmKey = ETrue;
+                TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::HandleNokiaMultimediaKeys: Prev %d"), aIsKeyDown));
+            break;
+            }
+
+        case EStdKeyIncVolume: //Volume up
+            {
+            scancode = EStdKeyIncVolume;
+            isMmKey = ETrue;
+                TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::HandleNokiaMultimediaKeys: Volume up %d"), aIsKeyDown));
+            break;
+            }
+
+        case EStdKeyDecVolume: //Volume down
+            {
+            scancode = EStdKeyDecVolume;
+            isMmKey = ETrue;
+                TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::HandleNokiaMultimediaKeys: Volume down %d"), aIsKeyDown));
+            break;
+            }
+
+        default:
+            break;
+        }
+
+    if (isMmKey)
+        {
+        SendRawEvent(scancode, aIsKeyDown, modifier);
+        }
+    return isMmKey;
+    }
+
+// ----------------------------------------------------------------------
+// CHidKeyboardDriver::SendRawEvent
+// Send raw key event to window server
+// ----------------------------------------------------------------------
+TInt CHidKeyboardDriver::SendRawEvent(TInt aScancode, TBool aIsKeyDown,
+        TUint aModifier)
+    {
+    TRawEvent rawEvent;
+    TInt err = KErrNone;
+
+        TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::SendRawEvent: scancode %d, modifier: %d, keydown: %d"), aScancode, aModifier, aIsKeyDown ));
+    if (aScancode != 0)
+        {
+        if (aIsKeyDown)
+            rawEvent.Set(TRawEvent::EKeyDown, aScancode);
+        else
+            rawEvent.Set(TRawEvent::EKeyUp, aScancode); //This will never be called for +,* and #
+
+        TEventModifier eventmodifier = (TEventModifier) -1; //all bits set to 1.
+        TModifierState modifierstate = (TModifierState) aModifier;
+            TRACE_INFO( (_L("[HID]\tCHidKeyboardDriver::SendRawEvents: modifiers %d, modifierState: %d"), aModifier, (TUint)modifierstate));
+
+        err = iWsSession.SetModifierState(eventmodifier, modifierstate);
+        iWsSession.SimulateRawEvent(rawEvent);
+        iWsSession.Flush();
+        }
+    return err;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::SupportedFieldCount
+//----------------------------------------------------------------------------
+//
+TInt CHidKeyboardDriver::SupportedFieldCount()
+    {
+    return iSupportedFieldCount;
+    }
+
+//----------------------------------------------------------------------------
+// CHidKeyboardDriver::SetInputHandlingReg
+//----------------------------------------------------------------------------
+//
+void CHidKeyboardDriver::SetInputHandlingReg(
+        CHidInputDataHandlingReg* aHandlingReg)
+    {
+    iInputHandlingReg = aHandlingReg;
+    }
+
+// ----------------------------------------------------------------------
+// CHidKeyboardDriver::TimerExpired
+// Callback function from CTimeOutTimer
+// ----------------------------------------------------------------------
+void CHidKeyboardDriver::TimerExpired()
+    {
+    DBG(RDebug::Print(_L("[HID]\tCHidKeyboardDriver::TimerExpired, cancel all key presses")));
+    CancelAllKeys();
+    }
+
+// End of file