windowing/windowserverplugins/keyeventrouting/src/keyrouter.cpp
changeset 188 1b081cb0800b
equal deleted inserted replaced
187:9f66f99ee56f 188:1b081cb0800b
       
     1 // Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Reference implementation of Key Event Routing plug-in
       
    15 
       
    16 /**
       
    17 @file
       
    18 @internalTechnology
       
    19 @prototype
       
    20 */
       
    21 
       
    22 #include <e32cmn.h>
       
    23 #include <e32debug.h>
       
    24 #include "keyrouterimpl.h"
       
    25 #include "keyaliases.h"
       
    26 
       
    27 #ifdef KEYROUTER_TEST
       
    28 /**
       
    29 Privileged application UIDs
       
    30 */
       
    31 const TInt KUidTAutoServer = 0x10205152;
       
    32 const TInt KUidReservedApp = 0x102872e3;
       
    33 
       
    34 /**
       
    35 Key Capture Translation Table
       
    36 
       
    37 The following scan codes and key codes are translated at capture-request time.
       
    38 
       
    39 @note	The data in this table is for example/test purposes only.
       
    40 */
       
    41 const TTranslationEntry KTranslations[] =
       
    42 	{
       
    43 		// Entry for TEvent test case GRAPHICS-WSERV-0751.
       
    44 		// Capture requests for psuedo key Device0 are mapped to capture
       
    45 		// the real key Device1.
       
    46 		// Req. scancode,	Capture scancode,	Req. keycode,	Capture keycode
       
    47 		{ EStdKeyDevice0,	EStdKeyDevice1,		EKeyDevice0,	EKeyDevice1 }
       
    48 	};
       
    49 
       
    50 /**
       
    51 Restricted Key Table
       
    52 
       
    53 The following keys may be captured only by the specified application.
       
    54 
       
    55 @note	The data in this table is for example/test purposes only.
       
    56 */
       
    57 const TAppKeyEntry KRestrictedKeys[] =
       
    58 	{
       
    59 		// Examples:
       
    60 		// Only the Phone app is allowed to capture long End key events
       
    61 		// { EKeyPhoneEnd,			ECaptureTypeLongKey,	KUidPhoneApp },
       
    62 		// Only the Home Screen app is allowed to capture short Apps key events
       
    63 		// { EStdKeyApplication,	ECaptureTypeKeyUpDown,	KUidHomeScreenApp },
       
    64 		// { EKeyApplication,		ECaptureTypeKey,		KUidHomeScreenApp },
       
    65 		// Only SysApp is allowed to capture long Apps key events (for
       
    66 		// launching the task switcher).
       
    67 		// { EKeyApplication,		ECaptureTypeLongKey,	KUidSysApp },
       
    68 
       
    69 		// Test Case GRAPHICS-WSERV-0754. Only a reserved UID is allowed to
       
    70 		// capture F20 key events.
       
    71 		{ EKeyF20,				ECaptureTypeKey,		KUidReservedApp },
       
    72 		{ EKeyF20,				ECaptureTypeLongKey,	KUidReservedApp },
       
    73 		{ EStdKeyF20,			ECaptureTypeKeyUpDown,	KUidReservedApp },
       
    74 		// Only TAuto tests are allowed to capture F21 key events
       
    75 		{ EKeyF21,				ECaptureTypeKey,		KUidTAutoServer },
       
    76 		{ EKeyF21,				ECaptureTypeLongKey,	KUidTAutoServer },
       
    77 		{ EStdKeyF21,			ECaptureTypeKeyUpDown,	KUidTAutoServer }
       
    78 	};
       
    79 
       
    80 /**
       
    81 Priority Application Table
       
    82 
       
    83 The following applications have priority over other applications for capture
       
    84 of the specified key.
       
    85 
       
    86 @note	The data in this table is for example/test purposes only.
       
    87 		If a key should be never be delivered to any other application, then
       
    88 		it should be placed in KRestrictedKeys[] instead.
       
    89 */
       
    90 const TAppKeyEntry KPriorityAppKeys[] =
       
    91 	{
       
    92 		// Example:
       
    93 		// The Phone app has priority for capture of short Send and End
       
    94 		// key events
       
    95 		// { EStdKeyPhoneSend,	ECaptureTypeKeyUpDown,	KUidPhoneApp },
       
    96 		// { EKeyPhoneSend,		ECaptureTypeKey,		KUidPhoneApp },
       
    97 		// { EStdKeyPhoneEnd,	ECaptureTypeKeyUpDown,	KUidPhoneApp },
       
    98 		// { EKeyPhoneEnd,		ECaptureTypeKey,		KUidPhoneApp },
       
    99 
       
   100 		// Test Case GRAPHICS-WSERV-0757. TAuto tests have priority for
       
   101 		// capture of F22 key events.
       
   102 		{ EStdKeyF22,			ECaptureTypeKeyUpDown,	KUidTAutoServer },
       
   103 		{ EKeyF22,				ECaptureTypeKey,		KUidTAutoServer },
       
   104 		{ EKeyF22,				ECaptureTypeLongKey,	KUidTAutoServer }
       
   105 	};
       
   106 
       
   107 /**
       
   108 Blocked key table.
       
   109 
       
   110 The following keys are not routed by default.
       
   111 
       
   112 @note	The data in this table is for example/test purposes only.
       
   113 		Since long key events are never routed by default, there is no need
       
   114 		to list them here.
       
   115 */
       
   116 const TBlockedKeyEntry KBlockedKeys[] =
       
   117 	{
       
   118 		// Entries for TEvent test case GRAPHICS-WSERV-0760
       
   119 		{ EStdKeyDevice3,	ECaptureTypeKeyUpDown },
       
   120 		{ EKeyDevice3,		ECaptureTypeKey }
       
   121 	};
       
   122 
       
   123 const TInt KNumTranslations = TABLE_SIZE(KTranslations);
       
   124 const TInt KNumRestrictedKeys = TABLE_SIZE(KRestrictedKeys);
       
   125 const TInt KNumPriorityAppKeys = TABLE_SIZE(KPriorityAppKeys);
       
   126 const TInt KNumBlockedKeys = TABLE_SIZE(KBlockedKeys);
       
   127 #endif // KEYROUTER_TEST
       
   128 
       
   129 const TInt KCaptureKeyArrayGranularity = 5;
       
   130 
       
   131 /**
       
   132 Create and return an instance of CKeyEventRouter
       
   133 
       
   134 @return	Pointer to new router instance
       
   135 */
       
   136 EXPORT_C CKeyEventRouter* CKeyEventRouter::NewL()
       
   137 	{
       
   138 	return new(ELeave) CKeyEventRouterImpl;
       
   139 	}
       
   140 
       
   141 CKeyEventRouterImpl::CKeyEventRouterImpl()
       
   142 : iCaptureKeys(KCaptureKeyArrayGranularity, _FOFF(TKeyCaptureRequest, iHandle))
       
   143 	{
       
   144 	}
       
   145 
       
   146 CKeyEventRouterImpl::~CKeyEventRouterImpl()
       
   147 	{
       
   148 	iCaptureKeys.Close();
       
   149 	}
       
   150 
       
   151 /**
       
   152 Add a new key capture request
       
   153 
       
   154 @param	aRequest	Capture request details
       
   155 
       
   156 @see CKeyEventRouter::AddCaptureKeyL
       
   157 */
       
   158 void CKeyEventRouterImpl::AddCaptureKeyL(const TKeyCaptureRequest& aRequest)
       
   159 	{
       
   160 	CheckCaptureKeyL(aRequest);
       
   161 	iCaptureKeys.InsertL(aRequest, 0);
       
   162 #ifdef KEYROUTER_TEST
       
   163 	TranslateCaptureKey(aRequest.iType, iCaptureKeys[0].iInputCode);
       
   164 #endif
       
   165 	}
       
   166    
       
   167 /**
       
   168 Update an existing key capture request
       
   169 
       
   170 @param	aRequest	Updated capture request details
       
   171 
       
   172 @see CKeyEventRouter::UpdateCaptureKeyL
       
   173 */
       
   174 void CKeyEventRouterImpl::UpdateCaptureKeyL(const TKeyCaptureRequest& aRequest)
       
   175 	{
       
   176 	CheckCaptureKeyL(aRequest);
       
   177 
       
   178 	TInt index = iCaptureKeys.Find(aRequest);
       
   179 	ASSERT(index != KErrNotFound);
       
   180 
       
   181 	if (index != KErrNotFound)
       
   182 		{
       
   183 		iCaptureKeys[index] = aRequest;
       
   184 		}
       
   185 	}
       
   186 
       
   187 /**
       
   188 Cancel a key capture request
       
   189 
       
   190 @param	aType		Capture type
       
   191 @param	aHandle		Opaque handle of request to be cancelled
       
   192 
       
   193 @see CKeyEventRouter::CancelCaptureKey
       
   194 
       
   195 Note: aType is unused in this implementation, but is present to permit
       
   196 implementations that use separate lists for each of the three capture types.
       
   197 */
       
   198 void CKeyEventRouterImpl::CancelCaptureKey(TKeyCaptureType /*aType*/, TAny* aHandle)
       
   199 	{
       
   200 	TKeyCaptureRequest request;
       
   201 	request.iHandle = aHandle;
       
   202 
       
   203 	TInt index = iCaptureKeys.Find(request);
       
   204 	if (index != KErrNotFound)
       
   205 		{
       
   206 		iCaptureKeys.Remove(index);
       
   207 		}
       
   208 	}
       
   209 
       
   210 /**
       
   211 Route the key event described by aInput and return its destination in iOutput
       
   212 
       
   213 @param	aInput		Input data with key event to be routed
       
   214 @param	aOutput		Output key event and routing results
       
   215 
       
   216 @see CKeyEventRouter::RouteKey
       
   217 */
       
   218 void CKeyEventRouterImpl::RouteKey(const TKeyEventRouterInput& aInput, TKeyEventRouterOutput& aOutput)
       
   219 	{
       
   220 	TUint inputCode = (aInput.iType == ECaptureTypeKeyUpDown) ?
       
   221 						aInput.iKeyEvent.iScanCode : aInput.iKeyEvent.iCode;
       
   222 #ifdef KEYROUTER_TEST
       
   223 	TInt priUid = PriorityAppUid(aInput.iType, inputCode);
       
   224 #endif
       
   225 	TInt priority = KMinTInt;
       
   226 	TInt captureCount = iCaptureKeys.Count();
       
   227 	TKeyCaptureRequest* matchRequest = NULL;
       
   228 
       
   229 	// Find the highest priority matching capture request. If there are
       
   230 	// multiple entries with the same priority then use the first one, i.e.
       
   231 	// the most recent request. Capture priorities are overridden if a
       
   232 	// particular application has precedence for capture of the key.
       
   233 	for (TInt index = 0; index < captureCount; index++)
       
   234 		{
       
   235 		TKeyCaptureRequest& request = iCaptureKeys[index];
       
   236 		if (request.iType == aInput.iType &&
       
   237 			request.iInputCode == inputCode &&
       
   238 		    (aInput.iKeyEvent.iModifiers & request.iModifierMask) == request.iModifiers &&
       
   239 			(request.iPriority > priority
       
   240 #ifdef KEYROUTER_TEST
       
   241 			 || priUid != 0 && request.iAppUid.iUid == priUid
       
   242 #endif
       
   243 			 ))
       
   244 			{
       
   245 			matchRequest = &request;
       
   246 #ifdef KEYROUTER_TEST
       
   247 			if (priUid != 0 && request.iAppUid.iUid == priUid)
       
   248 				{
       
   249 				break;
       
   250 				}
       
   251 #endif
       
   252 			priority = request.iPriority;
       
   253 			}
       
   254 		}
       
   255 
       
   256 	if (matchRequest)
       
   257 		{
       
   258 		// Found matching capture request. Route the key event to the window
       
   259 		// group that made the capture request.
       
   260 		aOutput.iWindowGroup = matchRequest->iWindowGroup;
       
   261 		if (aInput.iType == ECaptureTypeKeyUpDown)
       
   262 			{
       
   263 			aOutput.iKeyEvent.iScanCode = matchRequest->iOutputCode;
       
   264 			aOutput.iKeyEvent.iCode = aInput.iKeyEvent.iCode;
       
   265 			}
       
   266 		else
       
   267 			{
       
   268 			aOutput.iKeyEvent.iScanCode = aInput.iKeyEvent.iScanCode;
       
   269 			aOutput.iKeyEvent.iCode = matchRequest->iOutputCode;
       
   270 			}
       
   271 		aOutput.iKeyEvent.iModifiers = aInput.iKeyEvent.iModifiers;
       
   272 		aOutput.iCaptureHandle = matchRequest->iHandle;
       
   273 		aOutput.iResult = ECaptured;
       
   274 		}
       
   275 #ifdef KEYROUTER_TEST
       
   276 	else if (IsKeyBlocked(aInput.iType, inputCode))
       
   277 		{
       
   278 		// No matching capture request and key is blocked. Do not route.
       
   279 		aOutput.iResult = EConsumed;
       
   280 		}
       
   281 #endif
       
   282 	else
       
   283 		{
       
   284 		// No matching capture request. Route the key event to the current
       
   285 		// focussed window group.
       
   286 		aOutput.iWindowGroup = aInput.iFocusWindowGroup;
       
   287 		aOutput.iKeyEvent = aInput.iKeyEvent;
       
   288 		aOutput.iCaptureHandle = NULL;
       
   289 		aOutput.iResult = ERouted;
       
   290 		}
       
   291 	}
       
   292 
       
   293 /**
       
   294 Check that capture request arguments are sane and capture is allowed
       
   295 
       
   296 @param	aRequest	Capture request details
       
   297 
       
   298 @leave	KErrArgument if modifier state contains bits that are not in the
       
   299 		modifier mask or modifier mask contains EModifierLongKey or priority
       
   300 		is KMinTInt.
       
   301 		KErrPermissionDenied if key is restricted to capture by a specific
       
   302 		application UID and the UID of the requesting app does not match.
       
   303 
       
   304 @note	Requests with a priority of KMinTint would never be captured: this was
       
   305 		also true of the previous implementation in ektran.dll but was ignored.
       
   306 		Client code must use the appropriate API function to capture short or
       
   307 		long key events, so including EModifierLongKey in the modifier mask is
       
   308 		not allowed. (Hotkeys are excepted since a mask of 0xffffffff is used
       
   309 		to disable them).
       
   310 */
       
   311 void CKeyEventRouterImpl::CheckCaptureKeyL(const TKeyCaptureRequest& aRequest)
       
   312 	{
       
   313 	if ((aRequest.iModifiers & ~aRequest.iModifierMask) != 0 ||
       
   314 		(aRequest.iModifierMask & EModifierLongKey) != 0 && aRequest.iWindowGroup != NULL ||
       
   315 		aRequest.iPriority == KMinTInt)
       
   316 		{
       
   317 		User::Leave(KErrArgument);
       
   318 		}
       
   319 
       
   320 #ifdef KEYROUTER_TEST
       
   321 	if (aRequest.iWindowGroup != NULL && IsRestrictedKey(aRequest))
       
   322 		{
       
   323 		User::Leave(KErrPermissionDenied);
       
   324 		}
       
   325 #endif
       
   326 	}
       
   327 
       
   328 #ifdef KEYROUTER_TEST
       
   329 /**
       
   330 Check if the requested key capture is restricted by application UID
       
   331 
       
   332 @param	aRequest	Capture request details
       
   333 
       
   334 @return	ETrue if key is restricted and requesting UID does not match,
       
   335 		otherwise EFalse.
       
   336 */
       
   337 TBool CKeyEventRouterImpl::IsRestrictedKey(const TKeyCaptureRequest& aRequest)
       
   338 	{
       
   339 	for (const TAppKeyEntry* entry = KRestrictedKeys; entry < &KRestrictedKeys[KNumRestrictedKeys]; entry++)
       
   340 		{
       
   341 		if (entry->iCode == aRequest.iInputCode &&
       
   342 			entry->iType == aRequest.iType &&
       
   343 			entry->iAppUidValue != aRequest.iAppUid.iUid)
       
   344 			{
       
   345 			return ETrue;
       
   346 			}
       
   347 		}
       
   348 
       
   349 		return EFalse;
       
   350 	}
       
   351 
       
   352 /**
       
   353 Return the UID of the application with priority for capture of the specified
       
   354 key.
       
   355 
       
   356 @param	aType	Key capture type
       
   357 @param	aCode	Key code or scan code
       
   358 
       
   359 @return	UID3 of the privileged application or zero if none.
       
   360 */
       
   361 TInt CKeyEventRouterImpl::PriorityAppUid(TKeyCaptureType aType, TUint aCode)
       
   362 	{
       
   363 	for (const TAppKeyEntry* entry = KPriorityAppKeys; entry < &KPriorityAppKeys[KNumPriorityAppKeys]; entry++)
       
   364 		{
       
   365 		if (entry->iCode == aCode && entry->iType == aType)
       
   366 			{
       
   367 			return entry->iAppUidValue;
       
   368 			}
       
   369 		}
       
   370 
       
   371 		return 0;
       
   372 	}
       
   373 
       
   374 /**
       
   375 Check if the specified key is blocked from default routing
       
   376 
       
   377 @param	aType		Key capture type
       
   378 @param	aCode		Scan code or key code
       
   379 
       
   380 @return	ETrue if key is blocked, otherwise EFalse.
       
   381 */
       
   382 TBool CKeyEventRouterImpl::IsKeyBlocked(TKeyCaptureType aType, TUint aCode)
       
   383 	{
       
   384 	for (const TBlockedKeyEntry* entry = KBlockedKeys; entry < &KBlockedKeys[KNumBlockedKeys]; entry++)
       
   385 		{
       
   386 		if (entry->iCode == aCode && entry->iType == aType)
       
   387 			{
       
   388 			return ETrue;
       
   389 			}
       
   390 		}
       
   391 
       
   392 		return EFalse;
       
   393 	}
       
   394 
       
   395 /**
       
   396 Translate the scan or key code of a capture request
       
   397 
       
   398 @param	aType	Key capture type
       
   399 @param	aCode	Key code or scan code, updated to translated value (if any)
       
   400 
       
   401 @note	This function is used to translate the input key or scan code of a
       
   402 		capture request on addition to the capture list. When a key event that
       
   403 		matches the list entry is routed, the output code will be taken from
       
   404 		TKeyCaptureRequest.iOutputCode and hence automatically translated again
       
   405 		(typically back to the original input code of the request, unless the
       
   406 		input and output codes were different). For example, a request to
       
   407 		capture key code A will be translated to key code B in the capture list.
       
   408 		When RouteKey() processes an event with key code B and selects that
       
   409 		list entry, it will output key code A for delivery to the application.
       
   410 */
       
   411 void CKeyEventRouterImpl::TranslateCaptureKey(TKeyCaptureType aType, TUint& aCode)
       
   412 {
       
   413 	for (const TTranslationEntry* entry = KTranslations; entry < &KTranslations[KNumTranslations]; entry++)
       
   414 		{
       
   415 		if (aType == ECaptureTypeKeyUpDown)
       
   416 			{
       
   417 			if (aCode == entry->iRequestScanCode)
       
   418 				{
       
   419 				aCode = entry->iCaptureScanCode;
       
   420 				}
       
   421 			}
       
   422 		else
       
   423 			{
       
   424 			if (aCode == entry->iRequestKeyCode)
       
   425 				{
       
   426 				aCode = entry->iCaptureKeyCode;
       
   427 				}
       
   428 			}
       
   429 		}
       
   430 	}
       
   431 #endif // KEYROUTER_TEST