diff -r 9f66f99ee56f -r 1b081cb0800b windowing/windowserverplugins/keyeventrouting/src/keyrouter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/windowing/windowserverplugins/keyeventrouting/src/keyrouter.cpp Fri Sep 24 16:44:34 2010 +0300 @@ -0,0 +1,431 @@ +// Copyright (c) 2010 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: +// Reference implementation of Key Event Routing plug-in + +/** +@file +@internalTechnology +@prototype +*/ + +#include +#include +#include "keyrouterimpl.h" +#include "keyaliases.h" + +#ifdef KEYROUTER_TEST +/** +Privileged application UIDs +*/ +const TInt KUidTAutoServer = 0x10205152; +const TInt KUidReservedApp = 0x102872e3; + +/** +Key Capture Translation Table + +The following scan codes and key codes are translated at capture-request time. + +@note The data in this table is for example/test purposes only. +*/ +const TTranslationEntry KTranslations[] = + { + // Entry for TEvent test case GRAPHICS-WSERV-0751. + // Capture requests for psuedo key Device0 are mapped to capture + // the real key Device1. + // Req. scancode, Capture scancode, Req. keycode, Capture keycode + { EStdKeyDevice0, EStdKeyDevice1, EKeyDevice0, EKeyDevice1 } + }; + +/** +Restricted Key Table + +The following keys may be captured only by the specified application. + +@note The data in this table is for example/test purposes only. +*/ +const TAppKeyEntry KRestrictedKeys[] = + { + // Examples: + // Only the Phone app is allowed to capture long End key events + // { EKeyPhoneEnd, ECaptureTypeLongKey, KUidPhoneApp }, + // Only the Home Screen app is allowed to capture short Apps key events + // { EStdKeyApplication, ECaptureTypeKeyUpDown, KUidHomeScreenApp }, + // { EKeyApplication, ECaptureTypeKey, KUidHomeScreenApp }, + // Only SysApp is allowed to capture long Apps key events (for + // launching the task switcher). + // { EKeyApplication, ECaptureTypeLongKey, KUidSysApp }, + + // Test Case GRAPHICS-WSERV-0754. Only a reserved UID is allowed to + // capture F20 key events. + { EKeyF20, ECaptureTypeKey, KUidReservedApp }, + { EKeyF20, ECaptureTypeLongKey, KUidReservedApp }, + { EStdKeyF20, ECaptureTypeKeyUpDown, KUidReservedApp }, + // Only TAuto tests are allowed to capture F21 key events + { EKeyF21, ECaptureTypeKey, KUidTAutoServer }, + { EKeyF21, ECaptureTypeLongKey, KUidTAutoServer }, + { EStdKeyF21, ECaptureTypeKeyUpDown, KUidTAutoServer } + }; + +/** +Priority Application Table + +The following applications have priority over other applications for capture +of the specified key. + +@note The data in this table is for example/test purposes only. + If a key should be never be delivered to any other application, then + it should be placed in KRestrictedKeys[] instead. +*/ +const TAppKeyEntry KPriorityAppKeys[] = + { + // Example: + // The Phone app has priority for capture of short Send and End + // key events + // { EStdKeyPhoneSend, ECaptureTypeKeyUpDown, KUidPhoneApp }, + // { EKeyPhoneSend, ECaptureTypeKey, KUidPhoneApp }, + // { EStdKeyPhoneEnd, ECaptureTypeKeyUpDown, KUidPhoneApp }, + // { EKeyPhoneEnd, ECaptureTypeKey, KUidPhoneApp }, + + // Test Case GRAPHICS-WSERV-0757. TAuto tests have priority for + // capture of F22 key events. + { EStdKeyF22, ECaptureTypeKeyUpDown, KUidTAutoServer }, + { EKeyF22, ECaptureTypeKey, KUidTAutoServer }, + { EKeyF22, ECaptureTypeLongKey, KUidTAutoServer } + }; + +/** +Blocked key table. + +The following keys are not routed by default. + +@note The data in this table is for example/test purposes only. + Since long key events are never routed by default, there is no need + to list them here. +*/ +const TBlockedKeyEntry KBlockedKeys[] = + { + // Entries for TEvent test case GRAPHICS-WSERV-0760 + { EStdKeyDevice3, ECaptureTypeKeyUpDown }, + { EKeyDevice3, ECaptureTypeKey } + }; + +const TInt KNumTranslations = TABLE_SIZE(KTranslations); +const TInt KNumRestrictedKeys = TABLE_SIZE(KRestrictedKeys); +const TInt KNumPriorityAppKeys = TABLE_SIZE(KPriorityAppKeys); +const TInt KNumBlockedKeys = TABLE_SIZE(KBlockedKeys); +#endif // KEYROUTER_TEST + +const TInt KCaptureKeyArrayGranularity = 5; + +/** +Create and return an instance of CKeyEventRouter + +@return Pointer to new router instance +*/ +EXPORT_C CKeyEventRouter* CKeyEventRouter::NewL() + { + return new(ELeave) CKeyEventRouterImpl; + } + +CKeyEventRouterImpl::CKeyEventRouterImpl() +: iCaptureKeys(KCaptureKeyArrayGranularity, _FOFF(TKeyCaptureRequest, iHandle)) + { + } + +CKeyEventRouterImpl::~CKeyEventRouterImpl() + { + iCaptureKeys.Close(); + } + +/** +Add a new key capture request + +@param aRequest Capture request details + +@see CKeyEventRouter::AddCaptureKeyL +*/ +void CKeyEventRouterImpl::AddCaptureKeyL(const TKeyCaptureRequest& aRequest) + { + CheckCaptureKeyL(aRequest); + iCaptureKeys.InsertL(aRequest, 0); +#ifdef KEYROUTER_TEST + TranslateCaptureKey(aRequest.iType, iCaptureKeys[0].iInputCode); +#endif + } + +/** +Update an existing key capture request + +@param aRequest Updated capture request details + +@see CKeyEventRouter::UpdateCaptureKeyL +*/ +void CKeyEventRouterImpl::UpdateCaptureKeyL(const TKeyCaptureRequest& aRequest) + { + CheckCaptureKeyL(aRequest); + + TInt index = iCaptureKeys.Find(aRequest); + ASSERT(index != KErrNotFound); + + if (index != KErrNotFound) + { + iCaptureKeys[index] = aRequest; + } + } + +/** +Cancel a key capture request + +@param aType Capture type +@param aHandle Opaque handle of request to be cancelled + +@see CKeyEventRouter::CancelCaptureKey + +Note: aType is unused in this implementation, but is present to permit +implementations that use separate lists for each of the three capture types. +*/ +void CKeyEventRouterImpl::CancelCaptureKey(TKeyCaptureType /*aType*/, TAny* aHandle) + { + TKeyCaptureRequest request; + request.iHandle = aHandle; + + TInt index = iCaptureKeys.Find(request); + if (index != KErrNotFound) + { + iCaptureKeys.Remove(index); + } + } + +/** +Route the key event described by aInput and return its destination in iOutput + +@param aInput Input data with key event to be routed +@param aOutput Output key event and routing results + +@see CKeyEventRouter::RouteKey +*/ +void CKeyEventRouterImpl::RouteKey(const TKeyEventRouterInput& aInput, TKeyEventRouterOutput& aOutput) + { + TUint inputCode = (aInput.iType == ECaptureTypeKeyUpDown) ? + aInput.iKeyEvent.iScanCode : aInput.iKeyEvent.iCode; +#ifdef KEYROUTER_TEST + TInt priUid = PriorityAppUid(aInput.iType, inputCode); +#endif + TInt priority = KMinTInt; + TInt captureCount = iCaptureKeys.Count(); + TKeyCaptureRequest* matchRequest = NULL; + + // Find the highest priority matching capture request. If there are + // multiple entries with the same priority then use the first one, i.e. + // the most recent request. Capture priorities are overridden if a + // particular application has precedence for capture of the key. + for (TInt index = 0; index < captureCount; index++) + { + TKeyCaptureRequest& request = iCaptureKeys[index]; + if (request.iType == aInput.iType && + request.iInputCode == inputCode && + (aInput.iKeyEvent.iModifiers & request.iModifierMask) == request.iModifiers && + (request.iPriority > priority +#ifdef KEYROUTER_TEST + || priUid != 0 && request.iAppUid.iUid == priUid +#endif + )) + { + matchRequest = &request; +#ifdef KEYROUTER_TEST + if (priUid != 0 && request.iAppUid.iUid == priUid) + { + break; + } +#endif + priority = request.iPriority; + } + } + + if (matchRequest) + { + // Found matching capture request. Route the key event to the window + // group that made the capture request. + aOutput.iWindowGroup = matchRequest->iWindowGroup; + if (aInput.iType == ECaptureTypeKeyUpDown) + { + aOutput.iKeyEvent.iScanCode = matchRequest->iOutputCode; + aOutput.iKeyEvent.iCode = aInput.iKeyEvent.iCode; + } + else + { + aOutput.iKeyEvent.iScanCode = aInput.iKeyEvent.iScanCode; + aOutput.iKeyEvent.iCode = matchRequest->iOutputCode; + } + aOutput.iKeyEvent.iModifiers = aInput.iKeyEvent.iModifiers; + aOutput.iCaptureHandle = matchRequest->iHandle; + aOutput.iResult = ECaptured; + } +#ifdef KEYROUTER_TEST + else if (IsKeyBlocked(aInput.iType, inputCode)) + { + // No matching capture request and key is blocked. Do not route. + aOutput.iResult = EConsumed; + } +#endif + else + { + // No matching capture request. Route the key event to the current + // focussed window group. + aOutput.iWindowGroup = aInput.iFocusWindowGroup; + aOutput.iKeyEvent = aInput.iKeyEvent; + aOutput.iCaptureHandle = NULL; + aOutput.iResult = ERouted; + } + } + +/** +Check that capture request arguments are sane and capture is allowed + +@param aRequest Capture request details + +@leave KErrArgument if modifier state contains bits that are not in the + modifier mask or modifier mask contains EModifierLongKey or priority + is KMinTInt. + KErrPermissionDenied if key is restricted to capture by a specific + application UID and the UID of the requesting app does not match. + +@note Requests with a priority of KMinTint would never be captured: this was + also true of the previous implementation in ektran.dll but was ignored. + Client code must use the appropriate API function to capture short or + long key events, so including EModifierLongKey in the modifier mask is + not allowed. (Hotkeys are excepted since a mask of 0xffffffff is used + to disable them). +*/ +void CKeyEventRouterImpl::CheckCaptureKeyL(const TKeyCaptureRequest& aRequest) + { + if ((aRequest.iModifiers & ~aRequest.iModifierMask) != 0 || + (aRequest.iModifierMask & EModifierLongKey) != 0 && aRequest.iWindowGroup != NULL || + aRequest.iPriority == KMinTInt) + { + User::Leave(KErrArgument); + } + +#ifdef KEYROUTER_TEST + if (aRequest.iWindowGroup != NULL && IsRestrictedKey(aRequest)) + { + User::Leave(KErrPermissionDenied); + } +#endif + } + +#ifdef KEYROUTER_TEST +/** +Check if the requested key capture is restricted by application UID + +@param aRequest Capture request details + +@return ETrue if key is restricted and requesting UID does not match, + otherwise EFalse. +*/ +TBool CKeyEventRouterImpl::IsRestrictedKey(const TKeyCaptureRequest& aRequest) + { + for (const TAppKeyEntry* entry = KRestrictedKeys; entry < &KRestrictedKeys[KNumRestrictedKeys]; entry++) + { + if (entry->iCode == aRequest.iInputCode && + entry->iType == aRequest.iType && + entry->iAppUidValue != aRequest.iAppUid.iUid) + { + return ETrue; + } + } + + return EFalse; + } + +/** +Return the UID of the application with priority for capture of the specified +key. + +@param aType Key capture type +@param aCode Key code or scan code + +@return UID3 of the privileged application or zero if none. +*/ +TInt CKeyEventRouterImpl::PriorityAppUid(TKeyCaptureType aType, TUint aCode) + { + for (const TAppKeyEntry* entry = KPriorityAppKeys; entry < &KPriorityAppKeys[KNumPriorityAppKeys]; entry++) + { + if (entry->iCode == aCode && entry->iType == aType) + { + return entry->iAppUidValue; + } + } + + return 0; + } + +/** +Check if the specified key is blocked from default routing + +@param aType Key capture type +@param aCode Scan code or key code + +@return ETrue if key is blocked, otherwise EFalse. +*/ +TBool CKeyEventRouterImpl::IsKeyBlocked(TKeyCaptureType aType, TUint aCode) + { + for (const TBlockedKeyEntry* entry = KBlockedKeys; entry < &KBlockedKeys[KNumBlockedKeys]; entry++) + { + if (entry->iCode == aCode && entry->iType == aType) + { + return ETrue; + } + } + + return EFalse; + } + +/** +Translate the scan or key code of a capture request + +@param aType Key capture type +@param aCode Key code or scan code, updated to translated value (if any) + +@note This function is used to translate the input key or scan code of a + capture request on addition to the capture list. When a key event that + matches the list entry is routed, the output code will be taken from + TKeyCaptureRequest.iOutputCode and hence automatically translated again + (typically back to the original input code of the request, unless the + input and output codes were different). For example, a request to + capture key code A will be translated to key code B in the capture list. + When RouteKey() processes an event with key code B and selects that + list entry, it will output key code A for delivery to the application. +*/ +void CKeyEventRouterImpl::TranslateCaptureKey(TKeyCaptureType aType, TUint& aCode) +{ + for (const TTranslationEntry* entry = KTranslations; entry < &KTranslations[KNumTranslations]; entry++) + { + if (aType == ECaptureTypeKeyUpDown) + { + if (aCode == entry->iRequestScanCode) + { + aCode = entry->iCaptureScanCode; + } + } + else + { + if (aCode == entry->iRequestKeyCode) + { + aCode = entry->iCaptureKeyCode; + } + } + } + } +#endif // KEYROUTER_TEST