/*
* 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 "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;
//----------------------------------------------------------------------------
// 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();
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();
}
if (iSettings)
delete iSettings;
}
//----------------------------------------------------------------------------
// 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);
}
// Ready to process keyboard events:
iDriverState = EInitialised;
}
//----------------------------------------------------------------------------
// 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();
}
// ----------------------------------------------------------------------
// 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)
{
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();
}
//----------------------------------------------------------------------------
// 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
// 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) || aScanCode == EStdKeyBackspace )
&& 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;
}
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