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