|
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 |