|
1 /* |
|
2 * Copyright (C) 2008 The Android Open Source Project |
|
3 * |
|
4 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 * you may not use this file except in compliance with the License. |
|
6 * You may obtain a copy of the License at |
|
7 * |
|
8 * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 * |
|
10 * Unless required by applicable law or agreed to in writing, software |
|
11 * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 * See the License for the specific language governing permissions and |
|
14 * limitations under the License. |
|
15 */ |
|
16 |
|
17 #define LOG_TAG "KeyCharacterMap" |
|
18 #include "cutils_log.h" |
|
19 |
|
20 #include <stdlib.h> |
|
21 #include <string.h> |
|
22 #include "android_keycodes.h" |
|
23 #include "Keyboard.h" |
|
24 #include "KeyCharacterMap.h" |
|
25 |
|
26 #if HAVE_ANDROID_OS |
|
27 #include <binder/Parcel.h> |
|
28 #endif |
|
29 |
|
30 #include <utils/Errors.h> |
|
31 #include "Tokenizer.h" |
|
32 #include <utils/Timers.h> |
|
33 |
|
34 // Enables debug output for the parser. |
|
35 #define DEBUG_PARSER 0 |
|
36 |
|
37 // Enables debug output for parser performance. |
|
38 #define DEBUG_PARSER_PERFORMANCE 0 |
|
39 |
|
40 // Enables debug output for mapping. |
|
41 #define DEBUG_MAPPING 0 |
|
42 |
|
43 |
|
44 namespace android { |
|
45 |
|
46 static const char* WHITESPACE = " \t\r"; |
|
47 static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:"; |
|
48 |
|
49 struct Modifier { |
|
50 const char* label; |
|
51 int32_t metaState; |
|
52 }; |
|
53 static const Modifier modifiers[] = { |
|
54 { "shift", AMETA_SHIFT_ON }, |
|
55 { "lshift", AMETA_SHIFT_LEFT_ON }, |
|
56 { "rshift", AMETA_SHIFT_RIGHT_ON }, |
|
57 { "alt", AMETA_ALT_ON }, |
|
58 { "lalt", AMETA_ALT_LEFT_ON }, |
|
59 { "ralt", AMETA_ALT_RIGHT_ON }, |
|
60 { "ctrl", AMETA_CTRL_ON }, |
|
61 { "lctrl", AMETA_CTRL_LEFT_ON }, |
|
62 { "rctrl", AMETA_CTRL_RIGHT_ON }, |
|
63 { "meta", AMETA_META_ON }, |
|
64 { "lmeta", AMETA_META_LEFT_ON }, |
|
65 { "rmeta", AMETA_META_RIGHT_ON }, |
|
66 { "sym", AMETA_SYM_ON }, |
|
67 { "fn", AMETA_FUNCTION_ON }, |
|
68 { "capslock", AMETA_CAPS_LOCK_ON }, |
|
69 { "numlock", AMETA_NUM_LOCK_ON }, |
|
70 { "scrolllock", AMETA_SCROLL_LOCK_ON }, |
|
71 }; |
|
72 |
|
73 #if DEBUG_MAPPING |
|
74 static String8 toString(const char16_t* chars, size_t numChars) { |
|
75 String8 result; |
|
76 for (size_t i = 0; i < numChars; i++) { |
|
77 result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]); |
|
78 } |
|
79 return result; |
|
80 } |
|
81 #endif |
|
82 |
|
83 |
|
84 // --- KeyCharacterMap --- |
|
85 |
|
86 sp<KeyCharacterMap> KeyCharacterMap::sEmpty = new KeyCharacterMap(); |
|
87 |
|
88 KeyCharacterMap::KeyCharacterMap() : |
|
89 mType(KEYBOARD_TYPE_UNKNOWN) { |
|
90 } |
|
91 |
|
92 KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) : |
|
93 RefBase(), mType(other.mType), mKeysByScanCode(other.mKeysByScanCode), |
|
94 mKeysByUsageCode(other.mKeysByUsageCode) { |
|
95 for (size_t i = 0; i < other.mKeys.size(); i++) { |
|
96 mKeys.add(other.mKeys.keyAt(i), new Key(*other.mKeys.valueAt(i))); |
|
97 } |
|
98 } |
|
99 |
|
100 KeyCharacterMap::~KeyCharacterMap() { |
|
101 for (size_t i = 0; i < mKeys.size(); i++) { |
|
102 Key* key = mKeys.editValueAt(i); |
|
103 delete key; |
|
104 } |
|
105 } |
|
106 |
|
107 status_t KeyCharacterMap::load(const String8& filename, |
|
108 Format format, sp<KeyCharacterMap>* outMap) { |
|
109 outMap->clear(); |
|
110 |
|
111 Tokenizer* tokenizer; |
|
112 status_t status = Tokenizer::open(filename, &tokenizer); |
|
113 if (status) { |
|
114 ALOGE("Error %d opening key character map file %s.", status, filename.string()); |
|
115 } else { |
|
116 status = load(tokenizer, format, outMap); |
|
117 delete tokenizer; |
|
118 } |
|
119 return status; |
|
120 } |
|
121 |
|
122 status_t KeyCharacterMap::loadContents(const String8& filename, const char* contents, |
|
123 Format format, sp<KeyCharacterMap>* outMap) { |
|
124 outMap->clear(); |
|
125 |
|
126 Tokenizer* tokenizer; |
|
127 status_t status = Tokenizer::fromContents(filename, contents, &tokenizer); |
|
128 if (status) { |
|
129 ALOGE("Error %d opening key character map.", status); |
|
130 } else { |
|
131 status = load(tokenizer, format, outMap); |
|
132 delete tokenizer; |
|
133 } |
|
134 return status; |
|
135 } |
|
136 |
|
137 status_t KeyCharacterMap::load(Tokenizer* tokenizer, |
|
138 Format format, sp<KeyCharacterMap>* outMap) { |
|
139 status_t status = OK; |
|
140 sp<KeyCharacterMap> map = new KeyCharacterMap(); |
|
141 if (!map.get()) { |
|
142 ALOGE("Error allocating key character map."); |
|
143 status = NO_MEMORY; |
|
144 } else { |
|
145 #if DEBUG_PARSER_PERFORMANCE |
|
146 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); |
|
147 #endif |
|
148 Parser parser(map.get(), tokenizer, format); |
|
149 status = parser.parse(); |
|
150 #if DEBUG_PARSER_PERFORMANCE |
|
151 nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; |
|
152 ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.", |
|
153 tokenizer->getFilename().string(), tokenizer->getLineNumber(), |
|
154 elapsedTime / 1000000.0); |
|
155 #endif |
|
156 if (!status) { |
|
157 *outMap = map; |
|
158 } |
|
159 } |
|
160 return status; |
|
161 } |
|
162 |
|
163 sp<KeyCharacterMap> KeyCharacterMap::combine(const sp<KeyCharacterMap>& base, |
|
164 const sp<KeyCharacterMap>& overlay) { |
|
165 if (overlay == NULL) { |
|
166 return base; |
|
167 } |
|
168 if (base == NULL) { |
|
169 return overlay; |
|
170 } |
|
171 |
|
172 sp<KeyCharacterMap> map = new KeyCharacterMap(*base.get()); |
|
173 for (size_t i = 0; i < overlay->mKeys.size(); i++) { |
|
174 int32_t keyCode = overlay->mKeys.keyAt(i); |
|
175 Key* key = overlay->mKeys.valueAt(i); |
|
176 ssize_t oldIndex = map->mKeys.indexOfKey(keyCode); |
|
177 if (oldIndex >= 0) { |
|
178 delete map->mKeys.valueAt(oldIndex); |
|
179 map->mKeys.editValueAt(oldIndex) = new Key(*key); |
|
180 } else { |
|
181 map->mKeys.add(keyCode, new Key(*key)); |
|
182 } |
|
183 } |
|
184 |
|
185 for (size_t i = 0; i < overlay->mKeysByScanCode.size(); i++) { |
|
186 map->mKeysByScanCode.replaceValueFor(overlay->mKeysByScanCode.keyAt(i), |
|
187 overlay->mKeysByScanCode.valueAt(i)); |
|
188 } |
|
189 |
|
190 for (size_t i = 0; i < overlay->mKeysByUsageCode.size(); i++) { |
|
191 map->mKeysByUsageCode.replaceValueFor(overlay->mKeysByUsageCode.keyAt(i), |
|
192 overlay->mKeysByUsageCode.valueAt(i)); |
|
193 } |
|
194 return map; |
|
195 } |
|
196 |
|
197 sp<KeyCharacterMap> KeyCharacterMap::empty() { |
|
198 return sEmpty; |
|
199 } |
|
200 |
|
201 int32_t KeyCharacterMap::getKeyboardType() const { |
|
202 return mType; |
|
203 } |
|
204 |
|
205 char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const { |
|
206 char16_t result = 0; |
|
207 const Key* key; |
|
208 if (getKey(keyCode, &key)) { |
|
209 result = key->label; |
|
210 } |
|
211 #if DEBUG_MAPPING |
|
212 ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result); |
|
213 #endif |
|
214 return result; |
|
215 } |
|
216 |
|
217 char16_t KeyCharacterMap::getNumber(int32_t keyCode) const { |
|
218 char16_t result = 0; |
|
219 const Key* key; |
|
220 if (getKey(keyCode, &key)) { |
|
221 result = key->number; |
|
222 } |
|
223 #if DEBUG_MAPPING |
|
224 ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result); |
|
225 #endif |
|
226 return result; |
|
227 } |
|
228 |
|
229 char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const { |
|
230 char16_t result = 0; |
|
231 const Key* key; |
|
232 const Behavior* behavior; |
|
233 if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { |
|
234 result = behavior->character; |
|
235 } |
|
236 #if DEBUG_MAPPING |
|
237 ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result); |
|
238 #endif |
|
239 return result; |
|
240 } |
|
241 |
|
242 bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState, |
|
243 FallbackAction* outFallbackAction) const { |
|
244 outFallbackAction->keyCode = 0; |
|
245 outFallbackAction->metaState = 0; |
|
246 |
|
247 bool result = false; |
|
248 const Key* key; |
|
249 const Behavior* behavior; |
|
250 if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { |
|
251 if (behavior->fallbackKeyCode) { |
|
252 outFallbackAction->keyCode = behavior->fallbackKeyCode; |
|
253 outFallbackAction->metaState = metaState & ~behavior->metaState; |
|
254 result = true; |
|
255 } |
|
256 } |
|
257 #if DEBUG_MAPPING |
|
258 ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, " |
|
259 "fallback keyCode=%d, fallback metaState=0x%08x.", |
|
260 keyCode, metaState, result ? "true" : "false", |
|
261 outFallbackAction->keyCode, outFallbackAction->metaState); |
|
262 #endif |
|
263 return result; |
|
264 } |
|
265 |
|
266 char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars, |
|
267 int32_t metaState) const { |
|
268 char16_t result = 0; |
|
269 const Key* key; |
|
270 if (getKey(keyCode, &key)) { |
|
271 // Try to find the most general behavior that maps to this character. |
|
272 // For example, the base key behavior will usually be last in the list. |
|
273 // However, if we find a perfect meta state match for one behavior then use that one. |
|
274 for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { |
|
275 if (behavior->character) { |
|
276 for (size_t i = 0; i < numChars; i++) { |
|
277 if (behavior->character == chars[i]) { |
|
278 result = behavior->character; |
|
279 if ((behavior->metaState & metaState) == behavior->metaState) { |
|
280 goto ExactMatch; |
|
281 } |
|
282 break; |
|
283 } |
|
284 } |
|
285 } |
|
286 } |
|
287 ExactMatch: ; |
|
288 } |
|
289 #if DEBUG_MAPPING |
|
290 ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.", |
|
291 keyCode, toString(chars, numChars).string(), metaState, result); |
|
292 #endif |
|
293 return result; |
|
294 } |
|
295 |
|
296 bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars, |
|
297 Vector<KeyEvent>& outEvents) const { |
|
298 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); |
|
299 |
|
300 for (size_t i = 0; i < numChars; i++) { |
|
301 int32_t keyCode, metaState; |
|
302 char16_t ch = chars[i]; |
|
303 if (!findKey(ch, &keyCode, &metaState)) { |
|
304 #if DEBUG_MAPPING |
|
305 ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.", |
|
306 deviceId, toString(chars, numChars).string(), ch); |
|
307 #endif |
|
308 return false; |
|
309 } |
|
310 |
|
311 int32_t currentMetaState = 0; |
|
312 addMetaKeys(outEvents, deviceId, metaState, true, now, ¤tMetaState); |
|
313 addKey(outEvents, deviceId, keyCode, currentMetaState, true, now); |
|
314 addKey(outEvents, deviceId, keyCode, currentMetaState, false, now); |
|
315 addMetaKeys(outEvents, deviceId, metaState, false, now, ¤tMetaState); |
|
316 } |
|
317 #if DEBUG_MAPPING |
|
318 ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", |
|
319 deviceId, toString(chars, numChars).string(), int32_t(outEvents.size())); |
|
320 for (size_t i = 0; i < outEvents.size(); i++) { |
|
321 ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.", |
|
322 outEvents[i].getKeyCode(), outEvents[i].getMetaState(), |
|
323 outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up"); |
|
324 } |
|
325 #endif |
|
326 return true; |
|
327 } |
|
328 |
|
329 status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const { |
|
330 if (usageCode) { |
|
331 ssize_t index = mKeysByUsageCode.indexOfKey(usageCode); |
|
332 if (index >= 0) { |
|
333 #if DEBUG_MAPPING |
|
334 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.", |
|
335 scanCode, usageCode, *outKeyCode); |
|
336 #endif |
|
337 *outKeyCode = mKeysByUsageCode.valueAt(index); |
|
338 return OK; |
|
339 } |
|
340 } |
|
341 if (scanCode) { |
|
342 ssize_t index = mKeysByScanCode.indexOfKey(scanCode); |
|
343 if (index >= 0) { |
|
344 #if DEBUG_MAPPING |
|
345 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.", |
|
346 scanCode, usageCode, *outKeyCode); |
|
347 #endif |
|
348 *outKeyCode = mKeysByScanCode.valueAt(index); |
|
349 return OK; |
|
350 } |
|
351 } |
|
352 |
|
353 #if DEBUG_MAPPING |
|
354 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode); |
|
355 #endif |
|
356 *outKeyCode = AKEYCODE_UNKNOWN; |
|
357 return NAME_NOT_FOUND; |
|
358 } |
|
359 |
|
360 bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const { |
|
361 ssize_t index = mKeys.indexOfKey(keyCode); |
|
362 if (index >= 0) { |
|
363 *outKey = mKeys.valueAt(index); |
|
364 return true; |
|
365 } |
|
366 return false; |
|
367 } |
|
368 |
|
369 bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState, |
|
370 const Key** outKey, const Behavior** outBehavior) const { |
|
371 const Key* key; |
|
372 if (getKey(keyCode, &key)) { |
|
373 const Behavior* behavior = key->firstBehavior; |
|
374 while (behavior) { |
|
375 if (matchesMetaState(metaState, behavior->metaState)) { |
|
376 *outKey = key; |
|
377 *outBehavior = behavior; |
|
378 return true; |
|
379 } |
|
380 behavior = behavior->next; |
|
381 } |
|
382 } |
|
383 return false; |
|
384 } |
|
385 |
|
386 bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) { |
|
387 // Behavior must have at least the set of meta states specified. |
|
388 // And if the key event has CTRL, ALT or META then the behavior must exactly |
|
389 // match those, taking into account that a behavior can specify that it handles |
|
390 // one, both or either of a left/right modifier pair. |
|
391 if ((eventMetaState & behaviorMetaState) == behaviorMetaState) { |
|
392 const int32_t EXACT_META_STATES = |
|
393 AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON |
|
394 | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON |
|
395 | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON; |
|
396 int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES; |
|
397 if (behaviorMetaState & AMETA_CTRL_ON) { |
|
398 unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON); |
|
399 } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) { |
|
400 unmatchedMetaState &= ~AMETA_CTRL_ON; |
|
401 } |
|
402 if (behaviorMetaState & AMETA_ALT_ON) { |
|
403 unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON); |
|
404 } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) { |
|
405 unmatchedMetaState &= ~AMETA_ALT_ON; |
|
406 } |
|
407 if (behaviorMetaState & AMETA_META_ON) { |
|
408 unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON); |
|
409 } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) { |
|
410 unmatchedMetaState &= ~AMETA_META_ON; |
|
411 } |
|
412 return !unmatchedMetaState; |
|
413 } |
|
414 return false; |
|
415 } |
|
416 |
|
417 bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const { |
|
418 if (!ch) { |
|
419 return false; |
|
420 } |
|
421 |
|
422 for (size_t i = 0; i < mKeys.size(); i++) { |
|
423 const Key* key = mKeys.valueAt(i); |
|
424 |
|
425 // Try to find the most general behavior that maps to this character. |
|
426 // For example, the base key behavior will usually be last in the list. |
|
427 const Behavior* found = NULL; |
|
428 for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { |
|
429 if (behavior->character == ch) { |
|
430 found = behavior; |
|
431 } |
|
432 } |
|
433 if (found) { |
|
434 *outKeyCode = mKeys.keyAt(i); |
|
435 *outMetaState = found->metaState; |
|
436 return true; |
|
437 } |
|
438 } |
|
439 return false; |
|
440 } |
|
441 |
|
442 void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents, |
|
443 int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) { |
|
444 outEvents.push(); |
|
445 KeyEvent& event = outEvents.editTop(); |
|
446 event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD, |
|
447 down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, |
|
448 0, keyCode, 0, metaState, 0, time, time); |
|
449 } |
|
450 |
|
451 void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents, |
|
452 int32_t deviceId, int32_t metaState, bool down, nsecs_t time, |
|
453 int32_t* currentMetaState) { |
|
454 // Add and remove meta keys symmetrically. |
|
455 if (down) { |
|
456 addLockedMetaKey(outEvents, deviceId, metaState, time, |
|
457 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState); |
|
458 addLockedMetaKey(outEvents, deviceId, metaState, time, |
|
459 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState); |
|
460 addLockedMetaKey(outEvents, deviceId, metaState, time, |
|
461 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState); |
|
462 |
|
463 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, |
|
464 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON, |
|
465 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON, |
|
466 AMETA_SHIFT_ON, currentMetaState); |
|
467 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, |
|
468 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON, |
|
469 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON, |
|
470 AMETA_ALT_ON, currentMetaState); |
|
471 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, |
|
472 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON, |
|
473 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON, |
|
474 AMETA_CTRL_ON, currentMetaState); |
|
475 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, |
|
476 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON, |
|
477 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON, |
|
478 AMETA_META_ON, currentMetaState); |
|
479 |
|
480 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, |
|
481 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState); |
|
482 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, |
|
483 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState); |
|
484 } else { |
|
485 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, |
|
486 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState); |
|
487 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, |
|
488 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState); |
|
489 |
|
490 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, |
|
491 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON, |
|
492 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON, |
|
493 AMETA_META_ON, currentMetaState); |
|
494 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, |
|
495 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON, |
|
496 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON, |
|
497 AMETA_CTRL_ON, currentMetaState); |
|
498 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, |
|
499 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON, |
|
500 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON, |
|
501 AMETA_ALT_ON, currentMetaState); |
|
502 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, |
|
503 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON, |
|
504 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON, |
|
505 AMETA_SHIFT_ON, currentMetaState); |
|
506 |
|
507 addLockedMetaKey(outEvents, deviceId, metaState, time, |
|
508 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState); |
|
509 addLockedMetaKey(outEvents, deviceId, metaState, time, |
|
510 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState); |
|
511 addLockedMetaKey(outEvents, deviceId, metaState, time, |
|
512 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState); |
|
513 } |
|
514 } |
|
515 |
|
516 bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents, |
|
517 int32_t deviceId, int32_t metaState, bool down, nsecs_t time, |
|
518 int32_t keyCode, int32_t keyMetaState, |
|
519 int32_t* currentMetaState) { |
|
520 if ((metaState & keyMetaState) == keyMetaState) { |
|
521 *currentMetaState = updateMetaState(keyCode, down, *currentMetaState); |
|
522 addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time); |
|
523 return true; |
|
524 } |
|
525 return false; |
|
526 } |
|
527 |
|
528 void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents, |
|
529 int32_t deviceId, int32_t metaState, bool down, nsecs_t time, |
|
530 int32_t leftKeyCode, int32_t leftKeyMetaState, |
|
531 int32_t rightKeyCode, int32_t rightKeyMetaState, |
|
532 int32_t eitherKeyMetaState, |
|
533 int32_t* currentMetaState) { |
|
534 bool specific = false; |
|
535 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, |
|
536 leftKeyCode, leftKeyMetaState, currentMetaState); |
|
537 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, |
|
538 rightKeyCode, rightKeyMetaState, currentMetaState); |
|
539 |
|
540 if (!specific) { |
|
541 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, |
|
542 leftKeyCode, eitherKeyMetaState, currentMetaState); |
|
543 } |
|
544 } |
|
545 |
|
546 void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents, |
|
547 int32_t deviceId, int32_t metaState, nsecs_t time, |
|
548 int32_t keyCode, int32_t keyMetaState, |
|
549 int32_t* currentMetaState) { |
|
550 if ((metaState & keyMetaState) == keyMetaState) { |
|
551 *currentMetaState = updateMetaState(keyCode, true, *currentMetaState); |
|
552 addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time); |
|
553 *currentMetaState = updateMetaState(keyCode, false, *currentMetaState); |
|
554 addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time); |
|
555 } |
|
556 } |
|
557 |
|
558 #if HAVE_ANDROID_OS |
|
559 sp<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) { |
|
560 sp<KeyCharacterMap> map = new KeyCharacterMap(); |
|
561 map->mType = parcel->readInt32(); |
|
562 size_t numKeys = parcel->readInt32(); |
|
563 if (parcel->errorCheck()) { |
|
564 return NULL; |
|
565 } |
|
566 |
|
567 for (size_t i = 0; i < numKeys; i++) { |
|
568 int32_t keyCode = parcel->readInt32(); |
|
569 char16_t label = parcel->readInt32(); |
|
570 char16_t number = parcel->readInt32(); |
|
571 if (parcel->errorCheck()) { |
|
572 return NULL; |
|
573 } |
|
574 |
|
575 Key* key = new Key(); |
|
576 key->label = label; |
|
577 key->number = number; |
|
578 map->mKeys.add(keyCode, key); |
|
579 |
|
580 Behavior* lastBehavior = NULL; |
|
581 while (parcel->readInt32()) { |
|
582 int32_t metaState = parcel->readInt32(); |
|
583 char16_t character = parcel->readInt32(); |
|
584 int32_t fallbackKeyCode = parcel->readInt32(); |
|
585 if (parcel->errorCheck()) { |
|
586 return NULL; |
|
587 } |
|
588 |
|
589 Behavior* behavior = new Behavior(); |
|
590 behavior->metaState = metaState; |
|
591 behavior->character = character; |
|
592 behavior->fallbackKeyCode = fallbackKeyCode; |
|
593 if (lastBehavior) { |
|
594 lastBehavior->next = behavior; |
|
595 } else { |
|
596 key->firstBehavior = behavior; |
|
597 } |
|
598 lastBehavior = behavior; |
|
599 } |
|
600 |
|
601 if (parcel->errorCheck()) { |
|
602 return NULL; |
|
603 } |
|
604 } |
|
605 return map; |
|
606 } |
|
607 |
|
608 void KeyCharacterMap::writeToParcel(Parcel* parcel) const { |
|
609 parcel->writeInt32(mType); |
|
610 |
|
611 size_t numKeys = mKeys.size(); |
|
612 parcel->writeInt32(numKeys); |
|
613 for (size_t i = 0; i < numKeys; i++) { |
|
614 int32_t keyCode = mKeys.keyAt(i); |
|
615 const Key* key = mKeys.valueAt(i); |
|
616 parcel->writeInt32(keyCode); |
|
617 parcel->writeInt32(key->label); |
|
618 parcel->writeInt32(key->number); |
|
619 for (const Behavior* behavior = key->firstBehavior; behavior != NULL; |
|
620 behavior = behavior->next) { |
|
621 parcel->writeInt32(1); |
|
622 parcel->writeInt32(behavior->metaState); |
|
623 parcel->writeInt32(behavior->character); |
|
624 parcel->writeInt32(behavior->fallbackKeyCode); |
|
625 } |
|
626 parcel->writeInt32(0); |
|
627 } |
|
628 } |
|
629 #endif |
|
630 |
|
631 |
|
632 // --- KeyCharacterMap::Key --- |
|
633 |
|
634 KeyCharacterMap::Key::Key() : |
|
635 label(0), number(0), firstBehavior(NULL) { |
|
636 } |
|
637 |
|
638 KeyCharacterMap::Key::Key(const Key& other) : |
|
639 label(other.label), number(other.number), |
|
640 firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) { |
|
641 } |
|
642 |
|
643 KeyCharacterMap::Key::~Key() { |
|
644 Behavior* behavior = firstBehavior; |
|
645 while (behavior) { |
|
646 Behavior* next = behavior->next; |
|
647 delete behavior; |
|
648 behavior = next; |
|
649 } |
|
650 } |
|
651 |
|
652 |
|
653 // --- KeyCharacterMap::Behavior --- |
|
654 |
|
655 KeyCharacterMap::Behavior::Behavior() : |
|
656 next(NULL), metaState(0), character(0), fallbackKeyCode(0) { |
|
657 } |
|
658 |
|
659 KeyCharacterMap::Behavior::Behavior(const Behavior& other) : |
|
660 next(other.next ? new Behavior(*other.next) : NULL), |
|
661 metaState(other.metaState), character(other.character), |
|
662 fallbackKeyCode(other.fallbackKeyCode) { |
|
663 } |
|
664 |
|
665 |
|
666 // --- KeyCharacterMap::Parser --- |
|
667 |
|
668 KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) : |
|
669 mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) { |
|
670 } |
|
671 |
|
672 KeyCharacterMap::Parser::~Parser() { |
|
673 } |
|
674 |
|
675 status_t KeyCharacterMap::Parser::parse() { |
|
676 while (!mTokenizer->isEof()) { |
|
677 #if DEBUG_PARSER |
|
678 ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), |
|
679 mTokenizer->peekRemainderOfLine().string()); |
|
680 #endif |
|
681 |
|
682 mTokenizer->skipDelimiters(WHITESPACE); |
|
683 |
|
684 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { |
|
685 switch (mState) { |
|
686 case STATE_TOP: { |
|
687 String8 keywordToken = mTokenizer->nextToken(WHITESPACE); |
|
688 if (keywordToken == "type") { |
|
689 mTokenizer->skipDelimiters(WHITESPACE); |
|
690 status_t status = parseType(); |
|
691 if (status) return status; |
|
692 } else if (keywordToken == "map") { |
|
693 mTokenizer->skipDelimiters(WHITESPACE); |
|
694 status_t status = parseMap(); |
|
695 if (status) return status; |
|
696 } else if (keywordToken == "key") { |
|
697 mTokenizer->skipDelimiters(WHITESPACE); |
|
698 status_t status = parseKey(); |
|
699 if (status) return status; |
|
700 } else { |
|
701 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), |
|
702 keywordToken.string()); |
|
703 return BAD_VALUE; |
|
704 } |
|
705 break; |
|
706 } |
|
707 |
|
708 case STATE_KEY: { |
|
709 status_t status = parseKeyProperty(); |
|
710 if (status) return status; |
|
711 break; |
|
712 } |
|
713 } |
|
714 |
|
715 mTokenizer->skipDelimiters(WHITESPACE); |
|
716 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { |
|
717 ALOGE("%s: Expected end of line or trailing comment, got '%s'.", |
|
718 mTokenizer->getLocation().string(), |
|
719 mTokenizer->peekRemainderOfLine().string()); |
|
720 return BAD_VALUE; |
|
721 } |
|
722 } |
|
723 |
|
724 mTokenizer->nextLine(); |
|
725 } |
|
726 |
|
727 if (mState != STATE_TOP) { |
|
728 ALOGE("%s: Unterminated key description at end of file.", |
|
729 mTokenizer->getLocation().string()); |
|
730 return BAD_VALUE; |
|
731 } |
|
732 |
|
733 if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) { |
|
734 ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.", |
|
735 mTokenizer->getLocation().string()); |
|
736 return BAD_VALUE; |
|
737 } |
|
738 |
|
739 if (mFormat == FORMAT_BASE) { |
|
740 if (mMap->mType == KEYBOARD_TYPE_OVERLAY) { |
|
741 ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.", |
|
742 mTokenizer->getLocation().string()); |
|
743 return BAD_VALUE; |
|
744 } |
|
745 } else if (mFormat == FORMAT_OVERLAY) { |
|
746 if (mMap->mType != KEYBOARD_TYPE_OVERLAY) { |
|
747 ALOGE("%s: Overlay keyboard layout missing required keyboard " |
|
748 "'type OVERLAY' declaration.", |
|
749 mTokenizer->getLocation().string()); |
|
750 return BAD_VALUE; |
|
751 } |
|
752 } |
|
753 |
|
754 return NO_ERROR; |
|
755 } |
|
756 |
|
757 status_t KeyCharacterMap::Parser::parseType() { |
|
758 if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) { |
|
759 ALOGE("%s: Duplicate keyboard 'type' declaration.", |
|
760 mTokenizer->getLocation().string()); |
|
761 return BAD_VALUE; |
|
762 } |
|
763 |
|
764 KeyboardType type; |
|
765 String8 typeToken = mTokenizer->nextToken(WHITESPACE); |
|
766 if (typeToken == "NUMERIC") { |
|
767 type = KEYBOARD_TYPE_NUMERIC; |
|
768 } else if (typeToken == "PREDICTIVE") { |
|
769 type = KEYBOARD_TYPE_PREDICTIVE; |
|
770 } else if (typeToken == "ALPHA") { |
|
771 type = KEYBOARD_TYPE_ALPHA; |
|
772 } else if (typeToken == "FULL") { |
|
773 type = KEYBOARD_TYPE_FULL; |
|
774 } else if (typeToken == "SPECIAL_FUNCTION") { |
|
775 type = KEYBOARD_TYPE_SPECIAL_FUNCTION; |
|
776 } else if (typeToken == "OVERLAY") { |
|
777 type = KEYBOARD_TYPE_OVERLAY; |
|
778 } else { |
|
779 ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(), |
|
780 typeToken.string()); |
|
781 return BAD_VALUE; |
|
782 } |
|
783 |
|
784 #if DEBUG_PARSER |
|
785 ALOGD("Parsed type: type=%d.", type); |
|
786 #endif |
|
787 mMap->mType = type; |
|
788 return NO_ERROR; |
|
789 } |
|
790 |
|
791 status_t KeyCharacterMap::Parser::parseMap() { |
|
792 String8 keywordToken = mTokenizer->nextToken(WHITESPACE); |
|
793 if (keywordToken == "key") { |
|
794 mTokenizer->skipDelimiters(WHITESPACE); |
|
795 return parseMapKey(); |
|
796 } |
|
797 ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(), |
|
798 keywordToken.string()); |
|
799 return BAD_VALUE; |
|
800 } |
|
801 |
|
802 status_t KeyCharacterMap::Parser::parseMapKey() { |
|
803 String8 codeToken = mTokenizer->nextToken(WHITESPACE); |
|
804 bool mapUsage = false; |
|
805 if (codeToken == "usage") { |
|
806 mapUsage = true; |
|
807 mTokenizer->skipDelimiters(WHITESPACE); |
|
808 codeToken = mTokenizer->nextToken(WHITESPACE); |
|
809 } |
|
810 |
|
811 char* end; |
|
812 int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); |
|
813 if (*end) { |
|
814 ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), |
|
815 mapUsage ? "usage" : "scan code", codeToken.string()); |
|
816 return BAD_VALUE; |
|
817 } |
|
818 KeyedVector<int32_t, int32_t>& map = |
|
819 mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; |
|
820 if (map.indexOfKey(code) >= 0) { |
|
821 ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), |
|
822 mapUsage ? "usage" : "scan code", codeToken.string()); |
|
823 return BAD_VALUE; |
|
824 } |
|
825 |
|
826 mTokenizer->skipDelimiters(WHITESPACE); |
|
827 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); |
|
828 int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); |
|
829 if (!keyCode) { |
|
830 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), |
|
831 keyCodeToken.string()); |
|
832 return BAD_VALUE; |
|
833 } |
|
834 |
|
835 #if DEBUG_PARSER |
|
836 ALOGD("Parsed map key %s: code=%d, keyCode=%d.", |
|
837 mapUsage ? "usage" : "scan code", code, keyCode); |
|
838 #endif |
|
839 map.add(code, keyCode); |
|
840 return NO_ERROR; |
|
841 } |
|
842 |
|
843 status_t KeyCharacterMap::Parser::parseKey() { |
|
844 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); |
|
845 int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); |
|
846 if (!keyCode) { |
|
847 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), |
|
848 keyCodeToken.string()); |
|
849 return BAD_VALUE; |
|
850 } |
|
851 if (mMap->mKeys.indexOfKey(keyCode) >= 0) { |
|
852 ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(), |
|
853 keyCodeToken.string()); |
|
854 return BAD_VALUE; |
|
855 } |
|
856 |
|
857 mTokenizer->skipDelimiters(WHITESPACE); |
|
858 String8 openBraceToken = mTokenizer->nextToken(WHITESPACE); |
|
859 if (openBraceToken != "{") { |
|
860 ALOGE("%s: Expected '{' after key code label, got '%s'.", |
|
861 mTokenizer->getLocation().string(), openBraceToken.string()); |
|
862 return BAD_VALUE; |
|
863 } |
|
864 |
|
865 #if DEBUG_PARSER |
|
866 ALOGD("Parsed beginning of key: keyCode=%d.", keyCode); |
|
867 #endif |
|
868 mKeyCode = keyCode; |
|
869 mMap->mKeys.add(keyCode, new Key()); |
|
870 mState = STATE_KEY; |
|
871 return NO_ERROR; |
|
872 } |
|
873 |
|
874 status_t KeyCharacterMap::Parser::parseKeyProperty() { |
|
875 Key* key = mMap->mKeys.valueFor(mKeyCode); |
|
876 String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); |
|
877 if (token == "}") { |
|
878 mState = STATE_TOP; |
|
879 return finishKey(key); |
|
880 } |
|
881 |
|
882 Vector<Property> properties; |
|
883 |
|
884 // Parse all comma-delimited property names up to the first colon. |
|
885 for (;;) { |
|
886 if (token == "label") { |
|
887 properties.add(Property(PROPERTY_LABEL)); |
|
888 } else if (token == "number") { |
|
889 properties.add(Property(PROPERTY_NUMBER)); |
|
890 } else { |
|
891 int32_t metaState; |
|
892 status_t status = parseModifier(token, &metaState); |
|
893 if (status) { |
|
894 ALOGE("%s: Expected a property name or modifier, got '%s'.", |
|
895 mTokenizer->getLocation().string(), token.string()); |
|
896 return status; |
|
897 } |
|
898 properties.add(Property(PROPERTY_META, metaState)); |
|
899 } |
|
900 |
|
901 mTokenizer->skipDelimiters(WHITESPACE); |
|
902 if (!mTokenizer->isEol()) { |
|
903 char ch = mTokenizer->nextChar(); |
|
904 if (ch == ':') { |
|
905 break; |
|
906 } else if (ch == ',') { |
|
907 mTokenizer->skipDelimiters(WHITESPACE); |
|
908 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); |
|
909 continue; |
|
910 } |
|
911 } |
|
912 |
|
913 ALOGE("%s: Expected ',' or ':' after property name.", |
|
914 mTokenizer->getLocation().string()); |
|
915 return BAD_VALUE; |
|
916 } |
|
917 |
|
918 // Parse behavior after the colon. |
|
919 mTokenizer->skipDelimiters(WHITESPACE); |
|
920 |
|
921 Behavior behavior; |
|
922 bool haveCharacter = false; |
|
923 bool haveFallback = false; |
|
924 |
|
925 do { |
|
926 char ch = mTokenizer->peekChar(); |
|
927 if (ch == '\'') { |
|
928 char16_t character; |
|
929 status_t status = parseCharacterLiteral(&character); |
|
930 if (status || !character) { |
|
931 ALOGE("%s: Invalid character literal for key.", |
|
932 mTokenizer->getLocation().string()); |
|
933 return BAD_VALUE; |
|
934 } |
|
935 if (haveCharacter) { |
|
936 ALOGE("%s: Cannot combine multiple character literals or 'none'.", |
|
937 mTokenizer->getLocation().string()); |
|
938 return BAD_VALUE; |
|
939 } |
|
940 behavior.character = character; |
|
941 haveCharacter = true; |
|
942 } else { |
|
943 token = mTokenizer->nextToken(WHITESPACE); |
|
944 if (token == "none") { |
|
945 if (haveCharacter) { |
|
946 ALOGE("%s: Cannot combine multiple character literals or 'none'.", |
|
947 mTokenizer->getLocation().string()); |
|
948 return BAD_VALUE; |
|
949 } |
|
950 haveCharacter = true; |
|
951 } else if (token == "fallback") { |
|
952 mTokenizer->skipDelimiters(WHITESPACE); |
|
953 token = mTokenizer->nextToken(WHITESPACE); |
|
954 int32_t keyCode = getKeyCodeByLabel(token.string()); |
|
955 if (!keyCode) { |
|
956 ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.", |
|
957 mTokenizer->getLocation().string(), |
|
958 token.string()); |
|
959 return BAD_VALUE; |
|
960 } |
|
961 if (haveFallback) { |
|
962 ALOGE("%s: Cannot combine multiple fallback key codes.", |
|
963 mTokenizer->getLocation().string()); |
|
964 return BAD_VALUE; |
|
965 } |
|
966 behavior.fallbackKeyCode = keyCode; |
|
967 haveFallback = true; |
|
968 } else { |
|
969 ALOGE("%s: Expected a key behavior after ':'.", |
|
970 mTokenizer->getLocation().string()); |
|
971 return BAD_VALUE; |
|
972 } |
|
973 } |
|
974 |
|
975 mTokenizer->skipDelimiters(WHITESPACE); |
|
976 } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#'); |
|
977 |
|
978 // Add the behavior. |
|
979 for (size_t i = 0; i < properties.size(); i++) { |
|
980 const Property& property = properties.itemAt(i); |
|
981 switch (property.property) { |
|
982 case PROPERTY_LABEL: |
|
983 if (key->label) { |
|
984 ALOGE("%s: Duplicate label for key.", |
|
985 mTokenizer->getLocation().string()); |
|
986 return BAD_VALUE; |
|
987 } |
|
988 key->label = behavior.character; |
|
989 #if DEBUG_PARSER |
|
990 ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label); |
|
991 #endif |
|
992 break; |
|
993 case PROPERTY_NUMBER: |
|
994 if (key->number) { |
|
995 ALOGE("%s: Duplicate number for key.", |
|
996 mTokenizer->getLocation().string()); |
|
997 return BAD_VALUE; |
|
998 } |
|
999 key->number = behavior.character; |
|
1000 #if DEBUG_PARSER |
|
1001 ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number); |
|
1002 #endif |
|
1003 break; |
|
1004 case PROPERTY_META: { |
|
1005 for (Behavior* b = key->firstBehavior; b; b = b->next) { |
|
1006 if (b->metaState == property.metaState) { |
|
1007 ALOGE("%s: Duplicate key behavior for modifier.", |
|
1008 mTokenizer->getLocation().string()); |
|
1009 return BAD_VALUE; |
|
1010 } |
|
1011 } |
|
1012 Behavior* newBehavior = new Behavior(behavior); |
|
1013 newBehavior->metaState = property.metaState; |
|
1014 newBehavior->next = key->firstBehavior; |
|
1015 key->firstBehavior = newBehavior; |
|
1016 #if DEBUG_PARSER |
|
1017 ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d.", mKeyCode, |
|
1018 newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode); |
|
1019 #endif |
|
1020 break; |
|
1021 } |
|
1022 } |
|
1023 } |
|
1024 return NO_ERROR; |
|
1025 } |
|
1026 |
|
1027 status_t KeyCharacterMap::Parser::finishKey(Key* key) { |
|
1028 // Fill in default number property. |
|
1029 if (!key->number) { |
|
1030 char16_t digit = 0; |
|
1031 char16_t symbol = 0; |
|
1032 for (Behavior* b = key->firstBehavior; b; b = b->next) { |
|
1033 char16_t ch = b->character; |
|
1034 if (ch) { |
|
1035 if (ch >= '0' && ch <= '9') { |
|
1036 digit = ch; |
|
1037 } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*' |
|
1038 || ch == '-' || ch == '+' || ch == ',' || ch == '.' |
|
1039 || ch == '\'' || ch == ':' || ch == ';' || ch == '/') { |
|
1040 symbol = ch; |
|
1041 } |
|
1042 } |
|
1043 } |
|
1044 key->number = digit ? digit : symbol; |
|
1045 } |
|
1046 return NO_ERROR; |
|
1047 } |
|
1048 |
|
1049 status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) { |
|
1050 if (token == "base") { |
|
1051 *outMetaState = 0; |
|
1052 return NO_ERROR; |
|
1053 } |
|
1054 |
|
1055 int32_t combinedMeta = 0; |
|
1056 |
|
1057 const char* str = token.string(); |
|
1058 const char* start = str; |
|
1059 for (const char* cur = str; ; cur++) { |
|
1060 char ch = *cur; |
|
1061 if (ch == '+' || ch == '\0') { |
|
1062 size_t len = cur - start; |
|
1063 int32_t metaState = 0; |
|
1064 for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) { |
|
1065 if (strlen(modifiers[i].label) == len |
|
1066 && strncmp(modifiers[i].label, start, len) == 0) { |
|
1067 metaState = modifiers[i].metaState; |
|
1068 break; |
|
1069 } |
|
1070 } |
|
1071 if (!metaState) { |
|
1072 return BAD_VALUE; |
|
1073 } |
|
1074 if (combinedMeta & metaState) { |
|
1075 ALOGE("%s: Duplicate modifier combination '%s'.", |
|
1076 mTokenizer->getLocation().string(), token.string()); |
|
1077 return BAD_VALUE; |
|
1078 } |
|
1079 |
|
1080 combinedMeta |= metaState; |
|
1081 start = cur + 1; |
|
1082 |
|
1083 if (ch == '\0') { |
|
1084 break; |
|
1085 } |
|
1086 } |
|
1087 } |
|
1088 *outMetaState = combinedMeta; |
|
1089 return NO_ERROR; |
|
1090 } |
|
1091 |
|
1092 status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) { |
|
1093 char ch = mTokenizer->nextChar(); |
|
1094 if (ch != '\'') { |
|
1095 goto Error; |
|
1096 } |
|
1097 |
|
1098 ch = mTokenizer->nextChar(); |
|
1099 if (ch == '\\') { |
|
1100 // Escape sequence. |
|
1101 ch = mTokenizer->nextChar(); |
|
1102 if (ch == 'n') { |
|
1103 *outCharacter = '\n'; |
|
1104 } else if (ch == 't') { |
|
1105 *outCharacter = '\t'; |
|
1106 } else if (ch == '\\') { |
|
1107 *outCharacter = '\\'; |
|
1108 } else if (ch == '\'') { |
|
1109 *outCharacter = '\''; |
|
1110 } else if (ch == '"') { |
|
1111 *outCharacter = '"'; |
|
1112 } else if (ch == 'u') { |
|
1113 *outCharacter = 0; |
|
1114 for (int i = 0; i < 4; i++) { |
|
1115 ch = mTokenizer->nextChar(); |
|
1116 int digit; |
|
1117 if (ch >= '0' && ch <= '9') { |
|
1118 digit = ch - '0'; |
|
1119 } else if (ch >= 'A' && ch <= 'F') { |
|
1120 digit = ch - 'A' + 10; |
|
1121 } else if (ch >= 'a' && ch <= 'f') { |
|
1122 digit = ch - 'a' + 10; |
|
1123 } else { |
|
1124 goto Error; |
|
1125 } |
|
1126 *outCharacter = (*outCharacter << 4) | digit; |
|
1127 } |
|
1128 } else { |
|
1129 goto Error; |
|
1130 } |
|
1131 } else if (ch >= 32 && ch <= 126 && ch != '\'') { |
|
1132 // ASCII literal character. |
|
1133 *outCharacter = ch; |
|
1134 } else { |
|
1135 goto Error; |
|
1136 } |
|
1137 |
|
1138 ch = mTokenizer->nextChar(); |
|
1139 if (ch != '\'') { |
|
1140 goto Error; |
|
1141 } |
|
1142 |
|
1143 // Ensure that we consumed the entire token. |
|
1144 if (mTokenizer->nextToken(WHITESPACE).isEmpty()) { |
|
1145 return NO_ERROR; |
|
1146 } |
|
1147 |
|
1148 Error: |
|
1149 ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string()); |
|
1150 return BAD_VALUE; |
|
1151 } |
|
1152 |
|
1153 } // namespace android |