widget/gonk/libui/KeyCharacterMap.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/gonk/libui/KeyCharacterMap.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1153 @@
     1.4 +/*
     1.5 + * Copyright (C) 2008 The Android Open Source Project
     1.6 + *
     1.7 + * Licensed under the Apache License, Version 2.0 (the "License");
     1.8 + * you may not use this file except in compliance with the License.
     1.9 + * You may obtain a copy of the License at
    1.10 + *
    1.11 + *      http://www.apache.org/licenses/LICENSE-2.0
    1.12 + *
    1.13 + * Unless required by applicable law or agreed to in writing, software
    1.14 + * distributed under the License is distributed on an "AS IS" BASIS,
    1.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.16 + * See the License for the specific language governing permissions and
    1.17 + * limitations under the License.
    1.18 + */
    1.19 +
    1.20 +#define LOG_TAG "KeyCharacterMap"
    1.21 +#include "cutils_log.h"
    1.22 +
    1.23 +#include <stdlib.h>
    1.24 +#include <string.h>
    1.25 +#include "android_keycodes.h"
    1.26 +#include "Keyboard.h"
    1.27 +#include "KeyCharacterMap.h"
    1.28 +
    1.29 +#if HAVE_ANDROID_OS
    1.30 +#include <binder/Parcel.h>
    1.31 +#endif
    1.32 +
    1.33 +#include <utils/Errors.h>
    1.34 +#include "Tokenizer.h"
    1.35 +#include <utils/Timers.h>
    1.36 +
    1.37 +// Enables debug output for the parser.
    1.38 +#define DEBUG_PARSER 0
    1.39 +
    1.40 +// Enables debug output for parser performance.
    1.41 +#define DEBUG_PARSER_PERFORMANCE 0
    1.42 +
    1.43 +// Enables debug output for mapping.
    1.44 +#define DEBUG_MAPPING 0
    1.45 +
    1.46 +
    1.47 +namespace android {
    1.48 +
    1.49 +static const char* WHITESPACE = " \t\r";
    1.50 +static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:";
    1.51 +
    1.52 +struct Modifier {
    1.53 +    const char* label;
    1.54 +    int32_t metaState;
    1.55 +};
    1.56 +static const Modifier modifiers[] = {
    1.57 +        { "shift", AMETA_SHIFT_ON },
    1.58 +        { "lshift", AMETA_SHIFT_LEFT_ON },
    1.59 +        { "rshift", AMETA_SHIFT_RIGHT_ON },
    1.60 +        { "alt", AMETA_ALT_ON },
    1.61 +        { "lalt", AMETA_ALT_LEFT_ON },
    1.62 +        { "ralt", AMETA_ALT_RIGHT_ON },
    1.63 +        { "ctrl", AMETA_CTRL_ON },
    1.64 +        { "lctrl", AMETA_CTRL_LEFT_ON },
    1.65 +        { "rctrl", AMETA_CTRL_RIGHT_ON },
    1.66 +        { "meta", AMETA_META_ON },
    1.67 +        { "lmeta", AMETA_META_LEFT_ON },
    1.68 +        { "rmeta", AMETA_META_RIGHT_ON },
    1.69 +        { "sym", AMETA_SYM_ON },
    1.70 +        { "fn", AMETA_FUNCTION_ON },
    1.71 +        { "capslock", AMETA_CAPS_LOCK_ON },
    1.72 +        { "numlock", AMETA_NUM_LOCK_ON },
    1.73 +        { "scrolllock", AMETA_SCROLL_LOCK_ON },
    1.74 +};
    1.75 +
    1.76 +#if DEBUG_MAPPING
    1.77 +static String8 toString(const char16_t* chars, size_t numChars) {
    1.78 +    String8 result;
    1.79 +    for (size_t i = 0; i < numChars; i++) {
    1.80 +        result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]);
    1.81 +    }
    1.82 +    return result;
    1.83 +}
    1.84 +#endif
    1.85 +
    1.86 +
    1.87 +// --- KeyCharacterMap ---
    1.88 +
    1.89 +sp<KeyCharacterMap> KeyCharacterMap::sEmpty = new KeyCharacterMap();
    1.90 +
    1.91 +KeyCharacterMap::KeyCharacterMap() :
    1.92 +    mType(KEYBOARD_TYPE_UNKNOWN) {
    1.93 +}
    1.94 +
    1.95 +KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) :
    1.96 +    RefBase(), mType(other.mType), mKeysByScanCode(other.mKeysByScanCode),
    1.97 +    mKeysByUsageCode(other.mKeysByUsageCode) {
    1.98 +    for (size_t i = 0; i < other.mKeys.size(); i++) {
    1.99 +        mKeys.add(other.mKeys.keyAt(i), new Key(*other.mKeys.valueAt(i)));
   1.100 +    }
   1.101 +}
   1.102 +
   1.103 +KeyCharacterMap::~KeyCharacterMap() {
   1.104 +    for (size_t i = 0; i < mKeys.size(); i++) {
   1.105 +        Key* key = mKeys.editValueAt(i);
   1.106 +        delete key;
   1.107 +    }
   1.108 +}
   1.109 +
   1.110 +status_t KeyCharacterMap::load(const String8& filename,
   1.111 +        Format format, sp<KeyCharacterMap>* outMap) {
   1.112 +    outMap->clear();
   1.113 +
   1.114 +    Tokenizer* tokenizer;
   1.115 +    status_t status = Tokenizer::open(filename, &tokenizer);
   1.116 +    if (status) {
   1.117 +        ALOGE("Error %d opening key character map file %s.", status, filename.string());
   1.118 +    } else {
   1.119 +        status = load(tokenizer, format, outMap);
   1.120 +        delete tokenizer;
   1.121 +    }
   1.122 +    return status;
   1.123 +}
   1.124 +
   1.125 +status_t KeyCharacterMap::loadContents(const String8& filename, const char* contents,
   1.126 +        Format format, sp<KeyCharacterMap>* outMap) {
   1.127 +    outMap->clear();
   1.128 +
   1.129 +    Tokenizer* tokenizer;
   1.130 +    status_t status = Tokenizer::fromContents(filename, contents, &tokenizer);
   1.131 +    if (status) {
   1.132 +        ALOGE("Error %d opening key character map.", status);
   1.133 +    } else {
   1.134 +        status = load(tokenizer, format, outMap);
   1.135 +        delete tokenizer;
   1.136 +    }
   1.137 +    return status;
   1.138 +}
   1.139 +
   1.140 +status_t KeyCharacterMap::load(Tokenizer* tokenizer,
   1.141 +        Format format, sp<KeyCharacterMap>* outMap) {
   1.142 +    status_t status = OK;
   1.143 +    sp<KeyCharacterMap> map = new KeyCharacterMap();
   1.144 +    if (!map.get()) {
   1.145 +        ALOGE("Error allocating key character map.");
   1.146 +        status = NO_MEMORY;
   1.147 +    } else {
   1.148 +#if DEBUG_PARSER_PERFORMANCE
   1.149 +        nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
   1.150 +#endif
   1.151 +        Parser parser(map.get(), tokenizer, format);
   1.152 +        status = parser.parse();
   1.153 +#if DEBUG_PARSER_PERFORMANCE
   1.154 +        nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
   1.155 +        ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
   1.156 +                tokenizer->getFilename().string(), tokenizer->getLineNumber(),
   1.157 +                elapsedTime / 1000000.0);
   1.158 +#endif
   1.159 +        if (!status) {
   1.160 +            *outMap = map;
   1.161 +        }
   1.162 +    }
   1.163 +    return status;
   1.164 +}
   1.165 +
   1.166 +sp<KeyCharacterMap> KeyCharacterMap::combine(const sp<KeyCharacterMap>& base,
   1.167 +        const sp<KeyCharacterMap>& overlay) {
   1.168 +    if (overlay == NULL) {
   1.169 +        return base;
   1.170 +    }
   1.171 +    if (base == NULL) {
   1.172 +        return overlay;
   1.173 +    }
   1.174 +
   1.175 +    sp<KeyCharacterMap> map = new KeyCharacterMap(*base.get());
   1.176 +    for (size_t i = 0; i < overlay->mKeys.size(); i++) {
   1.177 +        int32_t keyCode = overlay->mKeys.keyAt(i);
   1.178 +        Key* key = overlay->mKeys.valueAt(i);
   1.179 +        ssize_t oldIndex = map->mKeys.indexOfKey(keyCode);
   1.180 +        if (oldIndex >= 0) {
   1.181 +            delete map->mKeys.valueAt(oldIndex);
   1.182 +            map->mKeys.editValueAt(oldIndex) = new Key(*key);
   1.183 +        } else {
   1.184 +            map->mKeys.add(keyCode, new Key(*key));
   1.185 +        }
   1.186 +    }
   1.187 +
   1.188 +    for (size_t i = 0; i < overlay->mKeysByScanCode.size(); i++) {
   1.189 +        map->mKeysByScanCode.replaceValueFor(overlay->mKeysByScanCode.keyAt(i),
   1.190 +                overlay->mKeysByScanCode.valueAt(i));
   1.191 +    }
   1.192 +
   1.193 +    for (size_t i = 0; i < overlay->mKeysByUsageCode.size(); i++) {
   1.194 +        map->mKeysByUsageCode.replaceValueFor(overlay->mKeysByUsageCode.keyAt(i),
   1.195 +                overlay->mKeysByUsageCode.valueAt(i));
   1.196 +    }
   1.197 +    return map;
   1.198 +}
   1.199 +
   1.200 +sp<KeyCharacterMap> KeyCharacterMap::empty() {
   1.201 +    return sEmpty;
   1.202 +}
   1.203 +
   1.204 +int32_t KeyCharacterMap::getKeyboardType() const {
   1.205 +    return mType;
   1.206 +}
   1.207 +
   1.208 +char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const {
   1.209 +    char16_t result = 0;
   1.210 +    const Key* key;
   1.211 +    if (getKey(keyCode, &key)) {
   1.212 +        result = key->label;
   1.213 +    }
   1.214 +#if DEBUG_MAPPING
   1.215 +    ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result);
   1.216 +#endif
   1.217 +    return result;
   1.218 +}
   1.219 +
   1.220 +char16_t KeyCharacterMap::getNumber(int32_t keyCode) const {
   1.221 +    char16_t result = 0;
   1.222 +    const Key* key;
   1.223 +    if (getKey(keyCode, &key)) {
   1.224 +        result = key->number;
   1.225 +    }
   1.226 +#if DEBUG_MAPPING
   1.227 +    ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result);
   1.228 +#endif
   1.229 +    return result;
   1.230 +}
   1.231 +
   1.232 +char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
   1.233 +    char16_t result = 0;
   1.234 +    const Key* key;
   1.235 +    const Behavior* behavior;
   1.236 +    if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
   1.237 +        result = behavior->character;
   1.238 +    }
   1.239 +#if DEBUG_MAPPING
   1.240 +    ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result);
   1.241 +#endif
   1.242 +    return result;
   1.243 +}
   1.244 +
   1.245 +bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState,
   1.246 +        FallbackAction* outFallbackAction) const {
   1.247 +    outFallbackAction->keyCode = 0;
   1.248 +    outFallbackAction->metaState = 0;
   1.249 +
   1.250 +    bool result = false;
   1.251 +    const Key* key;
   1.252 +    const Behavior* behavior;
   1.253 +    if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
   1.254 +        if (behavior->fallbackKeyCode) {
   1.255 +            outFallbackAction->keyCode = behavior->fallbackKeyCode;
   1.256 +            outFallbackAction->metaState = metaState & ~behavior->metaState;
   1.257 +            result = true;
   1.258 +        }
   1.259 +    }
   1.260 +#if DEBUG_MAPPING
   1.261 +    ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, "
   1.262 +            "fallback keyCode=%d, fallback metaState=0x%08x.",
   1.263 +            keyCode, metaState, result ? "true" : "false",
   1.264 +            outFallbackAction->keyCode, outFallbackAction->metaState);
   1.265 +#endif
   1.266 +    return result;
   1.267 +}
   1.268 +
   1.269 +char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars,
   1.270 +        int32_t metaState) const {
   1.271 +    char16_t result = 0;
   1.272 +    const Key* key;
   1.273 +    if (getKey(keyCode, &key)) {
   1.274 +        // Try to find the most general behavior that maps to this character.
   1.275 +        // For example, the base key behavior will usually be last in the list.
   1.276 +        // However, if we find a perfect meta state match for one behavior then use that one.
   1.277 +        for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
   1.278 +            if (behavior->character) {
   1.279 +                for (size_t i = 0; i < numChars; i++) {
   1.280 +                    if (behavior->character == chars[i]) {
   1.281 +                        result = behavior->character;
   1.282 +                        if ((behavior->metaState & metaState) == behavior->metaState) {
   1.283 +                            goto ExactMatch;
   1.284 +                        }
   1.285 +                        break;
   1.286 +                    }
   1.287 +                }
   1.288 +            }
   1.289 +        }
   1.290 +    ExactMatch: ;
   1.291 +    }
   1.292 +#if DEBUG_MAPPING
   1.293 +    ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.",
   1.294 +            keyCode, toString(chars, numChars).string(), metaState, result);
   1.295 +#endif
   1.296 +    return result;
   1.297 +}
   1.298 +
   1.299 +bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
   1.300 +        Vector<KeyEvent>& outEvents) const {
   1.301 +    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
   1.302 +
   1.303 +    for (size_t i = 0; i < numChars; i++) {
   1.304 +        int32_t keyCode, metaState;
   1.305 +        char16_t ch = chars[i];
   1.306 +        if (!findKey(ch, &keyCode, &metaState)) {
   1.307 +#if DEBUG_MAPPING
   1.308 +            ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.",
   1.309 +                    deviceId, toString(chars, numChars).string(), ch);
   1.310 +#endif
   1.311 +            return false;
   1.312 +        }
   1.313 +
   1.314 +        int32_t currentMetaState = 0;
   1.315 +        addMetaKeys(outEvents, deviceId, metaState, true, now, &currentMetaState);
   1.316 +        addKey(outEvents, deviceId, keyCode, currentMetaState, true, now);
   1.317 +        addKey(outEvents, deviceId, keyCode, currentMetaState, false, now);
   1.318 +        addMetaKeys(outEvents, deviceId, metaState, false, now, &currentMetaState);
   1.319 +    }
   1.320 +#if DEBUG_MAPPING
   1.321 +    ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.",
   1.322 +            deviceId, toString(chars, numChars).string(), int32_t(outEvents.size()));
   1.323 +    for (size_t i = 0; i < outEvents.size(); i++) {
   1.324 +        ALOGD("  Key: keyCode=%d, metaState=0x%08x, %s.",
   1.325 +                outEvents[i].getKeyCode(), outEvents[i].getMetaState(),
   1.326 +                outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up");
   1.327 +    }
   1.328 +#endif
   1.329 +    return true;
   1.330 +}
   1.331 +
   1.332 +status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
   1.333 +    if (usageCode) {
   1.334 +        ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
   1.335 +        if (index >= 0) {
   1.336 +#if DEBUG_MAPPING
   1.337 +    ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
   1.338 +            scanCode, usageCode, *outKeyCode);
   1.339 +#endif
   1.340 +            *outKeyCode = mKeysByUsageCode.valueAt(index);
   1.341 +            return OK;
   1.342 +        }
   1.343 +    }
   1.344 +    if (scanCode) {
   1.345 +        ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
   1.346 +        if (index >= 0) {
   1.347 +#if DEBUG_MAPPING
   1.348 +    ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
   1.349 +            scanCode, usageCode, *outKeyCode);
   1.350 +#endif
   1.351 +            *outKeyCode = mKeysByScanCode.valueAt(index);
   1.352 +            return OK;
   1.353 +        }
   1.354 +    }
   1.355 +
   1.356 +#if DEBUG_MAPPING
   1.357 +        ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
   1.358 +#endif
   1.359 +    *outKeyCode = AKEYCODE_UNKNOWN;
   1.360 +    return NAME_NOT_FOUND;
   1.361 +}
   1.362 +
   1.363 +bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
   1.364 +    ssize_t index = mKeys.indexOfKey(keyCode);
   1.365 +    if (index >= 0) {
   1.366 +        *outKey = mKeys.valueAt(index);
   1.367 +        return true;
   1.368 +    }
   1.369 +    return false;
   1.370 +}
   1.371 +
   1.372 +bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState,
   1.373 +        const Key** outKey, const Behavior** outBehavior) const {
   1.374 +    const Key* key;
   1.375 +    if (getKey(keyCode, &key)) {
   1.376 +        const Behavior* behavior = key->firstBehavior;
   1.377 +        while (behavior) {
   1.378 +            if (matchesMetaState(metaState, behavior->metaState)) {
   1.379 +                *outKey = key;
   1.380 +                *outBehavior = behavior;
   1.381 +                return true;
   1.382 +            }
   1.383 +            behavior = behavior->next;
   1.384 +        }
   1.385 +    }
   1.386 +    return false;
   1.387 +}
   1.388 +
   1.389 +bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
   1.390 +    // Behavior must have at least the set of meta states specified.
   1.391 +    // And if the key event has CTRL, ALT or META then the behavior must exactly
   1.392 +    // match those, taking into account that a behavior can specify that it handles
   1.393 +    // one, both or either of a left/right modifier pair.
   1.394 +    if ((eventMetaState & behaviorMetaState) == behaviorMetaState) {
   1.395 +        const int32_t EXACT_META_STATES =
   1.396 +                AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON
   1.397 +                | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON
   1.398 +                | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON;
   1.399 +        int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES;
   1.400 +        if (behaviorMetaState & AMETA_CTRL_ON) {
   1.401 +            unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
   1.402 +        } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
   1.403 +            unmatchedMetaState &= ~AMETA_CTRL_ON;
   1.404 +        }
   1.405 +        if (behaviorMetaState & AMETA_ALT_ON) {
   1.406 +            unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
   1.407 +        } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
   1.408 +            unmatchedMetaState &= ~AMETA_ALT_ON;
   1.409 +        }
   1.410 +        if (behaviorMetaState & AMETA_META_ON) {
   1.411 +            unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
   1.412 +        } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
   1.413 +            unmatchedMetaState &= ~AMETA_META_ON;
   1.414 +        }
   1.415 +        return !unmatchedMetaState;
   1.416 +    }
   1.417 +    return false;
   1.418 +}
   1.419 +
   1.420 +bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
   1.421 +    if (!ch) {
   1.422 +        return false;
   1.423 +    }
   1.424 +
   1.425 +    for (size_t i = 0; i < mKeys.size(); i++) {
   1.426 +        const Key* key = mKeys.valueAt(i);
   1.427 +
   1.428 +        // Try to find the most general behavior that maps to this character.
   1.429 +        // For example, the base key behavior will usually be last in the list.
   1.430 +        const Behavior* found = NULL;
   1.431 +        for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
   1.432 +            if (behavior->character == ch) {
   1.433 +                found = behavior;
   1.434 +            }
   1.435 +        }
   1.436 +        if (found) {
   1.437 +            *outKeyCode = mKeys.keyAt(i);
   1.438 +            *outMetaState = found->metaState;
   1.439 +            return true;
   1.440 +        }
   1.441 +    }
   1.442 +    return false;
   1.443 +}
   1.444 +
   1.445 +void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents,
   1.446 +        int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
   1.447 +    outEvents.push();
   1.448 +    KeyEvent& event = outEvents.editTop();
   1.449 +    event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD,
   1.450 +            down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
   1.451 +            0, keyCode, 0, metaState, 0, time, time);
   1.452 +}
   1.453 +
   1.454 +void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
   1.455 +        int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
   1.456 +        int32_t* currentMetaState) {
   1.457 +    // Add and remove meta keys symmetrically.
   1.458 +    if (down) {
   1.459 +        addLockedMetaKey(outEvents, deviceId, metaState, time,
   1.460 +                AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
   1.461 +        addLockedMetaKey(outEvents, deviceId, metaState, time,
   1.462 +                AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
   1.463 +        addLockedMetaKey(outEvents, deviceId, metaState, time,
   1.464 +                AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
   1.465 +
   1.466 +        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
   1.467 +                AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
   1.468 +                AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
   1.469 +                AMETA_SHIFT_ON, currentMetaState);
   1.470 +        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
   1.471 +                AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
   1.472 +                AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
   1.473 +                AMETA_ALT_ON, currentMetaState);
   1.474 +        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
   1.475 +                AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
   1.476 +                AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
   1.477 +                AMETA_CTRL_ON, currentMetaState);
   1.478 +        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
   1.479 +                AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
   1.480 +                AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
   1.481 +                AMETA_META_ON, currentMetaState);
   1.482 +
   1.483 +        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
   1.484 +                AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
   1.485 +        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
   1.486 +                AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
   1.487 +    } else {
   1.488 +        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
   1.489 +                AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
   1.490 +        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
   1.491 +                AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
   1.492 +
   1.493 +        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
   1.494 +                AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
   1.495 +                AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
   1.496 +                AMETA_META_ON, currentMetaState);
   1.497 +        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
   1.498 +                AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
   1.499 +                AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
   1.500 +                AMETA_CTRL_ON, currentMetaState);
   1.501 +        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
   1.502 +                AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
   1.503 +                AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
   1.504 +                AMETA_ALT_ON, currentMetaState);
   1.505 +        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
   1.506 +                AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
   1.507 +                AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
   1.508 +                AMETA_SHIFT_ON, currentMetaState);
   1.509 +
   1.510 +        addLockedMetaKey(outEvents, deviceId, metaState, time,
   1.511 +                AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
   1.512 +        addLockedMetaKey(outEvents, deviceId, metaState, time,
   1.513 +                AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
   1.514 +        addLockedMetaKey(outEvents, deviceId, metaState, time,
   1.515 +                AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
   1.516 +    }
   1.517 +}
   1.518 +
   1.519 +bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
   1.520 +        int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
   1.521 +        int32_t keyCode, int32_t keyMetaState,
   1.522 +        int32_t* currentMetaState) {
   1.523 +    if ((metaState & keyMetaState) == keyMetaState) {
   1.524 +        *currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
   1.525 +        addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
   1.526 +        return true;
   1.527 +    }
   1.528 +    return false;
   1.529 +}
   1.530 +
   1.531 +void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
   1.532 +        int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
   1.533 +        int32_t leftKeyCode, int32_t leftKeyMetaState,
   1.534 +        int32_t rightKeyCode, int32_t rightKeyMetaState,
   1.535 +        int32_t eitherKeyMetaState,
   1.536 +        int32_t* currentMetaState) {
   1.537 +    bool specific = false;
   1.538 +    specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
   1.539 +            leftKeyCode, leftKeyMetaState, currentMetaState);
   1.540 +    specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
   1.541 +            rightKeyCode, rightKeyMetaState, currentMetaState);
   1.542 +
   1.543 +    if (!specific) {
   1.544 +        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
   1.545 +                leftKeyCode, eitherKeyMetaState, currentMetaState);
   1.546 +    }
   1.547 +}
   1.548 +
   1.549 +void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
   1.550 +        int32_t deviceId, int32_t metaState, nsecs_t time,
   1.551 +        int32_t keyCode, int32_t keyMetaState,
   1.552 +        int32_t* currentMetaState) {
   1.553 +    if ((metaState & keyMetaState) == keyMetaState) {
   1.554 +        *currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
   1.555 +        addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
   1.556 +        *currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
   1.557 +        addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
   1.558 +    }
   1.559 +}
   1.560 +
   1.561 +#if HAVE_ANDROID_OS
   1.562 +sp<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
   1.563 +    sp<KeyCharacterMap> map = new KeyCharacterMap();
   1.564 +    map->mType = parcel->readInt32();
   1.565 +    size_t numKeys = parcel->readInt32();
   1.566 +    if (parcel->errorCheck()) {
   1.567 +        return NULL;
   1.568 +    }
   1.569 +
   1.570 +    for (size_t i = 0; i < numKeys; i++) {
   1.571 +        int32_t keyCode = parcel->readInt32();
   1.572 +        char16_t label = parcel->readInt32();
   1.573 +        char16_t number = parcel->readInt32();
   1.574 +        if (parcel->errorCheck()) {
   1.575 +            return NULL;
   1.576 +        }
   1.577 +
   1.578 +        Key* key = new Key();
   1.579 +        key->label = label;
   1.580 +        key->number = number;
   1.581 +        map->mKeys.add(keyCode, key);
   1.582 +
   1.583 +        Behavior* lastBehavior = NULL;
   1.584 +        while (parcel->readInt32()) {
   1.585 +            int32_t metaState = parcel->readInt32();
   1.586 +            char16_t character = parcel->readInt32();
   1.587 +            int32_t fallbackKeyCode = parcel->readInt32();
   1.588 +            if (parcel->errorCheck()) {
   1.589 +                return NULL;
   1.590 +            }
   1.591 +
   1.592 +            Behavior* behavior = new Behavior();
   1.593 +            behavior->metaState = metaState;
   1.594 +            behavior->character = character;
   1.595 +            behavior->fallbackKeyCode = fallbackKeyCode;
   1.596 +            if (lastBehavior) {
   1.597 +                lastBehavior->next = behavior;
   1.598 +            } else {
   1.599 +                key->firstBehavior = behavior;
   1.600 +            }
   1.601 +            lastBehavior = behavior;
   1.602 +        }
   1.603 +
   1.604 +        if (parcel->errorCheck()) {
   1.605 +            return NULL;
   1.606 +        }
   1.607 +    }
   1.608 +    return map;
   1.609 +}
   1.610 +
   1.611 +void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
   1.612 +    parcel->writeInt32(mType);
   1.613 +
   1.614 +    size_t numKeys = mKeys.size();
   1.615 +    parcel->writeInt32(numKeys);
   1.616 +    for (size_t i = 0; i < numKeys; i++) {
   1.617 +        int32_t keyCode = mKeys.keyAt(i);
   1.618 +        const Key* key = mKeys.valueAt(i);
   1.619 +        parcel->writeInt32(keyCode);
   1.620 +        parcel->writeInt32(key->label);
   1.621 +        parcel->writeInt32(key->number);
   1.622 +        for (const Behavior* behavior = key->firstBehavior; behavior != NULL;
   1.623 +                behavior = behavior->next) {
   1.624 +            parcel->writeInt32(1);
   1.625 +            parcel->writeInt32(behavior->metaState);
   1.626 +            parcel->writeInt32(behavior->character);
   1.627 +            parcel->writeInt32(behavior->fallbackKeyCode);
   1.628 +        }
   1.629 +        parcel->writeInt32(0);
   1.630 +    }
   1.631 +}
   1.632 +#endif
   1.633 +
   1.634 +
   1.635 +// --- KeyCharacterMap::Key ---
   1.636 +
   1.637 +KeyCharacterMap::Key::Key() :
   1.638 +        label(0), number(0), firstBehavior(NULL) {
   1.639 +}
   1.640 +
   1.641 +KeyCharacterMap::Key::Key(const Key& other) :
   1.642 +        label(other.label), number(other.number),
   1.643 +        firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) {
   1.644 +}
   1.645 +
   1.646 +KeyCharacterMap::Key::~Key() {
   1.647 +    Behavior* behavior = firstBehavior;
   1.648 +    while (behavior) {
   1.649 +        Behavior* next = behavior->next;
   1.650 +        delete behavior;
   1.651 +        behavior = next;
   1.652 +    }
   1.653 +}
   1.654 +
   1.655 +
   1.656 +// --- KeyCharacterMap::Behavior ---
   1.657 +
   1.658 +KeyCharacterMap::Behavior::Behavior() :
   1.659 +        next(NULL), metaState(0), character(0), fallbackKeyCode(0) {
   1.660 +}
   1.661 +
   1.662 +KeyCharacterMap::Behavior::Behavior(const Behavior& other) :
   1.663 +        next(other.next ? new Behavior(*other.next) : NULL),
   1.664 +        metaState(other.metaState), character(other.character),
   1.665 +        fallbackKeyCode(other.fallbackKeyCode) {
   1.666 +}
   1.667 +
   1.668 +
   1.669 +// --- KeyCharacterMap::Parser ---
   1.670 +
   1.671 +KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
   1.672 +        mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
   1.673 +}
   1.674 +
   1.675 +KeyCharacterMap::Parser::~Parser() {
   1.676 +}
   1.677 +
   1.678 +status_t KeyCharacterMap::Parser::parse() {
   1.679 +    while (!mTokenizer->isEof()) {
   1.680 +#if DEBUG_PARSER
   1.681 +        ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
   1.682 +                mTokenizer->peekRemainderOfLine().string());
   1.683 +#endif
   1.684 +
   1.685 +        mTokenizer->skipDelimiters(WHITESPACE);
   1.686 +
   1.687 +        if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
   1.688 +            switch (mState) {
   1.689 +            case STATE_TOP: {
   1.690 +                String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
   1.691 +                if (keywordToken == "type") {
   1.692 +                    mTokenizer->skipDelimiters(WHITESPACE);
   1.693 +                    status_t status = parseType();
   1.694 +                    if (status) return status;
   1.695 +                } else if (keywordToken == "map") {
   1.696 +                    mTokenizer->skipDelimiters(WHITESPACE);
   1.697 +                    status_t status = parseMap();
   1.698 +                    if (status) return status;
   1.699 +                } else if (keywordToken == "key") {
   1.700 +                    mTokenizer->skipDelimiters(WHITESPACE);
   1.701 +                    status_t status = parseKey();
   1.702 +                    if (status) return status;
   1.703 +                } else {
   1.704 +                    ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
   1.705 +                            keywordToken.string());
   1.706 +                    return BAD_VALUE;
   1.707 +                }
   1.708 +                break;
   1.709 +            }
   1.710 +
   1.711 +            case STATE_KEY: {
   1.712 +                status_t status = parseKeyProperty();
   1.713 +                if (status) return status;
   1.714 +                break;
   1.715 +            }
   1.716 +            }
   1.717 +
   1.718 +            mTokenizer->skipDelimiters(WHITESPACE);
   1.719 +            if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
   1.720 +                ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
   1.721 +                        mTokenizer->getLocation().string(),
   1.722 +                        mTokenizer->peekRemainderOfLine().string());
   1.723 +                return BAD_VALUE;
   1.724 +            }
   1.725 +        }
   1.726 +
   1.727 +        mTokenizer->nextLine();
   1.728 +    }
   1.729 +
   1.730 +    if (mState != STATE_TOP) {
   1.731 +        ALOGE("%s: Unterminated key description at end of file.",
   1.732 +                mTokenizer->getLocation().string());
   1.733 +        return BAD_VALUE;
   1.734 +    }
   1.735 +
   1.736 +    if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
   1.737 +        ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
   1.738 +                mTokenizer->getLocation().string());
   1.739 +        return BAD_VALUE;
   1.740 +    }
   1.741 +
   1.742 +    if (mFormat == FORMAT_BASE) {
   1.743 +        if (mMap->mType == KEYBOARD_TYPE_OVERLAY) {
   1.744 +            ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
   1.745 +                    mTokenizer->getLocation().string());
   1.746 +            return BAD_VALUE;
   1.747 +        }
   1.748 +    } else if (mFormat == FORMAT_OVERLAY) {
   1.749 +        if (mMap->mType != KEYBOARD_TYPE_OVERLAY) {
   1.750 +            ALOGE("%s: Overlay keyboard layout missing required keyboard "
   1.751 +                    "'type OVERLAY' declaration.",
   1.752 +                    mTokenizer->getLocation().string());
   1.753 +            return BAD_VALUE;
   1.754 +        }
   1.755 +    }
   1.756 +
   1.757 +    return NO_ERROR;
   1.758 +}
   1.759 +
   1.760 +status_t KeyCharacterMap::Parser::parseType() {
   1.761 +    if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) {
   1.762 +        ALOGE("%s: Duplicate keyboard 'type' declaration.",
   1.763 +                mTokenizer->getLocation().string());
   1.764 +        return BAD_VALUE;
   1.765 +    }
   1.766 +
   1.767 +    KeyboardType type;
   1.768 +    String8 typeToken = mTokenizer->nextToken(WHITESPACE);
   1.769 +    if (typeToken == "NUMERIC") {
   1.770 +        type = KEYBOARD_TYPE_NUMERIC;
   1.771 +    } else if (typeToken == "PREDICTIVE") {
   1.772 +        type = KEYBOARD_TYPE_PREDICTIVE;
   1.773 +    } else if (typeToken == "ALPHA") {
   1.774 +        type = KEYBOARD_TYPE_ALPHA;
   1.775 +    } else if (typeToken == "FULL") {
   1.776 +        type = KEYBOARD_TYPE_FULL;
   1.777 +    } else if (typeToken == "SPECIAL_FUNCTION") {
   1.778 +        type = KEYBOARD_TYPE_SPECIAL_FUNCTION;
   1.779 +    } else if (typeToken == "OVERLAY") {
   1.780 +        type = KEYBOARD_TYPE_OVERLAY;
   1.781 +    } else {
   1.782 +        ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(),
   1.783 +                typeToken.string());
   1.784 +        return BAD_VALUE;
   1.785 +    }
   1.786 +
   1.787 +#if DEBUG_PARSER
   1.788 +    ALOGD("Parsed type: type=%d.", type);
   1.789 +#endif
   1.790 +    mMap->mType = type;
   1.791 +    return NO_ERROR;
   1.792 +}
   1.793 +
   1.794 +status_t KeyCharacterMap::Parser::parseMap() {
   1.795 +    String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
   1.796 +    if (keywordToken == "key") {
   1.797 +        mTokenizer->skipDelimiters(WHITESPACE);
   1.798 +        return parseMapKey();
   1.799 +    }
   1.800 +    ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(),
   1.801 +            keywordToken.string());
   1.802 +    return BAD_VALUE;
   1.803 +}
   1.804 +
   1.805 +status_t KeyCharacterMap::Parser::parseMapKey() {
   1.806 +    String8 codeToken = mTokenizer->nextToken(WHITESPACE);
   1.807 +    bool mapUsage = false;
   1.808 +    if (codeToken == "usage") {
   1.809 +        mapUsage = true;
   1.810 +        mTokenizer->skipDelimiters(WHITESPACE);
   1.811 +        codeToken = mTokenizer->nextToken(WHITESPACE);
   1.812 +    }
   1.813 +
   1.814 +    char* end;
   1.815 +    int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
   1.816 +    if (*end) {
   1.817 +        ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
   1.818 +                mapUsage ? "usage" : "scan code", codeToken.string());
   1.819 +        return BAD_VALUE;
   1.820 +    }
   1.821 +    KeyedVector<int32_t, int32_t>& map =
   1.822 +            mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
   1.823 +    if (map.indexOfKey(code) >= 0) {
   1.824 +        ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
   1.825 +                mapUsage ? "usage" : "scan code", codeToken.string());
   1.826 +        return BAD_VALUE;
   1.827 +    }
   1.828 +
   1.829 +    mTokenizer->skipDelimiters(WHITESPACE);
   1.830 +    String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
   1.831 +    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
   1.832 +    if (!keyCode) {
   1.833 +        ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
   1.834 +                keyCodeToken.string());
   1.835 +        return BAD_VALUE;
   1.836 +    }
   1.837 +
   1.838 +#if DEBUG_PARSER
   1.839 +    ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
   1.840 +            mapUsage ? "usage" : "scan code", code, keyCode);
   1.841 +#endif
   1.842 +    map.add(code, keyCode);
   1.843 +    return NO_ERROR;
   1.844 +}
   1.845 +
   1.846 +status_t KeyCharacterMap::Parser::parseKey() {
   1.847 +    String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
   1.848 +    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
   1.849 +    if (!keyCode) {
   1.850 +        ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
   1.851 +                keyCodeToken.string());
   1.852 +        return BAD_VALUE;
   1.853 +    }
   1.854 +    if (mMap->mKeys.indexOfKey(keyCode) >= 0) {
   1.855 +        ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(),
   1.856 +                keyCodeToken.string());
   1.857 +        return BAD_VALUE;
   1.858 +    }
   1.859 +
   1.860 +    mTokenizer->skipDelimiters(WHITESPACE);
   1.861 +    String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
   1.862 +    if (openBraceToken != "{") {
   1.863 +        ALOGE("%s: Expected '{' after key code label, got '%s'.",
   1.864 +                mTokenizer->getLocation().string(), openBraceToken.string());
   1.865 +        return BAD_VALUE;
   1.866 +    }
   1.867 +
   1.868 +#if DEBUG_PARSER
   1.869 +    ALOGD("Parsed beginning of key: keyCode=%d.", keyCode);
   1.870 +#endif
   1.871 +    mKeyCode = keyCode;
   1.872 +    mMap->mKeys.add(keyCode, new Key());
   1.873 +    mState = STATE_KEY;
   1.874 +    return NO_ERROR;
   1.875 +}
   1.876 +
   1.877 +status_t KeyCharacterMap::Parser::parseKeyProperty() {
   1.878 +    Key* key = mMap->mKeys.valueFor(mKeyCode);
   1.879 +    String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
   1.880 +    if (token == "}") {
   1.881 +        mState = STATE_TOP;
   1.882 +        return finishKey(key);
   1.883 +    }
   1.884 +
   1.885 +    Vector<Property> properties;
   1.886 +
   1.887 +    // Parse all comma-delimited property names up to the first colon.
   1.888 +    for (;;) {
   1.889 +        if (token == "label") {
   1.890 +            properties.add(Property(PROPERTY_LABEL));
   1.891 +        } else if (token == "number") {
   1.892 +            properties.add(Property(PROPERTY_NUMBER));
   1.893 +        } else {
   1.894 +            int32_t metaState;
   1.895 +            status_t status = parseModifier(token, &metaState);
   1.896 +            if (status) {
   1.897 +                ALOGE("%s: Expected a property name or modifier, got '%s'.",
   1.898 +                        mTokenizer->getLocation().string(), token.string());
   1.899 +                return status;
   1.900 +            }
   1.901 +            properties.add(Property(PROPERTY_META, metaState));
   1.902 +        }
   1.903 +
   1.904 +        mTokenizer->skipDelimiters(WHITESPACE);
   1.905 +        if (!mTokenizer->isEol()) {
   1.906 +            char ch = mTokenizer->nextChar();
   1.907 +            if (ch == ':') {
   1.908 +                break;
   1.909 +            } else if (ch == ',') {
   1.910 +                mTokenizer->skipDelimiters(WHITESPACE);
   1.911 +                token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
   1.912 +                continue;
   1.913 +            }
   1.914 +        }
   1.915 +
   1.916 +        ALOGE("%s: Expected ',' or ':' after property name.",
   1.917 +                mTokenizer->getLocation().string());
   1.918 +        return BAD_VALUE;
   1.919 +    }
   1.920 +
   1.921 +    // Parse behavior after the colon.
   1.922 +    mTokenizer->skipDelimiters(WHITESPACE);
   1.923 +
   1.924 +    Behavior behavior;
   1.925 +    bool haveCharacter = false;
   1.926 +    bool haveFallback = false;
   1.927 +
   1.928 +    do {
   1.929 +        char ch = mTokenizer->peekChar();
   1.930 +        if (ch == '\'') {
   1.931 +            char16_t character;
   1.932 +            status_t status = parseCharacterLiteral(&character);
   1.933 +            if (status || !character) {
   1.934 +                ALOGE("%s: Invalid character literal for key.",
   1.935 +                        mTokenizer->getLocation().string());
   1.936 +                return BAD_VALUE;
   1.937 +            }
   1.938 +            if (haveCharacter) {
   1.939 +                ALOGE("%s: Cannot combine multiple character literals or 'none'.",
   1.940 +                        mTokenizer->getLocation().string());
   1.941 +                return BAD_VALUE;
   1.942 +            }
   1.943 +            behavior.character = character;
   1.944 +            haveCharacter = true;
   1.945 +        } else {
   1.946 +            token = mTokenizer->nextToken(WHITESPACE);
   1.947 +            if (token == "none") {
   1.948 +                if (haveCharacter) {
   1.949 +                    ALOGE("%s: Cannot combine multiple character literals or 'none'.",
   1.950 +                            mTokenizer->getLocation().string());
   1.951 +                    return BAD_VALUE;
   1.952 +                }
   1.953 +                haveCharacter = true;
   1.954 +            } else if (token == "fallback") {
   1.955 +                mTokenizer->skipDelimiters(WHITESPACE);
   1.956 +                token = mTokenizer->nextToken(WHITESPACE);
   1.957 +                int32_t keyCode = getKeyCodeByLabel(token.string());
   1.958 +                if (!keyCode) {
   1.959 +                    ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
   1.960 +                            mTokenizer->getLocation().string(),
   1.961 +                            token.string());
   1.962 +                    return BAD_VALUE;
   1.963 +                }
   1.964 +                if (haveFallback) {
   1.965 +                    ALOGE("%s: Cannot combine multiple fallback key codes.",
   1.966 +                            mTokenizer->getLocation().string());
   1.967 +                    return BAD_VALUE;
   1.968 +                }
   1.969 +                behavior.fallbackKeyCode = keyCode;
   1.970 +                haveFallback = true;
   1.971 +            } else {
   1.972 +                ALOGE("%s: Expected a key behavior after ':'.",
   1.973 +                        mTokenizer->getLocation().string());
   1.974 +                return BAD_VALUE;
   1.975 +            }
   1.976 +        }
   1.977 +
   1.978 +        mTokenizer->skipDelimiters(WHITESPACE);
   1.979 +    } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#');
   1.980 +
   1.981 +    // Add the behavior.
   1.982 +    for (size_t i = 0; i < properties.size(); i++) {
   1.983 +        const Property& property = properties.itemAt(i);
   1.984 +        switch (property.property) {
   1.985 +        case PROPERTY_LABEL:
   1.986 +            if (key->label) {
   1.987 +                ALOGE("%s: Duplicate label for key.",
   1.988 +                        mTokenizer->getLocation().string());
   1.989 +                return BAD_VALUE;
   1.990 +            }
   1.991 +            key->label = behavior.character;
   1.992 +#if DEBUG_PARSER
   1.993 +            ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label);
   1.994 +#endif
   1.995 +            break;
   1.996 +        case PROPERTY_NUMBER:
   1.997 +            if (key->number) {
   1.998 +                ALOGE("%s: Duplicate number for key.",
   1.999 +                        mTokenizer->getLocation().string());
  1.1000 +                return BAD_VALUE;
  1.1001 +            }
  1.1002 +            key->number = behavior.character;
  1.1003 +#if DEBUG_PARSER
  1.1004 +            ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number);
  1.1005 +#endif
  1.1006 +            break;
  1.1007 +        case PROPERTY_META: {
  1.1008 +            for (Behavior* b = key->firstBehavior; b; b = b->next) {
  1.1009 +                if (b->metaState == property.metaState) {
  1.1010 +                    ALOGE("%s: Duplicate key behavior for modifier.",
  1.1011 +                            mTokenizer->getLocation().string());
  1.1012 +                    return BAD_VALUE;
  1.1013 +                }
  1.1014 +            }
  1.1015 +            Behavior* newBehavior = new Behavior(behavior);
  1.1016 +            newBehavior->metaState = property.metaState;
  1.1017 +            newBehavior->next = key->firstBehavior;
  1.1018 +            key->firstBehavior = newBehavior;
  1.1019 +#if DEBUG_PARSER
  1.1020 +            ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d.", mKeyCode,
  1.1021 +                    newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode);
  1.1022 +#endif
  1.1023 +            break;
  1.1024 +        }
  1.1025 +        }
  1.1026 +    }
  1.1027 +    return NO_ERROR;
  1.1028 +}
  1.1029 +
  1.1030 +status_t KeyCharacterMap::Parser::finishKey(Key* key) {
  1.1031 +    // Fill in default number property.
  1.1032 +    if (!key->number) {
  1.1033 +        char16_t digit = 0;
  1.1034 +        char16_t symbol = 0;
  1.1035 +        for (Behavior* b = key->firstBehavior; b; b = b->next) {
  1.1036 +            char16_t ch = b->character;
  1.1037 +            if (ch) {
  1.1038 +                if (ch >= '0' && ch <= '9') {
  1.1039 +                    digit = ch;
  1.1040 +                } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
  1.1041 +                        || ch == '-' || ch == '+' || ch == ',' || ch == '.'
  1.1042 +                        || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
  1.1043 +                    symbol = ch;
  1.1044 +                }
  1.1045 +            }
  1.1046 +        }
  1.1047 +        key->number = digit ? digit : symbol;
  1.1048 +    }
  1.1049 +    return NO_ERROR;
  1.1050 +}
  1.1051 +
  1.1052 +status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) {
  1.1053 +    if (token == "base") {
  1.1054 +        *outMetaState = 0;
  1.1055 +        return NO_ERROR;
  1.1056 +    }
  1.1057 +
  1.1058 +    int32_t combinedMeta = 0;
  1.1059 +
  1.1060 +    const char* str = token.string();
  1.1061 +    const char* start = str;
  1.1062 +    for (const char* cur = str; ; cur++) {
  1.1063 +        char ch = *cur;
  1.1064 +        if (ch == '+' || ch == '\0') {
  1.1065 +            size_t len = cur - start;
  1.1066 +            int32_t metaState = 0;
  1.1067 +            for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
  1.1068 +                if (strlen(modifiers[i].label) == len
  1.1069 +                        && strncmp(modifiers[i].label, start, len) == 0) {
  1.1070 +                    metaState = modifiers[i].metaState;
  1.1071 +                    break;
  1.1072 +                }
  1.1073 +            }
  1.1074 +            if (!metaState) {
  1.1075 +                return BAD_VALUE;
  1.1076 +            }
  1.1077 +            if (combinedMeta & metaState) {
  1.1078 +                ALOGE("%s: Duplicate modifier combination '%s'.",
  1.1079 +                        mTokenizer->getLocation().string(), token.string());
  1.1080 +                return BAD_VALUE;
  1.1081 +            }
  1.1082 +
  1.1083 +            combinedMeta |= metaState;
  1.1084 +            start = cur + 1;
  1.1085 +
  1.1086 +            if (ch == '\0') {
  1.1087 +                break;
  1.1088 +            }
  1.1089 +        }
  1.1090 +    }
  1.1091 +    *outMetaState = combinedMeta;
  1.1092 +    return NO_ERROR;
  1.1093 +}
  1.1094 +
  1.1095 +status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
  1.1096 +    char ch = mTokenizer->nextChar();
  1.1097 +    if (ch != '\'') {
  1.1098 +        goto Error;
  1.1099 +    }
  1.1100 +
  1.1101 +    ch = mTokenizer->nextChar();
  1.1102 +    if (ch == '\\') {
  1.1103 +        // Escape sequence.
  1.1104 +        ch = mTokenizer->nextChar();
  1.1105 +        if (ch == 'n') {
  1.1106 +            *outCharacter = '\n';
  1.1107 +        } else if (ch == 't') {
  1.1108 +            *outCharacter = '\t';
  1.1109 +        } else if (ch == '\\') {
  1.1110 +            *outCharacter = '\\';
  1.1111 +        } else if (ch == '\'') {
  1.1112 +            *outCharacter = '\'';
  1.1113 +        } else if (ch == '"') {
  1.1114 +            *outCharacter = '"';
  1.1115 +        } else if (ch == 'u') {
  1.1116 +            *outCharacter = 0;
  1.1117 +            for (int i = 0; i < 4; i++) {
  1.1118 +                ch = mTokenizer->nextChar();
  1.1119 +                int digit;
  1.1120 +                if (ch >= '0' && ch <= '9') {
  1.1121 +                    digit = ch - '0';
  1.1122 +                } else if (ch >= 'A' && ch <= 'F') {
  1.1123 +                    digit = ch - 'A' + 10;
  1.1124 +                } else if (ch >= 'a' && ch <= 'f') {
  1.1125 +                    digit = ch - 'a' + 10;
  1.1126 +                } else {
  1.1127 +                    goto Error;
  1.1128 +                }
  1.1129 +                *outCharacter = (*outCharacter << 4) | digit;
  1.1130 +            }
  1.1131 +        } else {
  1.1132 +            goto Error;
  1.1133 +        }
  1.1134 +    } else if (ch >= 32 && ch <= 126 && ch != '\'') {
  1.1135 +        // ASCII literal character.
  1.1136 +        *outCharacter = ch;
  1.1137 +    } else {
  1.1138 +        goto Error;
  1.1139 +    }
  1.1140 +
  1.1141 +    ch = mTokenizer->nextChar();
  1.1142 +    if (ch != '\'') {
  1.1143 +        goto Error;
  1.1144 +    }
  1.1145 +
  1.1146 +    // Ensure that we consumed the entire token.
  1.1147 +    if (mTokenizer->nextToken(WHITESPACE).isEmpty()) {
  1.1148 +        return NO_ERROR;
  1.1149 +    }
  1.1150 +
  1.1151 +Error:
  1.1152 +    ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string());
  1.1153 +    return BAD_VALUE;
  1.1154 +}
  1.1155 +
  1.1156 +} // namespace android

mercurial