--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserverplugins/keyeventrouting/src/keyrouter.cpp Fri Jul 16 11:45:55 2010 +0300
@@ -0,0 +1,543 @@
+// 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"
+
+#ifndef KEYROUTER_TEST
+// Temporary: to be made configurable
+#define COMBINED_POWER_END_KEY
+#endif
+
+/**
+Privileged application UIDs
+*/
+#ifdef KEYROUTER_TEST
+const TInt KUidTAutoServer = 0x10205152;
+const TInt KUidReservedApp = 0x102872e3;
+#else
+const TInt KUidPhoneApp = 0x100058b3;
+const TInt KUidSysAp = 0x100058f3;
+const TInt KUidAutoLock = 0x100059b5;
+const TInt KUidHomeScreen = 0x20022f35;
+const TInt KUidAknCapServer = 0x10207218;
+#endif
+
+#if defined(KEYROUTER_TEST) || defined(COMBINED_POWER_END_KEY)
+/**
+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[] =
+ {
+ // Req. scancode, Capture scancode, Req. keycode, Capture keycode
+#ifndef KEYROUTER_TEST
+ // On devices with a combined Power and End key, that key produces a
+ // PowerOff code. Map capture requests for the End key to PowerOff.
+ // At routing time, an End key event will automatically be delivered
+ // to the capturing application.
+ { EStdKeyPhoneEnd, EStdKeyPowerOff, EKeyPhoneEnd, EKeyPowerOff }
+#else
+ // Entry for TEvent test case GRAPHICS-WSERV-0751.
+ // Capture requests for psuedo key Device0 are mapped to capture
+ // the real key Device1.
+ { EStdKeyDevice0, EStdKeyDevice1, EKeyDevice0, EKeyDevice1 }
+#endif
+ };
+
+const TInt KNumTranslations = TABLE_SIZE(KTranslations);
+#endif // defined(KEYROUTER_TEST) || defined(COMBINED_POWER_END_KEY)
+
+/**
+Restricted Key Table
+
+The following keys may be captured only by the specified applications.
+More than one application may be listed for a given key-type combination.
+*/
+const TRestrictedKeyEntry KRestrictedKeys[] =
+ {
+#ifndef KEYROUTER_TEST
+ // Short Apps key events may only be captured by HomeScreen, SysApp,
+ // AutoLock, Phone and AknCapServer.
+ { EStdKeyApplication, ECaptureTypeKeyUpDown, KUidHomeScreen },
+ { EKeyApplication, ECaptureTypeKey, KUidHomeScreen },
+ { EStdKeyApplication, ECaptureTypeKeyUpDown, KUidSysAp },
+ { EKeyApplication, ECaptureTypeKey, KUidSysAp },
+ { EStdKeyApplication, ECaptureTypeKeyUpDown, KUidAutoLock },
+ { EKeyApplication, ECaptureTypeKey, KUidAutoLock },
+ { EStdKeyApplication, ECaptureTypeKeyUpDown, KUidPhoneApp },
+ { EKeyApplication, ECaptureTypeKey, KUidPhoneApp },
+ { EStdKeyApplication, ECaptureTypeKeyUpDown, KUidAknCapServer },
+ { EKeyApplication, ECaptureTypeKey, KUidAknCapServer },
+
+ // Long Apps key events may only be captured by SysAp (for launching
+ // the task switcher), AutoLock and Phone.
+ { EKeyApplication, ECaptureTypeLongKey, KUidSysAp },
+ { EKeyApplication, ECaptureTypeLongKey, KUidAutoLock },
+ { EKeyApplication, ECaptureTypeLongKey, KUidPhoneApp },
+
+ // Only SysAp and AutoLock are allowed to capture Power key events
+ { EKeyPowerOff, ECaptureTypeKey, KUidSysAp },
+ { EKeyPowerOff, ECaptureTypeLongKey, KUidSysAp },
+ { EStdKeyPowerOff, ECaptureTypeKeyUpDown, KUidSysAp },
+ { EKeyPowerOff, ECaptureTypeKey, KUidAutoLock },
+ { EKeyPowerOff, ECaptureTypeLongKey, KUidAutoLock },
+ { EStdKeyPowerOff, ECaptureTypeKeyUpDown, KUidAutoLock },
+
+ // Only AutoLock is allowed to capture Lock key events
+ { EKeyLock, ECaptureTypeKey, KUidAutoLock },
+ { EKeyLock, ECaptureTypeLongKey, KUidAutoLock },
+ { EStdKeyLock, ECaptureTypeKeyUpDown, KUidAutoLock }
+#else
+ // The following entries are for test purposes only.
+ // 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 the reserved UID and the TAuto tests are allowed to capture
+ // F21 key events
+ { EKeyF21, ECaptureTypeKey, KUidReservedApp },
+ { EKeyF21, ECaptureTypeLongKey, KUidReservedApp },
+ { EStdKeyF21, ECaptureTypeKeyUpDown, KUidReservedApp },
+ { EKeyF21, ECaptureTypeKey, KUidTAutoServer },
+ { EKeyF21, ECaptureTypeLongKey, KUidTAutoServer },
+ { EStdKeyF21, ECaptureTypeKeyUpDown, KUidTAutoServer }
+#endif
+ };
+
+/**
+Application Priority Table
+
+The following applications have fixed priorities for capture of the associated
+key. The priority specified in this table overrides the priority in the capture
+request. When any other application captures a key listed here, the priority is
+forced to zero.
+
+@note If a key should be never be delivered to any other application, then
+ it should be placed in KRestrictedKeys[] instead.
+*/
+const TAppPriorityEntry KAppPriorityKeys[] =
+ {
+#ifndef KEYROUTER_TEST
+ // The Phone app has priority for capture of Send key events
+ { EStdKeyPhoneSend, ECaptureTypeKeyUpDown, KUidPhoneApp, 1 },
+ { EKeyPhoneSend, ECaptureTypeKey, KUidPhoneApp, 1 },
+ { EKeyPhoneSend, ECaptureTypeLongKey, KUidPhoneApp, 1 },
+
+ // The Phone app has the highest priority for capture of End key
+ // events. Note: any applications that capture these events apart
+ // from those listed here (e.g. other telephony apps) will effectively
+ // have priority 0.
+ { EStdKeyPhoneEnd, ECaptureTypeKeyUpDown, KUidPhoneApp, 1 },
+ { EKeyPhoneEnd, ECaptureTypeKey, KUidPhoneApp, 1 },
+ { EKeyPhoneEnd, ECaptureTypeLongKey, KUidPhoneApp, 1 },
+
+ // The Home Screen app has low priority for capture of End key events
+ { EStdKeyPhoneEnd, ECaptureTypeKeyUpDown, KUidHomeScreen, -1 },
+ { EKeyPhoneEnd, ECaptureTypeKey, KUidHomeScreen, -1 },
+ { EKeyPhoneEnd, ECaptureTypeLongKey, KUidHomeScreen, -1 },
+
+ // SysAp has the lowest priority for capture of End key events
+ { EStdKeyPhoneEnd, ECaptureTypeKeyUpDown, KUidSysAp, -2 },
+ { EKeyPhoneEnd, ECaptureTypeKey, KUidSysAp, -2 },
+ { EKeyPhoneEnd, ECaptureTypeLongKey, KUidSysAp, -2 },
+
+#ifdef COMBINED_POWER_END_KEY
+ // SysAp has the same priority for capture of Power key events as
+ // it does for End key events. This is necessary to maintain correct
+ // relative priorities when there is a combined Power and End key.
+ { EStdKeyPowerOff, ECaptureTypeKeyUpDown, KUidSysAp, -2 },
+ { EKeyPowerOff, ECaptureTypeKey, KUidSysAp, -2 },
+ { EKeyPowerOff, ECaptureTypeLongKey, KUidSysAp, -2 }
+#endif
+
+#else // KEYROUTER_TEST
+ // The following entries are for test purposes only.
+ // Test Case GRAPHICS-WSERV-0757. TAuto tests have priority for
+ // capture of F22 key events.
+ { EStdKeyF22, ECaptureTypeKeyUpDown, KUidTAutoServer, 1 },
+ { EKeyF22, ECaptureTypeKey, KUidTAutoServer, 1 },
+ { EKeyF22, ECaptureTypeLongKey, KUidTAutoServer, 1 }
+#endif // KEYROUTER_TEST
+ };
+
+#ifdef KEYROUTER_TEST
+/**
+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 KNumBlockedKeys = TABLE_SIZE(KBlockedKeys);
+#endif // KEYROUTER_TEST
+
+const TInt KNumRestrictedKeys = TABLE_SIZE(KRestrictedKeys);
+const TInt KNumAppPriorityKeys = TABLE_SIZE(KAppPriorityKeys);
+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);
+ ProcessAppPriorities(iCaptureKeys[0]);
+ TranslateCaptureKey(aRequest.iType, iCaptureKeys[0].iInputCode);
+ }
+
+
+/**
+Update an existing key capture request
+
+@param aRequest Updated capture request details
+
+@note This function is used only for window server hotkeys, hence key/scan
+ code translation and processing of special application priorities are
+ omitted.
+
+@see CKeyEventRouter::UpdateCaptureKeyL
+*/
+void CKeyEventRouterImpl::UpdateCaptureKeyL(const TKeyCaptureRequest& aRequest)
+ {
+ ASSERT(!aRequest.iWindowGroup);
+ 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;
+ 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.
+ 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))
+ {
+ matchRequest = &request;
+ 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;
+#ifdef COMBINED_POWER_END_KEY
+ // When routing to SysAp on devices with a combined Power and End
+ // key, deliver this event as PowerOff if the HomeScreen currently
+ // has focus, otherwise as End. (Note that when the HomeScreen app
+ // is showing the application library, it will capture the End key
+ // itself with higher priority.)
+ if (matchRequest->iAppUid.iUid == KUidSysAp &&
+ aInput.iKeyEvent.iScanCode == EStdKeyPowerOff)
+ {
+ aOutput.iKeyEvent.iScanCode =
+ (aInput.iFocusAppUid.iUid == KUidHomeScreen) ?
+ EStdKeyPowerOff : EStdKeyPhoneEnd;
+ }
+#endif
+ }
+ else
+ {
+ aOutput.iKeyEvent.iScanCode = aInput.iKeyEvent.iScanCode;
+ aOutput.iKeyEvent.iCode = matchRequest->iOutputCode;
+#ifdef COMBINED_POWER_END_KEY
+ if (matchRequest->iAppUid.iUid == KUidSysAp &&
+ aInput.iKeyEvent.iCode == EKeyPowerOff)
+ {
+ aOutput.iKeyEvent.iCode =
+ (aInput.iFocusAppUid.iUid == KUidHomeScreen) ?
+ EKeyPowerOff : EKeyPhoneEnd;
+ }
+#endif
+ }
+ 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);
+ }
+
+ if (aRequest.iWindowGroup != NULL && IsRestrictedKey(aRequest))
+ {
+ User::Leave(KErrPermissionDenied);
+ }
+ }
+
+/**
+Check if the requested key capture is restricted by application UID
+
+@param aRequest Capture request details
+
+@return ETrue if the key-type combination in aRequest is listed in
+ KRestrictedKeys[] but the requesting application UID does not match
+ any entry in the table; otherwise EFalse.
+*/
+TBool CKeyEventRouterImpl::IsRestrictedKey(const TKeyCaptureRequest& aRequest)
+ {
+ TBool foundKey = EFalse;
+
+ for (const TRestrictedKeyEntry* entry = KRestrictedKeys; entry < &KRestrictedKeys[KNumRestrictedKeys]; entry++)
+ {
+ if (entry->iCode == aRequest.iInputCode &&
+ entry->iType == aRequest.iType)
+ {
+ foundKey = ETrue;
+ if (entry->iAppUidValue == aRequest.iAppUid.iUid)
+ {
+ return EFalse;
+ }
+ }
+ }
+
+ return foundKey;
+ }
+
+/**
+Process special application priorities
+
+@param aRequest Capture request details. If the key-type combination is
+ listed in KAppPriorityKeys[], then the capture priority is
+ replaced with the configured priority for the requesting
+ application, or with zero if the application UID does not
+ match any entry in the table.
+*/
+void CKeyEventRouterImpl::ProcessAppPriorities(TKeyCaptureRequest& aRequest)
+ {
+ TBool foundKey = EFalse;
+
+ for (const TAppPriorityEntry* entry = KAppPriorityKeys; entry < &KAppPriorityKeys[KNumAppPriorityKeys]; entry++)
+ {
+ if (entry->iCode == aRequest.iInputCode &&
+ entry->iType == aRequest.iType)
+ {
+ foundKey = ETrue;
+ if (entry->iAppUidValue == aRequest.iAppUid.iUid)
+ {
+ aRequest.iPriority = entry->iAppPriority;
+ return;
+ }
+ }
+ }
+
+ if (foundKey)
+ {
+ aRequest.iPriority = 0;
+ }
+ }
+
+#ifdef KEYROUTER_TEST
+/**
+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;
+ }
+#endif // KEYROUTER_TEST
+
+/**
+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)
+ {
+#if defined(KEYROUTER_TEST) || defined(COMBINED_POWER_END_KEY)
+ 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
+ }