KeyCharacterMap.cpp revision 115f93eeebf7f33b56ed090de70d6e8c733e5d88
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
46namespace android {
47
48static const char* WHITESPACE = " \t\r";
49static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:";
50
51struct Modifier {
52    const char* label;
53    int32_t metaState;
54};
55static 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
76static 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
88sp<KeyCharacterMap> KeyCharacterMap::sEmpty = new KeyCharacterMap();
89
90KeyCharacterMap::KeyCharacterMap() :
91    mType(KEYBOARD_TYPE_UNKNOWN) {
92}
93
94KeyCharacterMap::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
102KeyCharacterMap::~KeyCharacterMap() {
103    for (size_t i = 0; i < mKeys.size(); i++) {
104        Key* key = mKeys.editValueAt(i);
105        delete key;
106    }
107}
108
109status_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
124status_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
139status_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
165sp<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
199sp<KeyCharacterMap> KeyCharacterMap::empty() {
200    return sEmpty;
201}
202
203int32_t KeyCharacterMap::getKeyboardType() const {
204    return mType;
205}
206
207char16_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
219char16_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
231char16_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
244bool 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
268char16_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
298bool 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
331status_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            *outKeyCode = mKeysByUsageCode.valueAt(index);
336#if DEBUG_MAPPING
337            ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
338                    scanCode, usageCode, *outKeyCode);
339#endif
340            return OK;
341        }
342    }
343    if (scanCode) {
344        ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
345        if (index >= 0) {
346            *outKeyCode = mKeysByScanCode.valueAt(index);
347#if DEBUG_MAPPING
348            ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
349                    scanCode, usageCode, *outKeyCode);
350#endif
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
362void KeyCharacterMap::tryRemapKey(int32_t keyCode, int32_t metaState,
363                                  int32_t *outKeyCode, int32_t *outMetaState) const {
364    *outKeyCode = keyCode;
365    *outMetaState = metaState;
366
367    const Key* key;
368    const Behavior* behavior;
369    if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
370        if (behavior->replacementKeyCode) {
371            *outKeyCode = behavior->replacementKeyCode;
372            int32_t newMetaState = metaState & ~behavior->metaState;
373            // Reset dependent meta states.
374            if (behavior->metaState & AMETA_ALT_ON) {
375                newMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
376            }
377            if (behavior->metaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
378                newMetaState &= ~AMETA_ALT_ON;
379            }
380            if (behavior->metaState & AMETA_CTRL_ON) {
381                newMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
382            }
383            if (behavior->metaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
384                newMetaState &= ~AMETA_CTRL_ON;
385            }
386            if (behavior->metaState & AMETA_SHIFT_ON) {
387                newMetaState &= ~(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON);
388            }
389            if (behavior->metaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
390                newMetaState &= ~AMETA_SHIFT_ON;
391            }
392            // ... and put universal bits back if needed
393            *outMetaState = normalizeMetaState(newMetaState);
394        }
395    }
396
397#if DEBUG_MAPPING
398    ALOGD("tryRemapKey: keyCode=%d, metaState=0x%08x ~ "
399            "replacement keyCode=%d, replacement metaState=0x%08x.",
400            keyCode, metaState, *outKeyCode, *outMetaState);
401#endif
402}
403
404bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
405    ssize_t index = mKeys.indexOfKey(keyCode);
406    if (index >= 0) {
407        *outKey = mKeys.valueAt(index);
408        return true;
409    }
410    return false;
411}
412
413bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState,
414        const Key** outKey, const Behavior** outBehavior) const {
415    const Key* key;
416    if (getKey(keyCode, &key)) {
417        const Behavior* behavior = key->firstBehavior;
418        while (behavior) {
419            if (matchesMetaState(metaState, behavior->metaState)) {
420                *outKey = key;
421                *outBehavior = behavior;
422                return true;
423            }
424            behavior = behavior->next;
425        }
426    }
427    return false;
428}
429
430bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
431    // Behavior must have at least the set of meta states specified.
432    // And if the key event has CTRL, ALT or META then the behavior must exactly
433    // match those, taking into account that a behavior can specify that it handles
434    // one, both or either of a left/right modifier pair.
435    if ((eventMetaState & behaviorMetaState) == behaviorMetaState) {
436        const int32_t EXACT_META_STATES =
437                AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON
438                | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON
439                | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON;
440        int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES;
441        if (behaviorMetaState & AMETA_CTRL_ON) {
442            unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
443        } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
444            unmatchedMetaState &= ~AMETA_CTRL_ON;
445        }
446        if (behaviorMetaState & AMETA_ALT_ON) {
447            unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
448        } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
449            unmatchedMetaState &= ~AMETA_ALT_ON;
450        }
451        if (behaviorMetaState & AMETA_META_ON) {
452            unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
453        } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
454            unmatchedMetaState &= ~AMETA_META_ON;
455        }
456        return !unmatchedMetaState;
457    }
458    return false;
459}
460
461bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
462    if (!ch) {
463        return false;
464    }
465
466    for (size_t i = 0; i < mKeys.size(); i++) {
467        const Key* key = mKeys.valueAt(i);
468
469        // Try to find the most general behavior that maps to this character.
470        // For example, the base key behavior will usually be last in the list.
471        const Behavior* found = NULL;
472        for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
473            if (behavior->character == ch) {
474                found = behavior;
475            }
476        }
477        if (found) {
478            *outKeyCode = mKeys.keyAt(i);
479            *outMetaState = found->metaState;
480            return true;
481        }
482    }
483    return false;
484}
485
486void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents,
487        int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
488    outEvents.push();
489    KeyEvent& event = outEvents.editTop();
490    event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD,
491            down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
492            0, keyCode, 0, metaState, 0, time, time);
493}
494
495void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
496        int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
497        int32_t* currentMetaState) {
498    // Add and remove meta keys symmetrically.
499    if (down) {
500        addLockedMetaKey(outEvents, deviceId, metaState, time,
501                AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
502        addLockedMetaKey(outEvents, deviceId, metaState, time,
503                AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
504        addLockedMetaKey(outEvents, deviceId, metaState, time,
505                AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
506
507        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
508                AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
509                AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
510                AMETA_SHIFT_ON, currentMetaState);
511        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
512                AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
513                AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
514                AMETA_ALT_ON, currentMetaState);
515        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
516                AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
517                AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
518                AMETA_CTRL_ON, currentMetaState);
519        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
520                AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
521                AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
522                AMETA_META_ON, currentMetaState);
523
524        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
525                AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
526        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
527                AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
528    } else {
529        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
530                AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
531        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
532                AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
533
534        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
535                AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
536                AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
537                AMETA_META_ON, currentMetaState);
538        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
539                AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
540                AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
541                AMETA_CTRL_ON, currentMetaState);
542        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
543                AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
544                AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
545                AMETA_ALT_ON, currentMetaState);
546        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
547                AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
548                AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
549                AMETA_SHIFT_ON, currentMetaState);
550
551        addLockedMetaKey(outEvents, deviceId, metaState, time,
552                AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
553        addLockedMetaKey(outEvents, deviceId, metaState, time,
554                AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
555        addLockedMetaKey(outEvents, deviceId, metaState, time,
556                AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
557    }
558}
559
560bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
561        int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
562        int32_t keyCode, int32_t keyMetaState,
563        int32_t* currentMetaState) {
564    if ((metaState & keyMetaState) == keyMetaState) {
565        *currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
566        addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
567        return true;
568    }
569    return false;
570}
571
572void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
573        int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
574        int32_t leftKeyCode, int32_t leftKeyMetaState,
575        int32_t rightKeyCode, int32_t rightKeyMetaState,
576        int32_t eitherKeyMetaState,
577        int32_t* currentMetaState) {
578    bool specific = false;
579    specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
580            leftKeyCode, leftKeyMetaState, currentMetaState);
581    specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
582            rightKeyCode, rightKeyMetaState, currentMetaState);
583
584    if (!specific) {
585        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
586                leftKeyCode, eitherKeyMetaState, currentMetaState);
587    }
588}
589
590void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
591        int32_t deviceId, int32_t metaState, nsecs_t time,
592        int32_t keyCode, int32_t keyMetaState,
593        int32_t* currentMetaState) {
594    if ((metaState & keyMetaState) == keyMetaState) {
595        *currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
596        addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
597        *currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
598        addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
599    }
600}
601
602#if HAVE_ANDROID_OS
603sp<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
604    sp<KeyCharacterMap> map = new KeyCharacterMap();
605    map->mType = parcel->readInt32();
606    size_t numKeys = parcel->readInt32();
607    if (parcel->errorCheck()) {
608        return NULL;
609    }
610
611    for (size_t i = 0; i < numKeys; i++) {
612        int32_t keyCode = parcel->readInt32();
613        char16_t label = parcel->readInt32();
614        char16_t number = parcel->readInt32();
615        if (parcel->errorCheck()) {
616            return NULL;
617        }
618
619        Key* key = new Key();
620        key->label = label;
621        key->number = number;
622        map->mKeys.add(keyCode, key);
623
624        Behavior* lastBehavior = NULL;
625        while (parcel->readInt32()) {
626            int32_t metaState = parcel->readInt32();
627            char16_t character = parcel->readInt32();
628            int32_t fallbackKeyCode = parcel->readInt32();
629            int32_t replacementKeyCode = parcel->readInt32();
630            if (parcel->errorCheck()) {
631                return NULL;
632            }
633
634            Behavior* behavior = new Behavior();
635            behavior->metaState = metaState;
636            behavior->character = character;
637            behavior->fallbackKeyCode = fallbackKeyCode;
638            behavior->replacementKeyCode = replacementKeyCode;
639            if (lastBehavior) {
640                lastBehavior->next = behavior;
641            } else {
642                key->firstBehavior = behavior;
643            }
644            lastBehavior = behavior;
645        }
646
647        if (parcel->errorCheck()) {
648            return NULL;
649        }
650    }
651    return map;
652}
653
654void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
655    parcel->writeInt32(mType);
656
657    size_t numKeys = mKeys.size();
658    parcel->writeInt32(numKeys);
659    for (size_t i = 0; i < numKeys; i++) {
660        int32_t keyCode = mKeys.keyAt(i);
661        const Key* key = mKeys.valueAt(i);
662        parcel->writeInt32(keyCode);
663        parcel->writeInt32(key->label);
664        parcel->writeInt32(key->number);
665        for (const Behavior* behavior = key->firstBehavior; behavior != NULL;
666                behavior = behavior->next) {
667            parcel->writeInt32(1);
668            parcel->writeInt32(behavior->metaState);
669            parcel->writeInt32(behavior->character);
670            parcel->writeInt32(behavior->fallbackKeyCode);
671            parcel->writeInt32(behavior->replacementKeyCode);
672        }
673        parcel->writeInt32(0);
674    }
675}
676#endif
677
678
679// --- KeyCharacterMap::Key ---
680
681KeyCharacterMap::Key::Key() :
682        label(0), number(0), firstBehavior(NULL) {
683}
684
685KeyCharacterMap::Key::Key(const Key& other) :
686        label(other.label), number(other.number),
687        firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) {
688}
689
690KeyCharacterMap::Key::~Key() {
691    Behavior* behavior = firstBehavior;
692    while (behavior) {
693        Behavior* next = behavior->next;
694        delete behavior;
695        behavior = next;
696    }
697}
698
699
700// --- KeyCharacterMap::Behavior ---
701
702KeyCharacterMap::Behavior::Behavior() :
703        next(NULL), metaState(0), character(0), fallbackKeyCode(0), replacementKeyCode(0) {
704}
705
706KeyCharacterMap::Behavior::Behavior(const Behavior& other) :
707        next(other.next ? new Behavior(*other.next) : NULL),
708        metaState(other.metaState), character(other.character),
709        fallbackKeyCode(other.fallbackKeyCode),
710        replacementKeyCode(other.replacementKeyCode) {
711}
712
713
714// --- KeyCharacterMap::Parser ---
715
716KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
717        mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
718}
719
720KeyCharacterMap::Parser::~Parser() {
721}
722
723status_t KeyCharacterMap::Parser::parse() {
724    while (!mTokenizer->isEof()) {
725#if DEBUG_PARSER
726        ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
727                mTokenizer->peekRemainderOfLine().string());
728#endif
729
730        mTokenizer->skipDelimiters(WHITESPACE);
731
732        if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
733            switch (mState) {
734            case STATE_TOP: {
735                String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
736                if (keywordToken == "type") {
737                    mTokenizer->skipDelimiters(WHITESPACE);
738                    status_t status = parseType();
739                    if (status) return status;
740                } else if (keywordToken == "map") {
741                    mTokenizer->skipDelimiters(WHITESPACE);
742                    status_t status = parseMap();
743                    if (status) return status;
744                } else if (keywordToken == "key") {
745                    mTokenizer->skipDelimiters(WHITESPACE);
746                    status_t status = parseKey();
747                    if (status) return status;
748                } else {
749                    ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
750                            keywordToken.string());
751                    return BAD_VALUE;
752                }
753                break;
754            }
755
756            case STATE_KEY: {
757                status_t status = parseKeyProperty();
758                if (status) return status;
759                break;
760            }
761            }
762
763            mTokenizer->skipDelimiters(WHITESPACE);
764            if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
765                ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
766                        mTokenizer->getLocation().string(),
767                        mTokenizer->peekRemainderOfLine().string());
768                return BAD_VALUE;
769            }
770        }
771
772        mTokenizer->nextLine();
773    }
774
775    if (mState != STATE_TOP) {
776        ALOGE("%s: Unterminated key description at end of file.",
777                mTokenizer->getLocation().string());
778        return BAD_VALUE;
779    }
780
781    if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
782        ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
783                mTokenizer->getLocation().string());
784        return BAD_VALUE;
785    }
786
787    if (mFormat == FORMAT_BASE) {
788        if (mMap->mType == KEYBOARD_TYPE_OVERLAY) {
789            ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
790                    mTokenizer->getLocation().string());
791            return BAD_VALUE;
792        }
793    } else if (mFormat == FORMAT_OVERLAY) {
794        if (mMap->mType != KEYBOARD_TYPE_OVERLAY) {
795            ALOGE("%s: Overlay keyboard layout missing required keyboard "
796                    "'type OVERLAY' declaration.",
797                    mTokenizer->getLocation().string());
798            return BAD_VALUE;
799        }
800    }
801
802    return NO_ERROR;
803}
804
805status_t KeyCharacterMap::Parser::parseType() {
806    if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) {
807        ALOGE("%s: Duplicate keyboard 'type' declaration.",
808                mTokenizer->getLocation().string());
809        return BAD_VALUE;
810    }
811
812    KeyboardType type;
813    String8 typeToken = mTokenizer->nextToken(WHITESPACE);
814    if (typeToken == "NUMERIC") {
815        type = KEYBOARD_TYPE_NUMERIC;
816    } else if (typeToken == "PREDICTIVE") {
817        type = KEYBOARD_TYPE_PREDICTIVE;
818    } else if (typeToken == "ALPHA") {
819        type = KEYBOARD_TYPE_ALPHA;
820    } else if (typeToken == "FULL") {
821        type = KEYBOARD_TYPE_FULL;
822    } else if (typeToken == "SPECIAL_FUNCTION") {
823        type = KEYBOARD_TYPE_SPECIAL_FUNCTION;
824    } else if (typeToken == "OVERLAY") {
825        type = KEYBOARD_TYPE_OVERLAY;
826    } else {
827        ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(),
828                typeToken.string());
829        return BAD_VALUE;
830    }
831
832#if DEBUG_PARSER
833    ALOGD("Parsed type: type=%d.", type);
834#endif
835    mMap->mType = type;
836    return NO_ERROR;
837}
838
839status_t KeyCharacterMap::Parser::parseMap() {
840    String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
841    if (keywordToken == "key") {
842        mTokenizer->skipDelimiters(WHITESPACE);
843        return parseMapKey();
844    }
845    ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(),
846            keywordToken.string());
847    return BAD_VALUE;
848}
849
850status_t KeyCharacterMap::Parser::parseMapKey() {
851    String8 codeToken = mTokenizer->nextToken(WHITESPACE);
852    bool mapUsage = false;
853    if (codeToken == "usage") {
854        mapUsage = true;
855        mTokenizer->skipDelimiters(WHITESPACE);
856        codeToken = mTokenizer->nextToken(WHITESPACE);
857    }
858
859    char* end;
860    int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
861    if (*end) {
862        ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
863                mapUsage ? "usage" : "scan code", codeToken.string());
864        return BAD_VALUE;
865    }
866    KeyedVector<int32_t, int32_t>& map =
867            mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
868    if (map.indexOfKey(code) >= 0) {
869        ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
870                mapUsage ? "usage" : "scan code", codeToken.string());
871        return BAD_VALUE;
872    }
873
874    mTokenizer->skipDelimiters(WHITESPACE);
875    String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
876    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
877    if (!keyCode) {
878        ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
879                keyCodeToken.string());
880        return BAD_VALUE;
881    }
882
883#if DEBUG_PARSER
884    ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
885            mapUsage ? "usage" : "scan code", code, keyCode);
886#endif
887    map.add(code, keyCode);
888    return NO_ERROR;
889}
890
891status_t KeyCharacterMap::Parser::parseKey() {
892    String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
893    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
894    if (!keyCode) {
895        ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
896                keyCodeToken.string());
897        return BAD_VALUE;
898    }
899    if (mMap->mKeys.indexOfKey(keyCode) >= 0) {
900        ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(),
901                keyCodeToken.string());
902        return BAD_VALUE;
903    }
904
905    mTokenizer->skipDelimiters(WHITESPACE);
906    String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
907    if (openBraceToken != "{") {
908        ALOGE("%s: Expected '{' after key code label, got '%s'.",
909                mTokenizer->getLocation().string(), openBraceToken.string());
910        return BAD_VALUE;
911    }
912
913#if DEBUG_PARSER
914    ALOGD("Parsed beginning of key: keyCode=%d.", keyCode);
915#endif
916    mKeyCode = keyCode;
917    mMap->mKeys.add(keyCode, new Key());
918    mState = STATE_KEY;
919    return NO_ERROR;
920}
921
922status_t KeyCharacterMap::Parser::parseKeyProperty() {
923    Key* key = mMap->mKeys.valueFor(mKeyCode);
924    String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
925    if (token == "}") {
926        mState = STATE_TOP;
927        return finishKey(key);
928    }
929
930    Vector<Property> properties;
931
932    // Parse all comma-delimited property names up to the first colon.
933    for (;;) {
934        if (token == "label") {
935            properties.add(Property(PROPERTY_LABEL));
936        } else if (token == "number") {
937            properties.add(Property(PROPERTY_NUMBER));
938        } else {
939            int32_t metaState;
940            status_t status = parseModifier(token, &metaState);
941            if (status) {
942                ALOGE("%s: Expected a property name or modifier, got '%s'.",
943                        mTokenizer->getLocation().string(), token.string());
944                return status;
945            }
946            properties.add(Property(PROPERTY_META, metaState));
947        }
948
949        mTokenizer->skipDelimiters(WHITESPACE);
950        if (!mTokenizer->isEol()) {
951            char ch = mTokenizer->nextChar();
952            if (ch == ':') {
953                break;
954            } else if (ch == ',') {
955                mTokenizer->skipDelimiters(WHITESPACE);
956                token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
957                continue;
958            }
959        }
960
961        ALOGE("%s: Expected ',' or ':' after property name.",
962                mTokenizer->getLocation().string());
963        return BAD_VALUE;
964    }
965
966    // Parse behavior after the colon.
967    mTokenizer->skipDelimiters(WHITESPACE);
968
969    Behavior behavior;
970    bool haveCharacter = false;
971    bool haveFallback = false;
972    bool haveReplacement = false;
973
974    do {
975        char ch = mTokenizer->peekChar();
976        if (ch == '\'') {
977            char16_t character;
978            status_t status = parseCharacterLiteral(&character);
979            if (status || !character) {
980                ALOGE("%s: Invalid character literal for key.",
981                        mTokenizer->getLocation().string());
982                return BAD_VALUE;
983            }
984            if (haveCharacter) {
985                ALOGE("%s: Cannot combine multiple character literals or 'none'.",
986                        mTokenizer->getLocation().string());
987                return BAD_VALUE;
988            }
989            if (haveReplacement) {
990                ALOGE("%s: Cannot combine character literal with replace action.",
991                        mTokenizer->getLocation().string());
992                return BAD_VALUE;
993            }
994            behavior.character = character;
995            haveCharacter = true;
996        } else {
997            token = mTokenizer->nextToken(WHITESPACE);
998            if (token == "none") {
999                if (haveCharacter) {
1000                    ALOGE("%s: Cannot combine multiple character literals or 'none'.",
1001                            mTokenizer->getLocation().string());
1002                    return BAD_VALUE;
1003                }
1004                if (haveReplacement) {
1005                    ALOGE("%s: Cannot combine 'none' with replace action.",
1006                            mTokenizer->getLocation().string());
1007                    return BAD_VALUE;
1008                }
1009                haveCharacter = true;
1010            } else if (token == "fallback") {
1011                mTokenizer->skipDelimiters(WHITESPACE);
1012                token = mTokenizer->nextToken(WHITESPACE);
1013                int32_t keyCode = getKeyCodeByLabel(token.string());
1014                if (!keyCode) {
1015                    ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
1016                            mTokenizer->getLocation().string(),
1017                            token.string());
1018                    return BAD_VALUE;
1019                }
1020                if (haveFallback || haveReplacement) {
1021                    ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
1022                            mTokenizer->getLocation().string());
1023                    return BAD_VALUE;
1024                }
1025                behavior.fallbackKeyCode = keyCode;
1026                haveFallback = true;
1027            } else if (token == "replace") {
1028                mTokenizer->skipDelimiters(WHITESPACE);
1029                token = mTokenizer->nextToken(WHITESPACE);
1030                int32_t keyCode = getKeyCodeByLabel(token.string());
1031                if (!keyCode) {
1032                    ALOGE("%s: Invalid key code label for replace, got '%s'.",
1033                            mTokenizer->getLocation().string(),
1034                            token.string());
1035                    return BAD_VALUE;
1036                }
1037                if (haveCharacter) {
1038                    ALOGE("%s: Cannot combine character literal with replace action.",
1039                            mTokenizer->getLocation().string());
1040                    return BAD_VALUE;
1041                }
1042                if (haveFallback || haveReplacement) {
1043                    ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
1044                            mTokenizer->getLocation().string());
1045                    return BAD_VALUE;
1046                }
1047                behavior.replacementKeyCode = keyCode;
1048                haveReplacement = true;
1049
1050            } else {
1051                ALOGE("%s: Expected a key behavior after ':'.",
1052                        mTokenizer->getLocation().string());
1053                return BAD_VALUE;
1054            }
1055        }
1056
1057        mTokenizer->skipDelimiters(WHITESPACE);
1058    } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#');
1059
1060    // Add the behavior.
1061    for (size_t i = 0; i < properties.size(); i++) {
1062        const Property& property = properties.itemAt(i);
1063        switch (property.property) {
1064        case PROPERTY_LABEL:
1065            if (key->label) {
1066                ALOGE("%s: Duplicate label for key.",
1067                        mTokenizer->getLocation().string());
1068                return BAD_VALUE;
1069            }
1070            key->label = behavior.character;
1071#if DEBUG_PARSER
1072            ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label);
1073#endif
1074            break;
1075        case PROPERTY_NUMBER:
1076            if (key->number) {
1077                ALOGE("%s: Duplicate number for key.",
1078                        mTokenizer->getLocation().string());
1079                return BAD_VALUE;
1080            }
1081            key->number = behavior.character;
1082#if DEBUG_PARSER
1083            ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number);
1084#endif
1085            break;
1086        case PROPERTY_META: {
1087            for (Behavior* b = key->firstBehavior; b; b = b->next) {
1088                if (b->metaState == property.metaState) {
1089                    ALOGE("%s: Duplicate key behavior for modifier.",
1090                            mTokenizer->getLocation().string());
1091                    return BAD_VALUE;
1092                }
1093            }
1094            Behavior* newBehavior = new Behavior(behavior);
1095            newBehavior->metaState = property.metaState;
1096            newBehavior->next = key->firstBehavior;
1097            key->firstBehavior = newBehavior;
1098#if DEBUG_PARSER
1099            ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
1100                    mKeyCode,
1101                    newBehavior->metaState, newBehavior->character,
1102                    newBehavior->fallbackKeyCode, newBehavior->replacementKeyCode);
1103#endif
1104            break;
1105        }
1106        }
1107    }
1108    return NO_ERROR;
1109}
1110
1111status_t KeyCharacterMap::Parser::finishKey(Key* key) {
1112    // Fill in default number property.
1113    if (!key->number) {
1114        char16_t digit = 0;
1115        char16_t symbol = 0;
1116        for (Behavior* b = key->firstBehavior; b; b = b->next) {
1117            char16_t ch = b->character;
1118            if (ch) {
1119                if (ch >= '0' && ch <= '9') {
1120                    digit = ch;
1121                } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
1122                        || ch == '-' || ch == '+' || ch == ',' || ch == '.'
1123                        || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
1124                    symbol = ch;
1125                }
1126            }
1127        }
1128        key->number = digit ? digit : symbol;
1129    }
1130    return NO_ERROR;
1131}
1132
1133status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) {
1134    if (token == "base") {
1135        *outMetaState = 0;
1136        return NO_ERROR;
1137    }
1138
1139    int32_t combinedMeta = 0;
1140
1141    const char* str = token.string();
1142    const char* start = str;
1143    for (const char* cur = str; ; cur++) {
1144        char ch = *cur;
1145        if (ch == '+' || ch == '\0') {
1146            size_t len = cur - start;
1147            int32_t metaState = 0;
1148            for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
1149                if (strlen(modifiers[i].label) == len
1150                        && strncmp(modifiers[i].label, start, len) == 0) {
1151                    metaState = modifiers[i].metaState;
1152                    break;
1153                }
1154            }
1155            if (!metaState) {
1156                return BAD_VALUE;
1157            }
1158            if (combinedMeta & metaState) {
1159                ALOGE("%s: Duplicate modifier combination '%s'.",
1160                        mTokenizer->getLocation().string(), token.string());
1161                return BAD_VALUE;
1162            }
1163
1164            combinedMeta |= metaState;
1165            start = cur + 1;
1166
1167            if (ch == '\0') {
1168                break;
1169            }
1170        }
1171    }
1172    *outMetaState = combinedMeta;
1173    return NO_ERROR;
1174}
1175
1176status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
1177    char ch = mTokenizer->nextChar();
1178    if (ch != '\'') {
1179        goto Error;
1180    }
1181
1182    ch = mTokenizer->nextChar();
1183    if (ch == '\\') {
1184        // Escape sequence.
1185        ch = mTokenizer->nextChar();
1186        if (ch == 'n') {
1187            *outCharacter = '\n';
1188        } else if (ch == 't') {
1189            *outCharacter = '\t';
1190        } else if (ch == '\\') {
1191            *outCharacter = '\\';
1192        } else if (ch == '\'') {
1193            *outCharacter = '\'';
1194        } else if (ch == '"') {
1195            *outCharacter = '"';
1196        } else if (ch == 'u') {
1197            *outCharacter = 0;
1198            for (int i = 0; i < 4; i++) {
1199                ch = mTokenizer->nextChar();
1200                int digit;
1201                if (ch >= '0' && ch <= '9') {
1202                    digit = ch - '0';
1203                } else if (ch >= 'A' && ch <= 'F') {
1204                    digit = ch - 'A' + 10;
1205                } else if (ch >= 'a' && ch <= 'f') {
1206                    digit = ch - 'a' + 10;
1207                } else {
1208                    goto Error;
1209                }
1210                *outCharacter = (*outCharacter << 4) | digit;
1211            }
1212        } else {
1213            goto Error;
1214        }
1215    } else if (ch >= 32 && ch <= 126 && ch != '\'') {
1216        // ASCII literal character.
1217        *outCharacter = ch;
1218    } else {
1219        goto Error;
1220    }
1221
1222    ch = mTokenizer->nextChar();
1223    if (ch != '\'') {
1224        goto Error;
1225    }
1226
1227    // Ensure that we consumed the entire token.
1228    if (mTokenizer->nextToken(WHITESPACE).isEmpty()) {
1229        return NO_ERROR;
1230    }
1231
1232Error:
1233    ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string());
1234    return BAD_VALUE;
1235}
1236
1237} // namespace android
1238