windowing/windowserverplugins/keyeventrouting/src/keyrouter.cpp
changeset 188 1b081cb0800b
--- /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