KeyCharacterMap.cpp revision b480269b0f8e933fa6fc6bd4c9e1e504e1b51508
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#ifdef __ANDROID__
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#ifdef __ANDROID__
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    if (numKeys > MAX_KEYS) {
611        ALOGE("Too many keys in KeyCharacterMap (%d > %d)", numKeys, MAX_KEYS);
612        return NULL;
613    }
614
615    for (size_t i = 0; i < numKeys; i++) {
616        int32_t keyCode = parcel->readInt32();
617        char16_t label = parcel->readInt32();
618        char16_t number = parcel->readInt32();
619        if (parcel->errorCheck()) {
620            return NULL;
621        }
622
623        Key* key = new Key();
624        key->label = label;
625        key->number = number;
626        map->mKeys.add(keyCode, key);
627
628        Behavior* lastBehavior = NULL;
629        while (parcel->readInt32()) {
630            int32_t metaState = parcel->readInt32();
631            char16_t character = parcel->readInt32();
632            int32_t fallbackKeyCode = parcel->readInt32();
633            int32_t replacementKeyCode = parcel->readInt32();
634            if (parcel->errorCheck()) {
635                return NULL;
636            }
637
638            Behavior* behavior = new Behavior();
639            behavior->metaState = metaState;
640            behavior->character = character;
641            behavior->fallbackKeyCode = fallbackKeyCode;
642            behavior->replacementKeyCode = replacementKeyCode;
643            if (lastBehavior) {
644                lastBehavior->next = behavior;
645            } else {
646                key->firstBehavior = behavior;
647            }
648            lastBehavior = behavior;
649        }
650
651        if (parcel->errorCheck()) {
652            return NULL;
653        }
654    }
655    return map;
656}
657
658void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
659    parcel->writeInt32(mType);
660
661    size_t numKeys = mKeys.size();
662    parcel->writeInt32(numKeys);
663    for (size_t i = 0; i < numKeys; i++) {
664        int32_t keyCode = mKeys.keyAt(i);
665        const Key* key = mKeys.valueAt(i);
666        parcel->writeInt32(keyCode);
667        parcel->writeInt32(key->label);
668        parcel->writeInt32(key->number);
669        for (const Behavior* behavior = key->firstBehavior; behavior != NULL;
670                behavior = behavior->next) {
671            parcel->writeInt32(1);
672            parcel->writeInt32(behavior->metaState);
673            parcel->writeInt32(behavior->character);
674            parcel->writeInt32(behavior->fallbackKeyCode);
675            parcel->writeInt32(behavior->replacementKeyCode);
676        }
677        parcel->writeInt32(0);
678    }
679}
680#endif
681
682
683// --- KeyCharacterMap::Key ---
684
685KeyCharacterMap::Key::Key() :
686        label(0), number(0), firstBehavior(NULL) {
687}
688
689KeyCharacterMap::Key::Key(const Key& other) :
690        label(other.label), number(other.number),
691        firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) {
692}
693
694KeyCharacterMap::Key::~Key() {
695    Behavior* behavior = firstBehavior;
696    while (behavior) {
697        Behavior* next = behavior->next;
698        delete behavior;
699        behavior = next;
700    }
701}
702
703
704// --- KeyCharacterMap::Behavior ---
705
706KeyCharacterMap::Behavior::Behavior() :
707        next(NULL), metaState(0), character(0), fallbackKeyCode(0), replacementKeyCode(0) {
708}
709
710KeyCharacterMap::Behavior::Behavior(const Behavior& other) :
711        next(other.next ? new Behavior(*other.next) : NULL),
712        metaState(other.metaState), character(other.character),
713        fallbackKeyCode(other.fallbackKeyCode),
714        replacementKeyCode(other.replacementKeyCode) {
715}
716
717
718// --- KeyCharacterMap::Parser ---
719
720KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
721        mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
722}
723
724KeyCharacterMap::Parser::~Parser() {
725}
726
727status_t KeyCharacterMap::Parser::parse() {
728    while (!mTokenizer->isEof()) {
729#if DEBUG_PARSER
730        ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
731                mTokenizer->peekRemainderOfLine().string());
732#endif
733
734        mTokenizer->skipDelimiters(WHITESPACE);
735
736        if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
737            switch (mState) {
738            case STATE_TOP: {
739                String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
740                if (keywordToken == "type") {
741                    mTokenizer->skipDelimiters(WHITESPACE);
742                    status_t status = parseType();
743                    if (status) return status;
744                } else if (keywordToken == "map") {
745                    mTokenizer->skipDelimiters(WHITESPACE);
746                    status_t status = parseMap();
747                    if (status) return status;
748                } else if (keywordToken == "key") {
749                    mTokenizer->skipDelimiters(WHITESPACE);
750                    status_t status = parseKey();
751                    if (status) return status;
752                } else {
753                    ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
754                            keywordToken.string());
755                    return BAD_VALUE;
756                }
757                break;
758            }
759
760            case STATE_KEY: {
761                status_t status = parseKeyProperty();
762                if (status) return status;
763                break;
764            }
765            }
766
767            mTokenizer->skipDelimiters(WHITESPACE);
768            if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
769                ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
770                        mTokenizer->getLocation().string(),
771                        mTokenizer->peekRemainderOfLine().string());
772                return BAD_VALUE;
773            }
774        }
775
776        mTokenizer->nextLine();
777    }
778
779    if (mState != STATE_TOP) {
780        ALOGE("%s: Unterminated key description at end of file.",
781                mTokenizer->getLocation().string());
782        return BAD_VALUE;
783    }
784
785    if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
786        ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
787                mTokenizer->getLocation().string());
788        return BAD_VALUE;
789    }
790
791    if (mFormat == FORMAT_BASE) {
792        if (mMap->mType == KEYBOARD_TYPE_OVERLAY) {
793            ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
794                    mTokenizer->getLocation().string());
795            return BAD_VALUE;
796        }
797    } else if (mFormat == FORMAT_OVERLAY) {
798        if (mMap->mType != KEYBOARD_TYPE_OVERLAY) {
799            ALOGE("%s: Overlay keyboard layout missing required keyboard "
800                    "'type OVERLAY' declaration.",
801                    mTokenizer->getLocation().string());
802            return BAD_VALUE;
803        }
804    }
805
806    return NO_ERROR;
807}
808
809status_t KeyCharacterMap::Parser::parseType() {
810    if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) {
811        ALOGE("%s: Duplicate keyboard 'type' declaration.",
812                mTokenizer->getLocation().string());
813        return BAD_VALUE;
814    }
815
816    KeyboardType type;
817    String8 typeToken = mTokenizer->nextToken(WHITESPACE);
818    if (typeToken == "NUMERIC") {
819        type = KEYBOARD_TYPE_NUMERIC;
820    } else if (typeToken == "PREDICTIVE") {
821        type = KEYBOARD_TYPE_PREDICTIVE;
822    } else if (typeToken == "ALPHA") {
823        type = KEYBOARD_TYPE_ALPHA;
824    } else if (typeToken == "FULL") {
825        type = KEYBOARD_TYPE_FULL;
826    } else if (typeToken == "SPECIAL_FUNCTION") {
827        type = KEYBOARD_TYPE_SPECIAL_FUNCTION;
828    } else if (typeToken == "OVERLAY") {
829        type = KEYBOARD_TYPE_OVERLAY;
830    } else {
831        ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(),
832                typeToken.string());
833        return BAD_VALUE;
834    }
835
836#if DEBUG_PARSER
837    ALOGD("Parsed type: type=%d.", type);
838#endif
839    mMap->mType = type;
840    return NO_ERROR;
841}
842
843status_t KeyCharacterMap::Parser::parseMap() {
844    String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
845    if (keywordToken == "key") {
846        mTokenizer->skipDelimiters(WHITESPACE);
847        return parseMapKey();
848    }
849    ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(),
850            keywordToken.string());
851    return BAD_VALUE;
852}
853
854status_t KeyCharacterMap::Parser::parseMapKey() {
855    String8 codeToken = mTokenizer->nextToken(WHITESPACE);
856    bool mapUsage = false;
857    if (codeToken == "usage") {
858        mapUsage = true;
859        mTokenizer->skipDelimiters(WHITESPACE);
860        codeToken = mTokenizer->nextToken(WHITESPACE);
861    }
862
863    char* end;
864    int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
865    if (*end) {
866        ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
867                mapUsage ? "usage" : "scan code", codeToken.string());
868        return BAD_VALUE;
869    }
870    KeyedVector<int32_t, int32_t>& map =
871            mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
872    if (map.indexOfKey(code) >= 0) {
873        ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
874                mapUsage ? "usage" : "scan code", codeToken.string());
875        return BAD_VALUE;
876    }
877
878    mTokenizer->skipDelimiters(WHITESPACE);
879    String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
880    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
881    if (!keyCode) {
882        ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
883                keyCodeToken.string());
884        return BAD_VALUE;
885    }
886
887#if DEBUG_PARSER
888    ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
889            mapUsage ? "usage" : "scan code", code, keyCode);
890#endif
891    map.add(code, keyCode);
892    return NO_ERROR;
893}
894
895status_t KeyCharacterMap::Parser::parseKey() {
896    String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
897    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
898    if (!keyCode) {
899        ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
900                keyCodeToken.string());
901        return BAD_VALUE;
902    }
903    if (mMap->mKeys.indexOfKey(keyCode) >= 0) {
904        ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(),
905                keyCodeToken.string());
906        return BAD_VALUE;
907    }
908
909    mTokenizer->skipDelimiters(WHITESPACE);
910    String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
911    if (openBraceToken != "{") {
912        ALOGE("%s: Expected '{' after key code label, got '%s'.",
913                mTokenizer->getLocation().string(), openBraceToken.string());
914        return BAD_VALUE;
915    }
916
917#if DEBUG_PARSER
918    ALOGD("Parsed beginning of key: keyCode=%d.", keyCode);
919#endif
920    mKeyCode = keyCode;
921    mMap->mKeys.add(keyCode, new Key());
922    mState = STATE_KEY;
923    return NO_ERROR;
924}
925
926status_t KeyCharacterMap::Parser::parseKeyProperty() {
927    Key* key = mMap->mKeys.valueFor(mKeyCode);
928    String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
929    if (token == "}") {
930        mState = STATE_TOP;
931        return finishKey(key);
932    }
933
934    Vector<Property> properties;
935
936    // Parse all comma-delimited property names up to the first colon.
937    for (;;) {
938        if (token == "label") {
939            properties.add(Property(PROPERTY_LABEL));
940        } else if (token == "number") {
941            properties.add(Property(PROPERTY_NUMBER));
942        } else {
943            int32_t metaState;
944            status_t status = parseModifier(token, &metaState);
945            if (status) {
946                ALOGE("%s: Expected a property name or modifier, got '%s'.",
947                        mTokenizer->getLocation().string(), token.string());
948                return status;
949            }
950            properties.add(Property(PROPERTY_META, metaState));
951        }
952
953        mTokenizer->skipDelimiters(WHITESPACE);
954        if (!mTokenizer->isEol()) {
955            char ch = mTokenizer->nextChar();
956            if (ch == ':') {
957                break;
958            } else if (ch == ',') {
959                mTokenizer->skipDelimiters(WHITESPACE);
960                token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
961                continue;
962            }
963        }
964
965        ALOGE("%s: Expected ',' or ':' after property name.",
966                mTokenizer->getLocation().string());
967        return BAD_VALUE;
968    }
969
970    // Parse behavior after the colon.
971    mTokenizer->skipDelimiters(WHITESPACE);
972
973    Behavior behavior;
974    bool haveCharacter = false;
975    bool haveFallback = false;
976    bool haveReplacement = false;
977
978    do {
979        char ch = mTokenizer->peekChar();
980        if (ch == '\'') {
981            char16_t character;
982            status_t status = parseCharacterLiteral(&character);
983            if (status || !character) {
984                ALOGE("%s: Invalid character literal for key.",
985                        mTokenizer->getLocation().string());
986                return BAD_VALUE;
987            }
988            if (haveCharacter) {
989                ALOGE("%s: Cannot combine multiple character literals or 'none'.",
990                        mTokenizer->getLocation().string());
991                return BAD_VALUE;
992            }
993            if (haveReplacement) {
994                ALOGE("%s: Cannot combine character literal with replace action.",
995                        mTokenizer->getLocation().string());
996                return BAD_VALUE;
997            }
998            behavior.character = character;
999            haveCharacter = true;
1000        } else {
1001            token = mTokenizer->nextToken(WHITESPACE);
1002            if (token == "none") {
1003                if (haveCharacter) {
1004                    ALOGE("%s: Cannot combine multiple character literals or 'none'.",
1005                            mTokenizer->getLocation().string());
1006                    return BAD_VALUE;
1007                }
1008                if (haveReplacement) {
1009                    ALOGE("%s: Cannot combine 'none' with replace action.",
1010                            mTokenizer->getLocation().string());
1011                    return BAD_VALUE;
1012                }
1013                haveCharacter = true;
1014            } else if (token == "fallback") {
1015                mTokenizer->skipDelimiters(WHITESPACE);
1016                token = mTokenizer->nextToken(WHITESPACE);
1017                int32_t keyCode = getKeyCodeByLabel(token.string());
1018                if (!keyCode) {
1019                    ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
1020                            mTokenizer->getLocation().string(),
1021                            token.string());
1022                    return BAD_VALUE;
1023                }
1024                if (haveFallback || haveReplacement) {
1025                    ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
1026                            mTokenizer->getLocation().string());
1027                    return BAD_VALUE;
1028                }
1029                behavior.fallbackKeyCode = keyCode;
1030                haveFallback = true;
1031            } else if (token == "replace") {
1032                mTokenizer->skipDelimiters(WHITESPACE);
1033                token = mTokenizer->nextToken(WHITESPACE);
1034                int32_t keyCode = getKeyCodeByLabel(token.string());
1035                if (!keyCode) {
1036                    ALOGE("%s: Invalid key code label for replace, got '%s'.",
1037                            mTokenizer->getLocation().string(),
1038                            token.string());
1039                    return BAD_VALUE;
1040                }
1041                if (haveCharacter) {
1042                    ALOGE("%s: Cannot combine character literal with replace action.",
1043                            mTokenizer->getLocation().string());
1044                    return BAD_VALUE;
1045                }
1046                if (haveFallback || haveReplacement) {
1047                    ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
1048                            mTokenizer->getLocation().string());
1049                    return BAD_VALUE;
1050                }
1051                behavior.replacementKeyCode = keyCode;
1052                haveReplacement = true;
1053
1054            } else {
1055                ALOGE("%s: Expected a key behavior after ':'.",
1056                        mTokenizer->getLocation().string());
1057                return BAD_VALUE;
1058            }
1059        }
1060
1061        mTokenizer->skipDelimiters(WHITESPACE);
1062    } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#');
1063
1064    // Add the behavior.
1065    for (size_t i = 0; i < properties.size(); i++) {
1066        const Property& property = properties.itemAt(i);
1067        switch (property.property) {
1068        case PROPERTY_LABEL:
1069            if (key->label) {
1070                ALOGE("%s: Duplicate label for key.",
1071                        mTokenizer->getLocation().string());
1072                return BAD_VALUE;
1073            }
1074            key->label = behavior.character;
1075#if DEBUG_PARSER
1076            ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label);
1077#endif
1078            break;
1079        case PROPERTY_NUMBER:
1080            if (key->number) {
1081                ALOGE("%s: Duplicate number for key.",
1082                        mTokenizer->getLocation().string());
1083                return BAD_VALUE;
1084            }
1085            key->number = behavior.character;
1086#if DEBUG_PARSER
1087            ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number);
1088#endif
1089            break;
1090        case PROPERTY_META: {
1091            for (Behavior* b = key->firstBehavior; b; b = b->next) {
1092                if (b->metaState == property.metaState) {
1093                    ALOGE("%s: Duplicate key behavior for modifier.",
1094                            mTokenizer->getLocation().string());
1095                    return BAD_VALUE;
1096                }
1097            }
1098            Behavior* newBehavior = new Behavior(behavior);
1099            newBehavior->metaState = property.metaState;
1100            newBehavior->next = key->firstBehavior;
1101            key->firstBehavior = newBehavior;
1102#if DEBUG_PARSER
1103            ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
1104                    mKeyCode,
1105                    newBehavior->metaState, newBehavior->character,
1106                    newBehavior->fallbackKeyCode, newBehavior->replacementKeyCode);
1107#endif
1108            break;
1109        }
1110        }
1111    }
1112    return NO_ERROR;
1113}
1114
1115status_t KeyCharacterMap::Parser::finishKey(Key* key) {
1116    // Fill in default number property.
1117    if (!key->number) {
1118        char16_t digit = 0;
1119        char16_t symbol = 0;
1120        for (Behavior* b = key->firstBehavior; b; b = b->next) {
1121            char16_t ch = b->character;
1122            if (ch) {
1123                if (ch >= '0' && ch <= '9') {
1124                    digit = ch;
1125                } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
1126                        || ch == '-' || ch == '+' || ch == ',' || ch == '.'
1127                        || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
1128                    symbol = ch;
1129                }
1130            }
1131        }
1132        key->number = digit ? digit : symbol;
1133    }
1134    return NO_ERROR;
1135}
1136
1137status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) {
1138    if (token == "base") {
1139        *outMetaState = 0;
1140        return NO_ERROR;
1141    }
1142
1143    int32_t combinedMeta = 0;
1144
1145    const char* str = token.string();
1146    const char* start = str;
1147    for (const char* cur = str; ; cur++) {
1148        char ch = *cur;
1149        if (ch == '+' || ch == '\0') {
1150            size_t len = cur - start;
1151            int32_t metaState = 0;
1152            for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
1153                if (strlen(modifiers[i].label) == len
1154                        && strncmp(modifiers[i].label, start, len) == 0) {
1155                    metaState = modifiers[i].metaState;
1156                    break;
1157                }
1158            }
1159            if (!metaState) {
1160                return BAD_VALUE;
1161            }
1162            if (combinedMeta & metaState) {
1163                ALOGE("%s: Duplicate modifier combination '%s'.",
1164                        mTokenizer->getLocation().string(), token.string());
1165                return BAD_VALUE;
1166            }
1167
1168            combinedMeta |= metaState;
1169            start = cur + 1;
1170
1171            if (ch == '\0') {
1172                break;
1173            }
1174        }
1175    }
1176    *outMetaState = combinedMeta;
1177    return NO_ERROR;
1178}
1179
1180status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
1181    char ch = mTokenizer->nextChar();
1182    if (ch != '\'') {
1183        goto Error;
1184    }
1185
1186    ch = mTokenizer->nextChar();
1187    if (ch == '\\') {
1188        // Escape sequence.
1189        ch = mTokenizer->nextChar();
1190        if (ch == 'n') {
1191            *outCharacter = '\n';
1192        } else if (ch == 't') {
1193            *outCharacter = '\t';
1194        } else if (ch == '\\') {
1195            *outCharacter = '\\';
1196        } else if (ch == '\'') {
1197            *outCharacter = '\'';
1198        } else if (ch == '"') {
1199            *outCharacter = '"';
1200        } else if (ch == 'u') {
1201            *outCharacter = 0;
1202            for (int i = 0; i < 4; i++) {
1203                ch = mTokenizer->nextChar();
1204                int digit;
1205                if (ch >= '0' && ch <= '9') {
1206                    digit = ch - '0';
1207                } else if (ch >= 'A' && ch <= 'F') {
1208                    digit = ch - 'A' + 10;
1209                } else if (ch >= 'a' && ch <= 'f') {
1210                    digit = ch - 'a' + 10;
1211                } else {
1212                    goto Error;
1213                }
1214                *outCharacter = (*outCharacter << 4) | digit;
1215            }
1216        } else {
1217            goto Error;
1218        }
1219    } else if (ch >= 32 && ch <= 126 && ch != '\'') {
1220        // ASCII literal character.
1221        *outCharacter = ch;
1222    } else {
1223        goto Error;
1224    }
1225
1226    ch = mTokenizer->nextChar();
1227    if (ch != '\'') {
1228        goto Error;
1229    }
1230
1231    // Ensure that we consumed the entire token.
1232    if (mTokenizer->nextToken(WHITESPACE).isEmpty()) {
1233        return NO_ERROR;
1234    }
1235
1236Error:
1237    ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string());
1238    return BAD_VALUE;
1239}
1240
1241} // namespace android
1242