--- /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 <e32cmn.h>
+#include <e32debug.h>
+#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