bluetoothengine/bthid/manager/src/decode.cpp
changeset 0 f63038272f30
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothengine/bthid/manager/src/decode.cpp	Mon Jan 18 20:28:57 2010 +0200
@@ -0,0 +1,265 @@
+/*
+* Copyright (c) 2008 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 <ecom/ecom.h>
+#include "modifier.h"
+#include "layout.h"
+#include "decode.h"
+#include "codestore.h"
+#include "client.h"
+#include "debug.h"
+#include "hidvalues.h"
+
+// ----------------------------------------------------------------------
+
+CKeyboardDecoder::CKeyboardDecoder()
+        : iLayout(0), iAltGrSequence(EFalse), iNumKeysDown(0)
+    {
+    TRACE_INFO( (
+                    _L("[HID]\tCKeyboardDecoder::CKeyboardDecoder at 0x%08x"), this));
+    }
+
+CKeyboardDecoder* CKeyboardDecoder::NewL()
+    {
+    CKeyboardDecoder* self =
+        new (ELeave) CKeyboardDecoder;
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop();
+    return self;
+    }
+
+void CKeyboardDecoder::ConstructL()
+    {
+    iScanCodes = CScanCodeStore::NewL();
+    }
+
+CKeyboardDecoder::~CKeyboardDecoder()
+    {
+    TRACE_INFO( (_L("[HID]\t~CKeyboardDecoder() 0x%08x"), this));
+
+    iLayout = 0; // (we don't own iLayout)
+
+    delete iScanCodes;
+    }
+
+// ----------------------------------------------------------------------
+
+void CKeyboardDecoder::Event(const TKeyEventInfo &aEvent,
+                             TDecodedKeyInfo& aDecodedKeys)
+    {
+    aDecodedKeys.iCount = 0;
+    aDecodedKeys.iScanCode = EStdKeyNull;
+
+    iNumKeysDown += (aEvent.iIsKeyDown ? 1 : -1);
+    // (NB. it is possible to get an up without a down just after a new
+    // decoder goes into use when the keyboard layout is changed -- but
+    // only if the Bluetooth keyboard is used to make the layout change.)
+    if (iNumKeysDown < 0)
+        iNumKeysDown = 0;
+
+    if (iLayout)
+        {
+        if (!HandleRightAlt(aEvent, aDecodedKeys))
+            {
+            if (aEvent.iIsKeyDown)
+                {
+                // Key down event:
+
+                TInt rawCode = iLayout->RawScanCode(aEvent.iHidKey,
+                                                    aEvent.iUsagePage, aEvent.iModifiers);
+
+                // Store the raw scan code, so that the scan code for
+                // the "key up" event for this key will match the one
+                // sent for the "key down" event.  These could be
+                // different, for example, if the scan code changes
+                // depending on the current modifier state.
+                //
+                if (iScanCodes->Store(aEvent.iHidKey, aEvent.iUsagePage,
+                                      rawCode) == KErrNone)
+                    {
+                    aDecodedKeys.iScanCode = rawCode;
+                    }
+                else
+                    {
+                    // Store() may fail due to low memory. In that
+                    // case we don't send key down (or key up) events:
+                    //
+                    aDecodedKeys.iScanCode = EStdKeyNull;
+                    }
+
+                // Decode any key press events:
+
+                TUint16 unicodeKey = iLayout->TranslateKey(aEvent.iHidKey,
+                                     aEvent.iUsagePage, aEvent.iModifiers, aEvent.iLockKeys);
+
+                if (unicodeKey != 0)
+                    {
+                    ProcessDeadKeys(unicodeKey, aEvent.iHidKey,
+                                    aEvent.iUsagePage, aDecodedKeys);
+                    }
+                }
+            else
+                {
+                // Key up event:
+
+                aDecodedKeys.iScanCode =
+                    iScanCodes->Retrieve(aEvent.iHidKey, aEvent.iUsagePage);
+                }
+            }
+        }
+    }
+
+// ----------------------------------------------------------------------
+
+TBool CKeyboardDecoder::HandleRightAlt(const TKeyEventInfo &aEvent,
+                                       TDecodedKeyInfo& aDecodedKeys)
+    {
+    // A press and release of the right-alt (Alt Gr) key should cause
+    // the S60 symbol selection dialog to appear, if no other keys are
+    // pressed in between.
+
+    TBool handledEvent = EFalse;
+
+    const TInt KRightAltKey = 0xe6;
+
+    if ((aEvent.iHidKey == KRightAltKey) &&
+            (aEvent.iUsagePage == EUsagePageKeyboard))
+        {
+        if (aEvent.iIsKeyDown && (iNumKeysDown == 1))
+            {
+            iAltGrSequence = ETrue;
+            }
+
+        if (!aEvent.iIsKeyDown && iAltGrSequence)
+            {
+            // We use EKeyApplication2 to indicate to the modified T9
+            // FEP that we wish it to produce the symbol selection dialog:
+            // EKeyApplication2 is not passed to Fep anymore, but
+            // it is converted to '*' in SendKeyPress() (keyboard.cpp)
+            aDecodedKeys.iEvent[0] = TTranslatedKey(EKeyApplication2,
+                                                    EStdKeyApplication2, 0, 0, EFalse);
+            aDecodedKeys.iCount = 1;
+
+            handledEvent = ETrue;
+            iAltGrSequence = EFalse;
+            }
+        }
+    else
+        {
+        iAltGrSequence = EFalse;
+        }
+
+    return handledEvent;
+    }
+
+// ----------------------------------------------------------------------
+
+void CKeyboardDecoder::Reset()
+    {
+    iDeadKey.iUnicode = 0;
+    iAltGrSequence = EFalse;
+    iNumKeysDown = 0;
+    }
+
+// ----------------------------------------------------------------------
+
+void CKeyboardDecoder::SetLayout(CKeyboardLayout* aLayout)
+    {
+    TRACE_INFO( (_L("[HID]\tCKeyboardDecoder::SetLayout(0x%08x)"), aLayout));
+
+    iLayout = aLayout;
+    Reset();
+    }
+
+// ----------------------------------------------------------------------
+
+void CKeyboardDecoder::ProcessDeadKeys(TUint16 aUnicodeKey,
+                                       TInt aHidKey, TInt aUsagePage, TDecodedKeyInfo &aDecodedKeys)
+    {
+    if (iDeadKey.iUnicode == 0)
+        {
+        // Check if the current key is a dead key:
+        //
+        if (iLayout->IsDeadKey(aUnicodeKey))
+            {
+            // We've received a dead key event, so there's no key press
+            // to issue -- just record the details for later:
+            //
+            TRACE_INFO( (_L("[HID]\tDeadkey 0x%04x (%d:%d)"),
+                         aUnicodeKey, aUsagePage, aHidKey));
+
+            iDeadKey = TTranslatedKey(aUnicodeKey,
+                                      aDecodedKeys.iScanCode, aHidKey, aUsagePage, EFalse);
+            aDecodedKeys.iCount = 0;
+            }
+        else
+            {
+            // No dead key processing to do, so just send a
+            // normal key code:
+            //
+            TRACE_INFO( (_L("[HID]\tNo dead key processing, one event")));
+
+            aDecodedKeys.iEvent[0] = TTranslatedKey(aUnicodeKey,
+                                                    aDecodedKeys.iScanCode, aHidKey, aUsagePage,
+                                                    iLayout->IsRepeatingKey(aUnicodeKey));
+            aDecodedKeys.iCount = 1;
+            }
+        }
+    else
+        {
+        // We've an active dead key, see if the current key produces
+        // a combination character:
+        //
+        TUint16 comboChar =
+            iLayout->FindCombiningChar(iDeadKey.iUnicode, aUnicodeKey);
+
+        if (comboChar == 0)
+            {
+            TRACE_INFO( (_L("[HID]\tNo match for 0x%04x, sending after 0x%04x"),
+                         aUnicodeKey, iDeadKey.iUnicode));
+
+            // No match, so two key events to send:
+
+            aDecodedKeys.iEvent[0] = iDeadKey;
+            aDecodedKeys.iEvent[1] = TTranslatedKey(aUnicodeKey,
+                                                    aDecodedKeys.iScanCode, aHidKey, aUsagePage,
+                                                    iLayout->IsRepeatingKey(aUnicodeKey));
+            aDecodedKeys.iCount = 2;
+            }
+        else
+            {
+            TRACE_INFO( (_L("[HID]\tFound a match 0x%04x, one combo to send 0x%04x"),
+                         aUnicodeKey, comboChar));
+
+            // Found a match, so one combo key event to send:
+
+            aDecodedKeys.iEvent[0] = TTranslatedKey(comboChar,
+                                                    aDecodedKeys.iScanCode, aHidKey, aUsagePage,
+                                                    iLayout->IsRepeatingKey(comboChar));
+            aDecodedKeys.iCount = 1;
+            }
+
+        // We've finished processing the dead key sequence:
+        iDeadKey.iUnicode = 0;
+        }
+    }
+
+// ----------------------------------------------------------------------