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