bluetoothengine/bthid/layouts/src/layout.cpp
changeset 0 f63038272f30
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothengine/bthid/layouts/src/layout.cpp	Mon Jan 18 20:28:57 2010 +0200
@@ -0,0 +1,624 @@
+/*
+* 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 <e32keys.h>
+#include <coedef.h>   // for CTRL()
+
+//#include "hidkeys.h"   // included from decode.h
+#include "layout.h"
+#include "decode.h"
+#include "modifier.h"
+#include "hiddebug.h"
+
+#include "hidvalues.h"
+
+// ----------------------------------------------------------------------
+// Map HID keyboard usage values (usage page 7) to EPOC raw "scan" codes:
+
+const TInt CKeyboardLayout::KRawCodes[] = 
+    {
+    EStdKeyNull,               // 0x00  0   No Event
+    EStdKeyNull,               // 0x01  1   Overrun Error
+    EStdKeyNull,               // 0x02  2   POST Fail
+    EStdKeyNull,               // 0x03  3   ErrorUndefined
+    'A',                       // 0x04  4   a A
+    'B',                       // 0x05  5   b B
+    'C',                       // 0x06  6   c C
+    'D',                       // 0x07  7   d D
+    'E',                       // 0x08  8   e E
+    'F',                       // 0x09  9   f F
+    'G',                       // 0x0A  10  g G
+    'H',                       // 0x0B  11  h H
+    'I',                       // 0x0C  12  i I
+    'J',                       // 0x0D  13  j J
+    'K',                       // 0x0E  14  k K
+    'L',                       // 0x0F  15  l L
+    'M',                       // 0x10  16  m M
+    'N',                       // 0x11  17  n N
+    'O',                       // 0x12  18  o O
+    'P',                       // 0x13  19  p P
+    'Q',                       // 0x14  20  q Q
+    'R',                       // 0x15  21  r R
+    'S',                       // 0x16  22  s S
+    'T',                       // 0x17  23  t T
+    'U',                       // 0x18  24  u U
+    'V',                       // 0x19  25  v V
+    'W',                       // 0x1A  26  w W
+    'X',                       // 0x1B  27  x X
+    'Y',                       // 0x1C  28  y Y
+    'Z',                       // 0x1D  29  z Z
+    '1',                       // 0x1E  30  1 !
+    '2',                       // 0x1F  31  2 @
+    '3',                       // 0x20  32  3 #
+    '4',                       // 0x21  33  4 $ Euro
+    '5',                       // 0x22  34  5 %
+    '6',                       // 0x23  35  6 ^
+    '7',                       // 0x24  36  7 &
+    '8',                       // 0x25  37  8 *
+    '9',                       // 0x26  38  9 (
+    '0',                       // 0x27  39  0 )
+    EStdKeyEnter,              // 0x28  40  Return
+    EStdKeyEscape,             // 0x29  41  Escape
+    EStdKeyBackspace,          // 0x2A  42  Backspace
+    EStdKeyTab,                // 0x2B  43  Tab
+    EStdKeySpace,              // 0x2C  44  Space
+    EStdKeyMinus,              // 0x2D  45  - _
+    EStdKeyEquals,             // 0x2E  46  = +
+    EStdKeySquareBracketLeft,  // 0x2F  47  [ {
+    EStdKeySquareBracketRight, // 0x30  48  ] }
+    EStdKeyBackSlash,          // 0x31  49  US backslash and bar
+    EStdKeyHash,               // 0x32  50  Near the enter key (UK #~)
+    EStdKeySemiColon,          // 0x33  51  ; :
+    EStdKeySingleQuote,        // 0x34  52  UK ' @  (US ' ")
+    EStdKeyXXX,                // 0x35  53  Top left: UK grave/not/bar
+    EStdKeyComma,              // 0x36  54  , <
+    EStdKeyFullStop,           // 0x37  55  . >
+    EStdKeyForwardSlash,       // 0x38  56  / ?
+    EStdKeyCapsLock,           // 0x39  57  Caps Lock
+    EStdKeyF1,                 // 0x3A  58  F1
+    EStdKeyF2,                 // 0x3B  59  F2
+    EStdKeyF3,                 // 0x3C  60  F3
+    EStdKeyF4,                 // 0x3D  61  F4
+    EStdKeyF5,                 // 0x3E  62  F5
+    EStdKeyF6,                 // 0x3F  63  F6
+    EStdKeyF7,                 // 0x40  64  F7
+    EStdKeyF8,                 // 0x41  65  F8
+    EStdKeyF9,                 // 0x42  66  F9
+    EStdKeyF10,                // 0x43  67  F10
+    EStdKeyF11,                // 0x44  68  F11
+    EStdKeyF12,                // 0x45  69  F12
+    EStdKeyPrintScreen,        // 0x46  70  Print Screen
+    EStdKeyScrollLock,         // 0x47  71  Scroll Lock
+    EStdKeyPause,              // 0x48  72  Break (Ctrl-Pause)
+    EStdKeyInsert,             // 0x49  73  Insert
+    EStdKeyHome,               // 0x4A  74  Home
+    EStdKeyPageUp,             // 0x4B  75  Page Up
+    EStdKeyDelete,             // 0x4C  76  Delete
+    EStdKeyEnd,                // 0x4D  77  End
+    EStdKeyPageDown,           // 0x4E  78  Page Down
+    EStdKeyRightArrow,         // 0x4F  79  Right Arrow
+    EStdKeyLeftArrow,          // 0x50  80  Left Arrow
+    EStdKeyDownArrow,          // 0x51  81  Down Arrow
+    EStdKeyUpArrow,            // 0x52  82  Up Arrow
+    EStdKeyNumLock,            // 0x53  83  Num Lock
+    EStdKeyNkpForwardSlash,    // 0x54  84  Keypad /
+    EStdKeyNkpAsterisk,        // 0x55  85  Keypad *
+    EStdKeyNkpMinus,           // 0x56  86  Keypad -
+    EStdKeyNkpPlus,            // 0x57  87  Keypad +
+    EStdKeyNkpEnter,           // 0x58  88  Keypad Enter
+    EStdKeyNkp1,               // 0x59  89  Keypad 1 End
+    EStdKeyNkp2,               // 0x5A  90  Keypad 2 Down
+    EStdKeyNkp3,               // 0x5B  91  Keypad 3 PageDn
+    EStdKeyNkp4,               // 0x5C  92  Keypad 4 Left
+    EStdKeyNkp5,               // 0x5D  93  Keypad 5
+    EStdKeyNkp6,               // 0x5E  94  Keypad 6 Right
+    EStdKeyNkp7,               // 0x5F  95  Keypad 7 Home
+    EStdKeyNkp8,               // 0x60  96  Keypad 8 Up
+    EStdKeyNkp9,               // 0x61  97  Keypad 9 PageUp
+    EStdKeyNkp0,               // 0x62  98  Keypad 0 Insert
+    EStdKeyNkpFullStop,        // 0x63  99  Keypad . Delete
+    EStdKeyBackSlash,          // 0x64  100 Next to LH shift (UK \|)
+    EStdKeyMenu,               // 0x65  101 Application key
+    EStdKeyNull,               // 0x66  102 Keyboard power
+    EStdKeyEquals              // 0x67  103 Keypad =
+    };
+
+// ----------------------------------------------------------------------
+
+// These apply in any modifier state:
+
+const CKeyboardLayout::TUsagePageKey CKeyboardLayout::KEnhancedKeyCodes[] = 
+    {
+    // Usage page, usage ID, Symbian raw code, Symbian key code (unicode)
+    //
+    // Generic functionality:
+    // 
+    { 12, 0x00cd, EStdKeyApplication2, EKeyApplication2 }, // Play/pause (was: EKeyDictaphonePlay)
+    { 12, 0x00b7, EStdKeyApplication3, EKeyApplication3 }, // Stop (was: EKeyDictaphoneStop)
+    { 12, 0x00e9, EStdKeyIncVolume,      EKeyIncVolume },      // Volume -
+    { 12, 0x00ea, EStdKeyDecVolume,      EKeyDecVolume },      // Volume +
+    { 12, 0x0095, EStdKeyHelp,           EKeyHelp },           // Help
+    { 12, 0x019c, EStdKeyDevice2,        EKeyDevice2 },        // Log off
+    //
+    // Map system control power and menu keys to the power key:
+    //
+    { 1,  0x0081, EStdKeyDevice2,        EKeyDevice2 },        // Power down
+    { 1,  0x0082, EStdKeyDevice2,        EKeyDevice2 },        // Sleep
+    { 1,  0x0083, EStdKeyDevice2,        EKeyDevice2 },        // Wake
+    { 1,  0x0084, EStdKeyDevice2,        EKeyDevice2 },        // Context menu
+    { 1,  0x0085, EStdKeyDevice2,        EKeyDevice2 },        // Main menu
+    { 1,  0x0086, EStdKeyDevice2,        EKeyDevice2 },        // App menu
+    //
+    // Map common consumer keys to the application and device key ranges:
+    // (Note that Series 60 AVKON reserves device keys 0-6, and app key 0.)
+    // (Also, we're reserving EStdKeyApplication1 for FEP symbol menu)
+    //
+    { 12, 0x00e2, EStdKeyApplication3, EKeyApplication3 }, // Mute				(was: EkeyApplication2)
+    { 12, 0x00b5, EStdKeyApplication4, EKeyApplication4 }, // Next track 	(Was: EKeyApplication3)
+    { 12, 0x00b6, EStdKeyApplication5, EKeyApplication5 }, // Prev track	(was: EKeyApplication4)
+    { 12, 0x021a, EStdKeyApplication5, EKeyApplication5 }, // Undo
+    { 12, 0x0279, EStdKeyApplication6, EKeyApplication6 }, // Redo
+    { 12, 0x0183, EStdKeyApplication7, EKeyApplication7 }, // Media
+    { 12, 0x0223, EStdKeyF1, EKeyF1 					}, // Web/Home [WAP] was: EKeyApplication8
+    { 12, 0x0199, EStdKeyApplication9, EKeyApplication9 }, // Messenger [SMS]
+    { 12, 0x018a, EStdKeyF2, EKeyF2 }, 					   // Mail [Email] was: EKeyApplicationA
+    { 12, 0x0192, EStdKeyApplicationC, EKeyApplicationB }, // Calculator
+    { 12, 0x01ab, EStdKeyApplicationD, EKeyApplicationD }, // Spell
+    { 12, 0x0207, EStdKeyApplicationE, EKeyApplicationE }, // Save
+    { 12, 0x0208, EStdKeyApplicationF, EKeyApplicationF }, // Print
+    { 12, 0x0201, EStdKeyDevice7,      EKeyDevice7 },      // New
+    { 12, 0x0202, EStdKeyDevice8,      EKeyDevice8 },      // Open
+    { 12, 0x0203, EStdKeyDevice9,      EKeyDevice9 },      // Close
+    { 12, 0x0289, EStdKeyDeviceA,      EKeyDeviceA },      // Reply
+    { 12, 0x028b, EStdKeyDeviceB,      EKeyDeviceB },      // Fwd
+    { 12, 0x028C, EStdKeyDeviceC,      EKeyDeviceC },      // Send
+    { 12, 0x01a7, EStdKeyDeviceD,      EKeyDeviceD },      // My Docs [Notepad]
+    { 12, 0x01b6, EStdKeyDeviceE,      EKeyDeviceE },      // My Pics
+    { 12, 0x01b7, EStdKeyDeviceF,      EKeyDeviceF }       // My Music
+    };
+
+// ----------------------------------------------------------------------
+
+ TUint16 CKeyboardLayout::TranslateKey(TInt aHidKey, 
+    TInt aUsagePage, THidModifier aModifiers, TLockKeys aLockKeys) const
+    {
+    if (aUsagePage == EUsagePageKeyboard)
+        {
+        return TranslateKeyboardKey(aHidKey, aModifiers, aLockKeys);
+        }
+    else
+        {
+        return TranslateOtherKey(aHidKey, aUsagePage, aModifiers, aLockKeys);
+        }
+    }
+
+// ----------------------------------------------------------------------
+
+TUint16 CKeyboardLayout::TranslateKeyboardKey(TInt aHidKey, 
+    THidModifier aModifiers, TLockKeys aLockKeys) const
+    {
+    // For most layouts, right alt (AltGr) is defined to have the
+    // same effect as ctrl-alt:
+    //
+    if (AltGrIsControlAlt() && aModifiers.RightAlt())
+        {
+        aModifiers.Merge(THidModifier::ELeftControl);
+        }
+
+    // Caps lock and num lock usually just invert the behaviour of
+    // the shift key:
+    //
+    if ((aLockKeys.iCapsLock && ChangesWithCapsLock(aHidKey, aModifiers)) ||
+        (!aLockKeys.iNumLock && ChangesWithNumLock(aHidKey)))
+        {
+        aModifiers.InvertShift();
+        }
+
+    // All standard layouts avoid control and shift-control modifiers.
+    // We map the standard control and shift-control key combinations
+    // to Symbian shortcut key codes:
+    //
+    TUint16 unicode = 0;
+
+    if (aModifiers.Control() && !aModifiers.Alt())
+        {
+        // Symbian Knowledgebase articles FAQ-0507 and FAQ-0511 say
+        // that this is the correct way to handle control keys so
+        // that keyboard shortcuts (such as ctrl-x) will work:
+        
+        const TInt KCtrlMin = 4;   // aA
+        const TInt KCtrlMax = 29;  // zZ
+            
+        if ((aHidKey >= KCtrlMin) && (aHidKey <= KCtrlMax))
+            {
+            unicode = static_cast<TUint16>(CTRL(
+                Unicode(aHidKey, THidModifier(0))));
+            }
+        }
+
+    // If the key wasn't a standard control or shift-control
+    // combination:
+    // 
+    if (unicode == 0)
+        {
+        unicode = Unicode(aHidKey, aModifiers);
+        }
+
+    return unicode;
+    }
+
+// ----------------------------------------------------------------------
+
+ TBool CKeyboardLayout::ChangesWithCapsLock(TInt aHidKey,
+    THidModifier aModifiers) const
+    {
+    // For most layouts Caps Lock only changes those keys in the
+    // standard A..Z positions:
+    //
+    const TInt KCapsLockKeysMin = 4;   // aA
+    const TInt KCapsLockKeysMax = 29;  // zZ
+
+    TBool inRange = (aHidKey >= KCapsLockKeysMin) && 
+        (aHidKey <= KCapsLockKeysMax);
+
+    // The standard behaviour is that Caps Lock shouldn't have any
+    // effect on alt-ctrl ("Alt Gr") modified keys:
+    //
+    TBool altGr = aModifiers.Control() && aModifiers.Alt();
+
+    return !altGr && inRange;
+    }
+
+// ----------------------------------------------------------------------
+
+ TBool CKeyboardLayout::ChangesWithNumLock(TInt aHidKey) const
+    {
+    // Num Lock only ever affects a standard subset of the keypad keys:
+
+    const TInt KNumLockMin = 89;  // Keypad End
+    const TInt KNumLockMax = 99;  // Keypad Delete
+
+    return (aHidKey >= KNumLockMin) && (aHidKey <= KNumLockMax);
+    }
+
+// ----------------------------------------------------------------------
+
+ TBool CKeyboardLayout::AltGrIsControlAlt() const
+    {
+    return ETrue;
+    }
+
+// ----------------------------------------------------------------------
+
+ TBool CKeyboardLayout::IsDeadKey(TInt /*aUnicodeKey*/) const
+    {
+    return EFalse;
+    }
+
+ TUint16 CKeyboardLayout::FindCombiningChar(
+    TUint16 /*aDeadKeyUnicode*/, TUint16 /*aUnicodeKey*/) const
+    {
+    return 0;
+    }
+
+// ----------------------------------------------------------------------
+
+ TBool CKeyboardLayout::IsRepeatingKey(TInt aUnicodeKey) const
+    {
+    const TInt KNoRepeatKeys[] = 
+        {
+        // The modifier and lock keys:
+        EKeyLeftShift,
+        EKeyRightShift,
+        EKeyLeftAlt,
+        EKeyRightAlt,
+        EKeyLeftCtrl,
+        EKeyRightCtrl,
+        EKeyLeftFunc,
+        EKeyRightFunc,
+        EKeyCapsLock,
+        EKeyNumLock,
+        EKeyScrollLock,
+
+        // Other keys that toggle:
+        EKeyPause,
+        EKeyInsert,
+
+        // Some special cases:
+        EKeyEscape,
+        EKeyPrintScreen
+        };
+
+    const TInt KNumberOfNoRepeatKeys = 
+        (sizeof (KNoRepeatKeys)) / (sizeof (TInt));
+
+    TBool match = EFalse;
+    
+    for (TInt i=0; i<KNumberOfNoRepeatKeys; ++i)
+        {
+        if (aUnicodeKey == KNoRepeatKeys[i])
+            {
+            match = ETrue;
+            }
+        }
+
+    return !match;
+    }
+
+// ----------------------------------------------------------------------
+
+TUint16 CKeyboardLayout::TranslateOtherKey(TInt aHidKey, 
+    TInt aUsagePage, THidModifier, TLockKeys) const
+    {
+    static const TInt KEnhancedKeyCodesSize = 
+        (sizeof (KEnhancedKeyCodes)) / (sizeof (TUsagePageKey));
+
+    TUint16 unicode = 0;
+
+    for (TInt i=0; (unicode == 0) && (i<KEnhancedKeyCodesSize); ++i)
+        {
+        if ((aHidKey == KEnhancedKeyCodes[i].iHidId)
+            && (aUsagePage == KEnhancedKeyCodes[i].iHidPage))
+            {
+            unicode = KEnhancedKeyCodes[i].iCode;
+            }
+        }
+
+    return unicode;
+    }
+
+// ----------------------------------------------------------------------
+
+ TInt CKeyboardLayout::RawScanCode(TInt aHidKey, 
+    TInt aUsagePage, THidModifier aModifiers) const
+    {
+    TInt result = EStdKeyNull;
+
+    if (aUsagePage == EUsagePageKeyboard)
+        {
+        result = CheckChangingKeys(aHidKey, aModifiers);
+        
+        if (result == EStdKeyNull)
+            {
+            const TInt KRawCodesSize = (sizeof (KRawCodes)) / (sizeof (TInt));
+            if (aHidKey < KRawCodesSize)
+                {
+                result = KRawCodes[aHidKey];
+                }
+            else
+                {
+                result = CheckModifierKeys(aHidKey);
+                }
+            }
+        }
+    else
+        {
+        result = CheckSpecialRawCode(aHidKey, aUsagePage);
+        }
+    
+    return result;
+    }
+
+TInt CKeyboardLayout::CheckChangingKeys(TInt aHidKey, THidModifier aModifiers)
+    {
+    // Handle any key that changes scan code depending on the modifier
+    // state:
+
+    // All these special cases only apply to the keyboard usage page:
+    const TInt KTabKey = 0x2B;
+    if ((aHidKey == KTabKey) && aModifiers.AltOnly())
+        {
+        // Application switch key:
+        return EStdKeyApplication0;
+        }
+    
+    const TInt KDelKey = 0x4c;
+    const TInt KKeypadDelKey = 0x63;
+    if (((aHidKey == KDelKey) || (aHidKey == KKeypadDelKey))
+        && (aModifiers.Fold() == THidModifier::EAltCtrl))
+        {
+        // Power key:
+        return EStdKeyDevice2;
+        }
+        
+    const TInt KEnterKey = 0x28;
+    const TInt KKeypadEnterKey = 0x58;
+    if (((aHidKey == KEnterKey) || (aHidKey == KKeypadEnterKey))
+        && (aModifiers.ShiftOnly() || aModifiers.ControlOnly()))
+        {
+        // OK key:
+        return EStdKeyDevice3;
+        }
+
+    const TInt KLeftGuiKey = 0xe3;
+    if (aHidKey == KLeftGuiKey)
+        {
+        // Call create or left softkey:
+        return aModifiers.Shift() ? EStdKeyYes : EStdKeyDevice0;
+        }
+
+    const TInt KRightGuiKey = 0xe7;
+    const TInt KMenuKey = 0x65;
+    if ((aHidKey == KRightGuiKey) || (aHidKey == KMenuKey))
+        {
+        // Call end or right softkey:
+        return aModifiers.Shift() ? EStdKeyNo : EStdKeyDevice1;
+        }
+
+    return EStdKeyNull;
+    }
+
+TInt CKeyboardLayout::CheckModifierKeys(TInt aHidKey)
+    {
+    const TInt KModifierCodes[] =
+        {
+        EStdKeyLeftCtrl,   // HID code 0xe0 224
+        EStdKeyLeftShift,  //          0xe1 225
+        EStdKeyLeftAlt,    //          0xe2 226
+        EStdKeyLeftFunc,   //          0xe3 227 (overridden by left sofkey)
+        EStdKeyRightCtrl,  //          0xe4 228
+        EStdKeyRightShift, //          0xe5 229
+        EStdKeyRightAlt,   //          0xe6 230
+        EStdKeyRightFunc   //          0xe7 231 (overridden by right sofkey)
+        };
+
+    const TInt KHidIdLeftCtrl = 0xe0;
+    const TInt KHidIdRightFunc = 0xe7;
+
+    TInt result = EStdKeyNull;
+
+    if ((aHidKey >= KHidIdLeftCtrl) && (aHidKey <= KHidIdRightFunc))
+        {
+        result = KModifierCodes[aHidKey - KHidIdLeftCtrl];
+        }
+
+    return result;
+    }
+
+TInt CKeyboardLayout::CheckSpecialRawCode(TInt aHidKey, TInt aUsagePage)
+    {
+    static const TInt KEnhancedKeyCodesSize = 
+        (sizeof (KEnhancedKeyCodes)) / (sizeof (TUsagePageKey));
+
+    TInt scanCode = EStdKeyNull;
+
+    for (TInt i=0; (scanCode == EStdKeyNull) && (i<KEnhancedKeyCodesSize); ++i)
+        {
+        if ((aHidKey == KEnhancedKeyCodes[i].iHidId)
+            && (aUsagePage == KEnhancedKeyCodes[i].iHidPage))
+            {
+            scanCode = KEnhancedKeyCodes[i].iScanCode;
+            }
+        }
+
+    return scanCode;
+    }
+
+// ----------------------------------------------------------------------
+
+ CStandardKeyboardLayout::CStandardKeyboardLayout(
+    const TInt* aColumnMap, TInt aMapSize,
+    const TUint16* aKeyCodes, TInt aTableSize,
+    const TSpecialKey* aSpecialCases)
+    : iColumnMap(aColumnMap), iKeyCodes(aKeyCodes),
+      iNumColumns(aMapSize / sizeof (TInt)), 
+      iNumKeys(aTableSize / (sizeof (TUint16) * iNumColumns)), 
+      iSpecialCases(aSpecialCases)
+    {
+    // nothing else to do
+    }
+
+ TUint16 CStandardKeyboardLayout::Unicode(TInt aHidKey, 
+    THidModifier aModifiers) const
+    {
+    TUint16 unicode = 0;
+    TUint8 foldedModifiers = aModifiers.Fold();
+
+    if ((aHidKey >= 0) && (aHidKey < iNumKeys))
+        {
+        for (TInt i=0; i<iNumColumns; ++i)
+            {
+            if (iColumnMap[i] == foldedModifiers)
+                unicode = iKeyCodes[(aHidKey * iNumColumns) + i];
+            }
+        }
+
+    if ((unicode == 0) && iSpecialCases)
+        {
+        unicode = FindSpecialKey(iSpecialCases, aHidKey, foldedModifiers);
+        }
+        
+    return unicode;
+    }
+
+ TUint16 CStandardKeyboardLayout::FindSpecialKey(
+    const TSpecialKey* aMap, TInt aHidKey, TUint8 aFoldedModifiers)
+    {
+    // Look for this HID key code in the appropriate special key
+    // key table. A zero key code means "end of table".
+
+    TUint16 keyCode = 0;
+    for (TInt i=0; (keyCode == 0) && (aMap[i].iHidKey != 0); ++i)
+        {
+        if ((aHidKey == aMap[i].iHidKey) 
+            && (aFoldedModifiers == aMap[i].iFoldedModifiers))
+            {
+            keyCode = aMap[i].iUnicode;
+            }
+        }
+    
+    return keyCode;
+    }
+
+// ----------------------------------------------------------------------
+
+ CDeadKeyLayout::CDeadKeyLayout(const TInt* aColumnMap, 
+    TInt aMapSize, const TUint16* aKeyCodes, TInt aTableSize,
+    const TSpecialKey* aSpecialCases, const TIndexPair* aDeadKeyIndex)
+    : CStandardKeyboardLayout(aColumnMap, aMapSize, aKeyCodes,
+        aTableSize, aSpecialCases), iDeadKeyIndex(aDeadKeyIndex)
+    {
+    // nothing else to do
+    }
+
+ TBool CDeadKeyLayout::IsDeadKey(TInt aUnicodeKey) const
+    {
+    TBool match = EFalse;
+    
+    for (TInt i=0; !match && (iDeadKeyIndex[i].iUnicode != 0); ++i)
+        {
+        match = (aUnicodeKey == iDeadKeyIndex[i].iUnicode);
+        }
+    
+    DBG(RDebug::Print(_L("[HID]\tCDeadKeyLayout::IsDeadKey(0x%08x:0x%04x) = %d"),
+      iDeadKeyIndex, aUnicodeKey, match));
+
+    return match;
+    }
+
+ TUint16 CDeadKeyLayout::FindCombiningChar(TUint16 aDeadKeyUnicode,
+    TUint16 aUnicodeKey) const
+    {
+    const TKeyPair* map = 0;
+    for (TInt i=0; (map == 0) && (iDeadKeyIndex[i].iUnicode != 0); ++i)
+        {
+        if (aDeadKeyUnicode == iDeadKeyIndex[i].iUnicode)
+            map = iDeadKeyIndex[i].iMap;
+        }
+
+    TUint16 comboChar = 0;
+    if (map != 0)
+        {
+        // Look for this base character code in the appropriate dead
+        // key table.  (NB. A zero base code means "end of table".)
+        //
+        for (TInt j=0; (comboChar==0) && (map[j].iBaseChar != 0); ++j)
+            {
+            if (aUnicodeKey == map[j].iBaseChar)
+                {
+                comboChar = map[j].iComboChar;
+                }
+            }
+        }
+    
+    return comboChar;
+    }
+
+// ----------------------------------------------------------------------