os/graphics/windowing/windowserverplugins/keyeventrouting/src/keyrouter.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     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 #ifndef KEYROUTER_TEST
    28 // Temporary: to be made configurable
    29 #define COMBINED_POWER_END_KEY
    30 #endif
    31 
    32 /**
    33 Privileged application UIDs
    34 */
    35 #ifdef KEYROUTER_TEST
    36 const TInt KUidTAutoServer = 0x10205152;
    37 const TInt KUidReservedApp = 0x102872e3;
    38 #else
    39 const TInt KUidPhoneApp = 0x100058b3;
    40 const TInt KUidSysAp = 0x100058f3;
    41 const TInt KUidAutoLock = 0x100059b5;
    42 const TInt KUidHomeScreen = 0x20022f35;
    43 const TInt KUidAknCapServer = 0x10207218;
    44 #endif
    45 
    46 #if defined(KEYROUTER_TEST) || defined(COMBINED_POWER_END_KEY)
    47 /**
    48 Key Capture Translation Table
    49 
    50 The following scan codes and key codes are translated at capture-request time.
    51 
    52 @note	The data in this table is for example/test purposes only.
    53 */
    54 const TTranslationEntry KTranslations[] =
    55 	{
    56 		// Req. scancode,	Capture scancode,	Req. keycode,	Capture keycode
    57 #ifndef KEYROUTER_TEST
    58 		// On devices with a combined Power and End key, that key produces a
    59 		// PowerOff code. Map capture requests for the End key to PowerOff.
    60 		// At routing time, an End key event will automatically be delivered
    61 		// to the capturing application.
    62 		{ EStdKeyPhoneEnd,	EStdKeyPowerOff,	EKeyPhoneEnd,	EKeyPowerOff }
    63 #else
    64 		// Entry for TEvent test case GRAPHICS-WSERV-0751.
    65 		// Capture requests for psuedo key Device0 are mapped to capture
    66 		// the real key Device1.
    67 		{ EStdKeyDevice0,	EStdKeyDevice1,		EKeyDevice0,	EKeyDevice1 }
    68 #endif
    69 	};
    70 
    71 const TInt KNumTranslations = TABLE_SIZE(KTranslations);
    72 #endif // defined(KEYROUTER_TEST) || defined(COMBINED_POWER_END_KEY)
    73 
    74 /**
    75 Restricted Key Table
    76 
    77 The following keys may be captured only by the specified applications.
    78 More than one application may be listed for a given key-type combination.
    79 */
    80 const TRestrictedKeyEntry KRestrictedKeys[] =
    81 	{
    82 #ifndef KEYROUTER_TEST
    83 		// Short Apps key events may only be captured by HomeScreen, SysApp,
    84 		// AutoLock, Phone and AknCapServer.
    85 		{ EStdKeyApplication,	ECaptureTypeKeyUpDown,	KUidHomeScreen },
    86 		{ EKeyApplication,		ECaptureTypeKey,		KUidHomeScreen },
    87 		{ EStdKeyApplication,	ECaptureTypeKeyUpDown,	KUidSysAp },
    88 		{ EKeyApplication,		ECaptureTypeKey,		KUidSysAp },
    89 		{ EStdKeyApplication,	ECaptureTypeKeyUpDown,	KUidAutoLock },
    90 		{ EKeyApplication,		ECaptureTypeKey,		KUidAutoLock },
    91 		{ EStdKeyApplication,	ECaptureTypeKeyUpDown,	KUidPhoneApp },
    92 		{ EKeyApplication,		ECaptureTypeKey,		KUidPhoneApp },
    93 		{ EStdKeyApplication,	ECaptureTypeKeyUpDown,	KUidAknCapServer },
    94 		{ EKeyApplication,		ECaptureTypeKey,		KUidAknCapServer },
    95 
    96 		// Long Apps key events may only be captured by SysAp (for launching
    97 		// the task switcher), AutoLock and Phone.
    98 		{ EKeyApplication,		ECaptureTypeLongKey,	KUidSysAp },
    99 		{ EKeyApplication,		ECaptureTypeLongKey,	KUidAutoLock },
   100 		{ EKeyApplication,		ECaptureTypeLongKey,	KUidPhoneApp },
   101 
   102 		// Only SysAp and AutoLock are allowed to capture Power key events
   103 		{ EKeyPowerOff,			ECaptureTypeKey,		KUidSysAp },
   104 		{ EKeyPowerOff,			ECaptureTypeLongKey,	KUidSysAp },
   105 		{ EStdKeyPowerOff,		ECaptureTypeKeyUpDown,	KUidSysAp },
   106 		{ EKeyPowerOff,			ECaptureTypeKey,		KUidAutoLock },
   107 		{ EKeyPowerOff,			ECaptureTypeLongKey,	KUidAutoLock },
   108 		{ EStdKeyPowerOff,		ECaptureTypeKeyUpDown,	KUidAutoLock },
   109 
   110 		// Only AutoLock is allowed to capture Lock key events
   111 		{ EKeyLock,				ECaptureTypeKey,		KUidAutoLock },
   112 		{ EKeyLock,				ECaptureTypeLongKey,	KUidAutoLock },
   113 		{ EStdKeyLock,			ECaptureTypeKeyUpDown,	KUidAutoLock }
   114 #else
   115 		// The following entries are for test purposes only.
   116 		// Test Case GRAPHICS-WSERV-0754. Only a reserved UID is allowed to
   117 		// capture F20 key events.
   118 		{ EKeyF20,				ECaptureTypeKey,		KUidReservedApp },
   119 		{ EKeyF20,				ECaptureTypeLongKey,	KUidReservedApp },
   120 		{ EStdKeyF20,			ECaptureTypeKeyUpDown,	KUidReservedApp },
   121 		// Only the reserved UID and the TAuto tests are allowed to capture
   122 		// F21 key events
   123 		{ EKeyF21,				ECaptureTypeKey,		KUidReservedApp },
   124 		{ EKeyF21,				ECaptureTypeLongKey,	KUidReservedApp },
   125 		{ EStdKeyF21,			ECaptureTypeKeyUpDown,	KUidReservedApp },
   126 		{ EKeyF21,				ECaptureTypeKey,		KUidTAutoServer },
   127 		{ EKeyF21,				ECaptureTypeLongKey,	KUidTAutoServer },
   128 		{ EStdKeyF21,			ECaptureTypeKeyUpDown,	KUidTAutoServer }
   129 #endif
   130 	};
   131 
   132 /**
   133 Application Priority Table
   134 
   135 The following applications have fixed priorities for capture of the associated
   136 key. The priority specified in this table overrides the priority in the capture
   137 request. When any other application captures a key listed here, the priority is
   138 forced to zero.
   139 
   140 @note	If a key should be never be delivered to any other application, then
   141 		it should be placed in KRestrictedKeys[] instead.
   142 */
   143 const TAppPriorityEntry KAppPriorityKeys[] =
   144 	{
   145 #ifndef KEYROUTER_TEST
   146 		// The Phone app has priority for capture of Send key events
   147 		{ EStdKeyPhoneSend,	ECaptureTypeKeyUpDown,	KUidPhoneApp, 1 },
   148 		{ EKeyPhoneSend,	ECaptureTypeKey,		KUidPhoneApp, 1 },
   149 		{ EKeyPhoneSend,	ECaptureTypeLongKey,	KUidPhoneApp, 1 },
   150 
   151 		// The Phone app has the highest priority for capture of End key
   152 		// events. Note: any applications that capture these events apart
   153 		// from those listed here (e.g. other telephony apps) will effectively
   154 		// have priority 0.
   155 		{ EStdKeyPhoneEnd,	ECaptureTypeKeyUpDown,	KUidPhoneApp, 1 },
   156 		{ EKeyPhoneEnd,		ECaptureTypeKey,		KUidPhoneApp, 1 },
   157 		{ EKeyPhoneEnd,		ECaptureTypeLongKey,	KUidPhoneApp, 1 },
   158 
   159 		// The Home Screen app has low priority for capture of End key events
   160 		{ EStdKeyPhoneEnd,	ECaptureTypeKeyUpDown,	KUidHomeScreen, -1 },
   161 		{ EKeyPhoneEnd,		ECaptureTypeKey,		KUidHomeScreen, -1 },
   162 		{ EKeyPhoneEnd,		ECaptureTypeLongKey,	KUidHomeScreen, -1 },
   163 
   164 		// SysAp has the lowest priority for capture of End key events
   165 		{ EStdKeyPhoneEnd,	ECaptureTypeKeyUpDown,	KUidSysAp, -2 },
   166 		{ EKeyPhoneEnd,		ECaptureTypeKey,		KUidSysAp, -2 },
   167 		{ EKeyPhoneEnd,		ECaptureTypeLongKey,	KUidSysAp, -2 },
   168 
   169 #ifdef COMBINED_POWER_END_KEY
   170 		// SysAp has the same priority for capture of Power key events as
   171 		// it does for End key events. This is necessary to maintain correct
   172 		// relative priorities when there is a combined Power and End key.
   173 		{ EStdKeyPowerOff,	ECaptureTypeKeyUpDown,	KUidSysAp, -2 },
   174 		{ EKeyPowerOff,		ECaptureTypeKey,		KUidSysAp, -2 },
   175 		{ EKeyPowerOff,		ECaptureTypeLongKey,	KUidSysAp, -2 }
   176 #endif
   177 
   178 #else // KEYROUTER_TEST
   179 		// The following entries are for test purposes only.
   180 		// Test Case GRAPHICS-WSERV-0757. TAuto tests have priority for
   181 		// capture of F22 key events.
   182 		{ EStdKeyF22,		ECaptureTypeKeyUpDown,	KUidTAutoServer, 1 },
   183 		{ EKeyF22,			ECaptureTypeKey,		KUidTAutoServer, 1 },
   184 		{ EKeyF22,			ECaptureTypeLongKey,	KUidTAutoServer, 1 }
   185 #endif // KEYROUTER_TEST
   186 	};
   187 
   188 #ifdef KEYROUTER_TEST
   189 /**
   190 Blocked key table.
   191 
   192 The following keys are not routed by default.
   193 
   194 @note	The data in this table is for example/test purposes only.
   195 		Since long key events are never routed by default, there is no need
   196 		to list them here.
   197 */
   198 const TBlockedKeyEntry KBlockedKeys[] =
   199 	{
   200 		// Entries for TEvent test case GRAPHICS-WSERV-0760
   201 		{ EStdKeyDevice3,	ECaptureTypeKeyUpDown },
   202 		{ EKeyDevice3,		ECaptureTypeKey }
   203 	};
   204 
   205 const TInt KNumBlockedKeys = TABLE_SIZE(KBlockedKeys);
   206 #endif // KEYROUTER_TEST
   207 
   208 const TInt KNumRestrictedKeys = TABLE_SIZE(KRestrictedKeys);
   209 const TInt KNumAppPriorityKeys = TABLE_SIZE(KAppPriorityKeys);
   210 const TInt KCaptureKeyArrayGranularity = 5;
   211 
   212 /**
   213 Create and return an instance of CKeyEventRouter
   214 
   215 @return	Pointer to new router instance
   216 */
   217 EXPORT_C CKeyEventRouter* CKeyEventRouter::NewL()
   218 	{
   219 	return new(ELeave) CKeyEventRouterImpl;
   220 	}
   221 
   222 CKeyEventRouterImpl::CKeyEventRouterImpl()
   223 : iCaptureKeys(KCaptureKeyArrayGranularity, _FOFF(TKeyCaptureRequest, iHandle))
   224 	{
   225 	}
   226 
   227 CKeyEventRouterImpl::~CKeyEventRouterImpl()
   228 	{
   229 	iCaptureKeys.Close();
   230 	}
   231 
   232 /**
   233 Add a new key capture request
   234 
   235 @param	aRequest	Capture request details
   236 
   237 @see CKeyEventRouter::AddCaptureKeyL
   238 */
   239 void CKeyEventRouterImpl::AddCaptureKeyL(const TKeyCaptureRequest& aRequest)
   240 	{
   241 	CheckCaptureKeyL(aRequest);
   242 	iCaptureKeys.InsertL(aRequest, 0);
   243 	ProcessAppPriorities(iCaptureKeys[0]);
   244 	TranslateCaptureKey(aRequest.iType, iCaptureKeys[0].iInputCode);
   245 	}
   246 
   247    
   248 /**
   249 Update an existing key capture request
   250 
   251 @param	aRequest	Updated capture request details
   252 
   253 @note	This function is used only for window server hotkeys, hence key/scan
   254 		code translation and processing of special application priorities are
   255 		omitted.
   256 
   257 @see CKeyEventRouter::UpdateCaptureKeyL
   258 */
   259 void CKeyEventRouterImpl::UpdateCaptureKeyL(const TKeyCaptureRequest& aRequest)
   260 	{
   261 	ASSERT(!aRequest.iWindowGroup);
   262 	CheckCaptureKeyL(aRequest);
   263 
   264 	TInt index = iCaptureKeys.Find(aRequest);
   265 	ASSERT(index != KErrNotFound);
   266 
   267 	if (index != KErrNotFound)
   268 		{
   269 		iCaptureKeys[index] = aRequest;
   270 		}
   271 	}
   272 
   273 /**
   274 Cancel a key capture request
   275 
   276 @param	aType		Capture type
   277 @param	aHandle		Opaque handle of request to be cancelled
   278 
   279 @see CKeyEventRouter::CancelCaptureKey
   280 
   281 Note: aType is unused in this implementation, but is present to permit
   282 implementations that use separate lists for each of the three capture types.
   283 */
   284 void CKeyEventRouterImpl::CancelCaptureKey(TKeyCaptureType /*aType*/, TAny* aHandle)
   285 	{
   286 	TKeyCaptureRequest request;
   287 	request.iHandle = aHandle;
   288 
   289 	TInt index = iCaptureKeys.Find(request);
   290 	if (index != KErrNotFound)
   291 		{
   292 		iCaptureKeys.Remove(index);
   293 		}
   294 	}
   295 
   296 /**
   297 Route the key event described by aInput and return its destination in iOutput
   298 
   299 @param	aInput		Input data with key event to be routed
   300 @param	aOutput		Output key event and routing results
   301 
   302 @see CKeyEventRouter::RouteKey
   303 */
   304 void CKeyEventRouterImpl::RouteKey(const TKeyEventRouterInput& aInput, TKeyEventRouterOutput& aOutput)
   305 	{
   306 	TUint inputCode = (aInput.iType == ECaptureTypeKeyUpDown) ?
   307 						aInput.iKeyEvent.iScanCode : aInput.iKeyEvent.iCode;
   308 	TInt priority = KMinTInt;
   309 	TInt captureCount = iCaptureKeys.Count();
   310 	TKeyCaptureRequest* matchRequest = NULL;
   311 
   312 	// Find the highest priority matching capture request. If there are
   313 	// multiple entries with the same priority then use the first one, i.e.
   314 	// the most recent request.
   315 	for (TInt index = 0; index < captureCount; index++)
   316 		{
   317 		TKeyCaptureRequest& request = iCaptureKeys[index];
   318 		if (request.iType == aInput.iType &&
   319 			request.iInputCode == inputCode &&
   320 		    (aInput.iKeyEvent.iModifiers & request.iModifierMask) == request.iModifiers &&
   321 			(request.iPriority > priority))
   322 			{
   323 			matchRequest = &request;
   324 			priority = request.iPriority;
   325 			}
   326 		}
   327 
   328 	if (matchRequest)
   329 		{
   330 		// Found matching capture request. Route the key event to the window
   331 		// group that made the capture request.
   332 		aOutput.iWindowGroup = matchRequest->iWindowGroup;
   333 		if (aInput.iType == ECaptureTypeKeyUpDown)
   334 			{
   335 			aOutput.iKeyEvent.iScanCode = matchRequest->iOutputCode;
   336 			aOutput.iKeyEvent.iCode = aInput.iKeyEvent.iCode;
   337 #ifdef COMBINED_POWER_END_KEY
   338 			// When routing to SysAp on devices with a combined Power and End
   339 			// key, deliver this event as PowerOff if the HomeScreen currently
   340 			// has focus, otherwise as End. (Note that when the HomeScreen app
   341 			// is showing the application library, it will capture the End key
   342 			// itself with higher priority.)
   343 			if (matchRequest->iAppUid.iUid == KUidSysAp &&
   344 				aInput.iKeyEvent.iScanCode == EStdKeyPowerOff)
   345 				{
   346 				aOutput.iKeyEvent.iScanCode =
   347 					(aInput.iFocusAppUid.iUid == KUidHomeScreen) ?
   348 					EStdKeyPowerOff : EStdKeyPhoneEnd;
   349 				}
   350 #endif
   351 			}
   352 		else
   353 			{
   354 			aOutput.iKeyEvent.iScanCode = aInput.iKeyEvent.iScanCode;
   355 			aOutput.iKeyEvent.iCode = matchRequest->iOutputCode;
   356 #ifdef COMBINED_POWER_END_KEY
   357 			if (matchRequest->iAppUid.iUid == KUidSysAp &&
   358 				aInput.iKeyEvent.iCode == EKeyPowerOff)
   359 				{
   360 				aOutput.iKeyEvent.iCode =
   361 					(aInput.iFocusAppUid.iUid == KUidHomeScreen) ?
   362 					EKeyPowerOff : EKeyPhoneEnd;
   363 				}
   364 #endif
   365 			}
   366 		aOutput.iKeyEvent.iModifiers = aInput.iKeyEvent.iModifiers;
   367 		aOutput.iCaptureHandle = matchRequest->iHandle;
   368 		aOutput.iResult = ECaptured;
   369 		}
   370 #ifdef KEYROUTER_TEST
   371 	else if (IsKeyBlocked(aInput.iType, inputCode))
   372 		{
   373 		// No matching capture request and key is blocked. Do not route.
   374 		aOutput.iResult = EConsumed;
   375 		}
   376 #endif
   377 	else
   378 		{
   379 		// No matching capture request. Route the key event to the current
   380 		// focussed window group.
   381 		aOutput.iWindowGroup = aInput.iFocusWindowGroup;
   382 		aOutput.iKeyEvent = aInput.iKeyEvent;
   383 		aOutput.iCaptureHandle = NULL;
   384 		aOutput.iResult = ERouted;
   385 		}
   386 	}
   387 
   388 /**
   389 Check that capture request arguments are sane and capture is allowed
   390 
   391 @param	aRequest	Capture request details
   392 
   393 @leave	KErrArgument if modifier state contains bits that are not in the
   394 		modifier mask or modifier mask contains EModifierLongKey or priority
   395 		is KMinTInt.
   396 		KErrPermissionDenied if key is restricted to capture by a specific
   397 		application UID and the UID of the requesting app does not match.
   398 
   399 @note	Requests with a priority of KMinTint would never be captured: this was
   400 		also true of the previous implementation in ektran.dll but was ignored.
   401 		Client code must use the appropriate API function to capture short or
   402 		long key events, so including EModifierLongKey in the modifier mask is
   403 		not allowed. (Hotkeys are excepted since a mask of 0xffffffff is used
   404 		to disable them).
   405 */
   406 void CKeyEventRouterImpl::CheckCaptureKeyL(const TKeyCaptureRequest& aRequest)
   407 	{
   408 	if ((aRequest.iModifiers & ~aRequest.iModifierMask) != 0 ||
   409 		(aRequest.iModifierMask & EModifierLongKey) != 0 && aRequest.iWindowGroup != NULL ||
   410 		aRequest.iPriority == KMinTInt)
   411 		{
   412 		User::Leave(KErrArgument);
   413 		}
   414 
   415 	if (aRequest.iWindowGroup != NULL && IsRestrictedKey(aRequest))
   416 		{
   417 		User::Leave(KErrPermissionDenied);
   418 		}
   419 	}
   420 
   421 /**
   422 Check if the requested key capture is restricted by application UID
   423 
   424 @param	aRequest	Capture request details
   425 
   426 @return	ETrue if the key-type combination in aRequest is listed in
   427 		KRestrictedKeys[] but the requesting application UID does not match
   428 		any entry in the table; otherwise EFalse.
   429 */
   430 TBool CKeyEventRouterImpl::IsRestrictedKey(const TKeyCaptureRequest& aRequest)
   431 	{
   432 	TBool foundKey = EFalse;
   433 
   434 	for (const TRestrictedKeyEntry* entry = KRestrictedKeys; entry < &KRestrictedKeys[KNumRestrictedKeys]; entry++)
   435 		{
   436 		if (entry->iCode == aRequest.iInputCode &&
   437 			entry->iType == aRequest.iType)
   438 			{
   439 			foundKey = ETrue;
   440 			if (entry->iAppUidValue == aRequest.iAppUid.iUid)
   441 				{
   442 				return EFalse;
   443 				}
   444 			}
   445 		}
   446 
   447 	return foundKey;
   448 	}
   449 
   450 /**
   451 Process special application priorities
   452 
   453 @param	aRequest	Capture request details. If the key-type combination is
   454 					listed in KAppPriorityKeys[], then the capture priority is
   455 					replaced with the configured priority for the requesting
   456 					application, or with zero if the application UID does not
   457 					match any entry in the table.
   458 */
   459 void CKeyEventRouterImpl::ProcessAppPriorities(TKeyCaptureRequest& aRequest)
   460 	{
   461 	TBool foundKey = EFalse;
   462 
   463 	for (const TAppPriorityEntry* entry = KAppPriorityKeys; entry < &KAppPriorityKeys[KNumAppPriorityKeys]; entry++)
   464 		{
   465 		if (entry->iCode == aRequest.iInputCode &&
   466 			entry->iType == aRequest.iType)
   467 			{
   468 			foundKey = ETrue;
   469 			if (entry->iAppUidValue == aRequest.iAppUid.iUid)
   470 				{
   471 				aRequest.iPriority = entry->iAppPriority;
   472 				return;
   473 				}
   474 			}
   475 		}
   476 
   477 	if (foundKey)
   478 		{
   479 		aRequest.iPriority = 0;
   480 		}
   481 	}
   482 
   483 #ifdef KEYROUTER_TEST
   484 /**
   485 Check if the specified key is blocked from default routing
   486 
   487 @param	aType		Key capture type
   488 @param	aCode		Scan code or key code
   489 
   490 @return	ETrue if key is blocked, otherwise EFalse.
   491 */
   492 TBool CKeyEventRouterImpl::IsKeyBlocked(TKeyCaptureType aType, TUint aCode)
   493 	{
   494 	for (const TBlockedKeyEntry* entry = KBlockedKeys; entry < &KBlockedKeys[KNumBlockedKeys]; entry++)
   495 		{
   496 		if (entry->iCode == aCode && entry->iType == aType)
   497 			{
   498 			return ETrue;
   499 			}
   500 		}
   501 
   502 		return EFalse;
   503 	}
   504 #endif // KEYROUTER_TEST
   505 
   506 /**
   507 Translate the scan or key code of a capture request
   508 
   509 @param	aType	Key capture type
   510 @param	aCode	Key code or scan code, updated to translated value (if any)
   511 
   512 @note	This function is used to translate the input key or scan code of a
   513 		capture request on addition to the capture list. When a key event that
   514 		matches the list entry is routed, the output code will be taken from
   515 		TKeyCaptureRequest.iOutputCode and hence automatically translated again
   516 		(typically back to the original input code of the request, unless the
   517 		input and output codes were different). For example, a request to
   518 		capture key code A will be translated to key code B in the capture list.
   519 		When RouteKey() processes an event with key code B and selects that
   520 		list entry, it will output key code A for delivery to the application.
   521 */
   522 void CKeyEventRouterImpl::TranslateCaptureKey(TKeyCaptureType aType, TUint& aCode)
   523 	{
   524 #if defined(KEYROUTER_TEST) || defined(COMBINED_POWER_END_KEY)
   525 	for (const TTranslationEntry* entry = KTranslations; entry < &KTranslations[KNumTranslations]; entry++)
   526 		{
   527 		if (aType == ECaptureTypeKeyUpDown)
   528 			{
   529 			if (aCode == entry->iRequestScanCode)
   530 				{
   531 				aCode = entry->iCaptureScanCode;
   532 				}
   533 			}
   534 		else
   535 			{
   536 			if (aCode == entry->iRequestKeyCode)
   537 				{
   538 				aCode = entry->iCaptureKeyCode;
   539 				}
   540 			}
   541 		}
   542 #endif
   543 	}