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