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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // Reference implementation of Key Event Routing plug-in
24 #include "keyrouterimpl.h"
25 #include "keyaliases.h"
27 #ifndef KEYROUTER_TEST
28 // Temporary: to be made configurable
29 #define COMBINED_POWER_END_KEY
33 Privileged application UIDs
36 const TInt KUidTAutoServer = 0x10205152;
37 const TInt KUidReservedApp = 0x102872e3;
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;
46 #if defined(KEYROUTER_TEST) || defined(COMBINED_POWER_END_KEY)
48 Key Capture Translation Table
50 The following scan codes and key codes are translated at capture-request time.
52 @note The data in this table is for example/test purposes only.
54 const TTranslationEntry KTranslations[] =
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 }
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 }
71 const TInt KNumTranslations = TABLE_SIZE(KTranslations);
72 #endif // defined(KEYROUTER_TEST) || defined(COMBINED_POWER_END_KEY)
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.
80 const TRestrictedKeyEntry KRestrictedKeys[] =
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 },
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 },
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 },
110 // Only AutoLock is allowed to capture Lock key events
111 { EKeyLock, ECaptureTypeKey, KUidAutoLock },
112 { EKeyLock, ECaptureTypeLongKey, KUidAutoLock },
113 { EStdKeyLock, ECaptureTypeKeyUpDown, KUidAutoLock }
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
123 { EKeyF21, ECaptureTypeKey, KUidReservedApp },
124 { EKeyF21, ECaptureTypeLongKey, KUidReservedApp },
125 { EStdKeyF21, ECaptureTypeKeyUpDown, KUidReservedApp },
126 { EKeyF21, ECaptureTypeKey, KUidTAutoServer },
127 { EKeyF21, ECaptureTypeLongKey, KUidTAutoServer },
128 { EStdKeyF21, ECaptureTypeKeyUpDown, KUidTAutoServer }
133 Application Priority Table
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
140 @note If a key should be never be delivered to any other application, then
141 it should be placed in KRestrictedKeys[] instead.
143 const TAppPriorityEntry KAppPriorityKeys[] =
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 },
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
155 { EStdKeyPhoneEnd, ECaptureTypeKeyUpDown, KUidPhoneApp, 1 },
156 { EKeyPhoneEnd, ECaptureTypeKey, KUidPhoneApp, 1 },
157 { EKeyPhoneEnd, ECaptureTypeLongKey, KUidPhoneApp, 1 },
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 },
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 },
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 }
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
188 #ifdef KEYROUTER_TEST
192 The following keys are not routed by default.
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
198 const TBlockedKeyEntry KBlockedKeys[] =
200 // Entries for TEvent test case GRAPHICS-WSERV-0760
201 { EStdKeyDevice3, ECaptureTypeKeyUpDown },
202 { EKeyDevice3, ECaptureTypeKey }
205 const TInt KNumBlockedKeys = TABLE_SIZE(KBlockedKeys);
206 #endif // KEYROUTER_TEST
208 const TInt KNumRestrictedKeys = TABLE_SIZE(KRestrictedKeys);
209 const TInt KNumAppPriorityKeys = TABLE_SIZE(KAppPriorityKeys);
210 const TInt KCaptureKeyArrayGranularity = 5;
213 Create and return an instance of CKeyEventRouter
215 @return Pointer to new router instance
217 EXPORT_C CKeyEventRouter* CKeyEventRouter::NewL()
219 return new(ELeave) CKeyEventRouterImpl;
222 CKeyEventRouterImpl::CKeyEventRouterImpl()
223 : iCaptureKeys(KCaptureKeyArrayGranularity, _FOFF(TKeyCaptureRequest, iHandle))
227 CKeyEventRouterImpl::~CKeyEventRouterImpl()
229 iCaptureKeys.Close();
233 Add a new key capture request
235 @param aRequest Capture request details
237 @see CKeyEventRouter::AddCaptureKeyL
239 void CKeyEventRouterImpl::AddCaptureKeyL(const TKeyCaptureRequest& aRequest)
241 CheckCaptureKeyL(aRequest);
242 iCaptureKeys.InsertL(aRequest, 0);
243 ProcessAppPriorities(iCaptureKeys[0]);
244 TranslateCaptureKey(aRequest.iType, iCaptureKeys[0].iInputCode);
249 Update an existing key capture request
251 @param aRequest Updated capture request details
253 @note This function is used only for window server hotkeys, hence key/scan
254 code translation and processing of special application priorities are
257 @see CKeyEventRouter::UpdateCaptureKeyL
259 void CKeyEventRouterImpl::UpdateCaptureKeyL(const TKeyCaptureRequest& aRequest)
261 ASSERT(!aRequest.iWindowGroup);
262 CheckCaptureKeyL(aRequest);
264 TInt index = iCaptureKeys.Find(aRequest);
265 ASSERT(index != KErrNotFound);
267 if (index != KErrNotFound)
269 iCaptureKeys[index] = aRequest;
274 Cancel a key capture request
276 @param aType Capture type
277 @param aHandle Opaque handle of request to be cancelled
279 @see CKeyEventRouter::CancelCaptureKey
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.
284 void CKeyEventRouterImpl::CancelCaptureKey(TKeyCaptureType /*aType*/, TAny* aHandle)
286 TKeyCaptureRequest request;
287 request.iHandle = aHandle;
289 TInt index = iCaptureKeys.Find(request);
290 if (index != KErrNotFound)
292 iCaptureKeys.Remove(index);
297 Route the key event described by aInput and return its destination in iOutput
299 @param aInput Input data with key event to be routed
300 @param aOutput Output key event and routing results
302 @see CKeyEventRouter::RouteKey
304 void CKeyEventRouterImpl::RouteKey(const TKeyEventRouterInput& aInput, TKeyEventRouterOutput& aOutput)
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;
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++)
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))
323 matchRequest = &request;
324 priority = request.iPriority;
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)
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)
346 aOutput.iKeyEvent.iScanCode =
347 (aInput.iFocusAppUid.iUid == KUidHomeScreen) ?
348 EStdKeyPowerOff : EStdKeyPhoneEnd;
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)
360 aOutput.iKeyEvent.iCode =
361 (aInput.iFocusAppUid.iUid == KUidHomeScreen) ?
362 EKeyPowerOff : EKeyPhoneEnd;
366 aOutput.iKeyEvent.iModifiers = aInput.iKeyEvent.iModifiers;
367 aOutput.iCaptureHandle = matchRequest->iHandle;
368 aOutput.iResult = ECaptured;
370 #ifdef KEYROUTER_TEST
371 else if (IsKeyBlocked(aInput.iType, inputCode))
373 // No matching capture request and key is blocked. Do not route.
374 aOutput.iResult = EConsumed;
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;
389 Check that capture request arguments are sane and capture is allowed
391 @param aRequest Capture request details
393 @leave KErrArgument if modifier state contains bits that are not in the
394 modifier mask or modifier mask contains EModifierLongKey or priority
396 KErrPermissionDenied if key is restricted to capture by a specific
397 application UID and the UID of the requesting app does not match.
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
406 void CKeyEventRouterImpl::CheckCaptureKeyL(const TKeyCaptureRequest& aRequest)
408 if ((aRequest.iModifiers & ~aRequest.iModifierMask) != 0 ||
409 (aRequest.iModifierMask & EModifierLongKey) != 0 && aRequest.iWindowGroup != NULL ||
410 aRequest.iPriority == KMinTInt)
412 User::Leave(KErrArgument);
415 if (aRequest.iWindowGroup != NULL && IsRestrictedKey(aRequest))
417 User::Leave(KErrPermissionDenied);
422 Check if the requested key capture is restricted by application UID
424 @param aRequest Capture request details
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.
430 TBool CKeyEventRouterImpl::IsRestrictedKey(const TKeyCaptureRequest& aRequest)
432 TBool foundKey = EFalse;
434 for (const TRestrictedKeyEntry* entry = KRestrictedKeys; entry < &KRestrictedKeys[KNumRestrictedKeys]; entry++)
436 if (entry->iCode == aRequest.iInputCode &&
437 entry->iType == aRequest.iType)
440 if (entry->iAppUidValue == aRequest.iAppUid.iUid)
451 Process special application priorities
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.
459 void CKeyEventRouterImpl::ProcessAppPriorities(TKeyCaptureRequest& aRequest)
461 TBool foundKey = EFalse;
463 for (const TAppPriorityEntry* entry = KAppPriorityKeys; entry < &KAppPriorityKeys[KNumAppPriorityKeys]; entry++)
465 if (entry->iCode == aRequest.iInputCode &&
466 entry->iType == aRequest.iType)
469 if (entry->iAppUidValue == aRequest.iAppUid.iUid)
471 aRequest.iPriority = entry->iAppPriority;
479 aRequest.iPriority = 0;
483 #ifdef KEYROUTER_TEST
485 Check if the specified key is blocked from default routing
487 @param aType Key capture type
488 @param aCode Scan code or key code
490 @return ETrue if key is blocked, otherwise EFalse.
492 TBool CKeyEventRouterImpl::IsKeyBlocked(TKeyCaptureType aType, TUint aCode)
494 for (const TBlockedKeyEntry* entry = KBlockedKeys; entry < &KBlockedKeys[KNumBlockedKeys]; entry++)
496 if (entry->iCode == aCode && entry->iType == aType)
504 #endif // KEYROUTER_TEST
507 Translate the scan or key code of a capture request
509 @param aType Key capture type
510 @param aCode Key code or scan code, updated to translated value (if any)
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.
522 void CKeyEventRouterImpl::TranslateCaptureKey(TKeyCaptureType aType, TUint& aCode)
524 #if defined(KEYROUTER_TEST) || defined(COMBINED_POWER_END_KEY)
525 for (const TTranslationEntry* entry = KTranslations; entry < &KTranslations[KNumTranslations]; entry++)
527 if (aType == ECaptureTypeKeyUpDown)
529 if (aCode == entry->iRequestScanCode)
531 aCode = entry->iCaptureScanCode;
536 if (aCode == entry->iRequestKeyCode)
538 aCode = entry->iCaptureKeyCode;