15912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown/*
25912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * Copyright (C) 2008 The Android Open Source Project
35912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown *
45912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
55912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * you may not use this file except in compliance with the License.
65912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * You may obtain a copy of the License at
75912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown *
85912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
95912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown *
105912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * Unless required by applicable law or agreed to in writing, software
115912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
125912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * See the License for the specific language governing permissions and
145912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * limitations under the License.
155912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown */
165912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
175912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#define LOG_TAG "KeyCharacterMap"
185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <stdlib.h>
205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <string.h>
215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
226071da7ef84c60645572654504813d492b8b21d5Elliott Hughes#ifdef __ANDROID__
235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <binder/Parcel.h>
245912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
255912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <android/keycodes.h>
27872db4f11e407accccba9d37c335ef7e3597eba4Michael Wright#include <input/InputEventLabels.h>
285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <input/Keyboard.h>
295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <input/KeyCharacterMap.h>
305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
315912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <utils/Log.h>
325912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <utils/Errors.h>
335912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <utils/Tokenizer.h>
345912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <utils/Timers.h>
355912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
365912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown// Enables debug output for the parser.
375912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#define DEBUG_PARSER 0
385912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
395912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown// Enables debug output for parser performance.
405912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#define DEBUG_PARSER_PERFORMANCE 0
415912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
425912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown// Enables debug output for mapping.
435912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#define DEBUG_MAPPING 0
445912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
455912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
465912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownnamespace android {
475912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
485912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatic const char* WHITESPACE = " \t\r";
495912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatic const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:";
505912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
515912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstruct Modifier {
525912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    const char* label;
535912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    int32_t metaState;
545912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown};
555912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatic const Modifier modifiers[] = {
565912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "shift", AMETA_SHIFT_ON },
575912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "lshift", AMETA_SHIFT_LEFT_ON },
585912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "rshift", AMETA_SHIFT_RIGHT_ON },
595912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "alt", AMETA_ALT_ON },
605912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "lalt", AMETA_ALT_LEFT_ON },
615912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "ralt", AMETA_ALT_RIGHT_ON },
625912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "ctrl", AMETA_CTRL_ON },
635912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "lctrl", AMETA_CTRL_LEFT_ON },
645912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "rctrl", AMETA_CTRL_RIGHT_ON },
655912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "meta", AMETA_META_ON },
665912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "lmeta", AMETA_META_LEFT_ON },
675912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "rmeta", AMETA_META_RIGHT_ON },
685912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "sym", AMETA_SYM_ON },
695912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "fn", AMETA_FUNCTION_ON },
705912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "capslock", AMETA_CAPS_LOCK_ON },
715912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "numlock", AMETA_NUM_LOCK_ON },
725912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        { "scrolllock", AMETA_SCROLL_LOCK_ON },
735912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown};
745912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
755912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_MAPPING
765912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatic String8 toString(const char16_t* chars, size_t numChars) {
775912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    String8 result;
785912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    for (size_t i = 0; i < numChars; i++) {
795912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]);
805912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
815912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return result;
825912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
835912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
845912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
855912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
865912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown// --- KeyCharacterMap ---
875912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
885912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownsp<KeyCharacterMap> KeyCharacterMap::sEmpty = new KeyCharacterMap();
895912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
905912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownKeyCharacterMap::KeyCharacterMap() :
915912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mType(KEYBOARD_TYPE_UNKNOWN) {
925912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
935912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
945912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownKeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) :
955912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    RefBase(), mType(other.mType), mKeysByScanCode(other.mKeysByScanCode),
965912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mKeysByUsageCode(other.mKeysByUsageCode) {
975912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    for (size_t i = 0; i < other.mKeys.size(); i++) {
985912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        mKeys.add(other.mKeys.keyAt(i), new Key(*other.mKeys.valueAt(i)));
995912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1005912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1015912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1025912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownKeyCharacterMap::~KeyCharacterMap() {
1035912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    for (size_t i = 0; i < mKeys.size(); i++) {
1045912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        Key* key = mKeys.editValueAt(i);
1055912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        delete key;
1065912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1075912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1085912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1095912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatus_t KeyCharacterMap::load(const String8& filename,
1105912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        Format format, sp<KeyCharacterMap>* outMap) {
1115912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    outMap->clear();
1125912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1135912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    Tokenizer* tokenizer;
1145912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    status_t status = Tokenizer::open(filename, &tokenizer);
1155912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (status) {
1165912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGE("Error %d opening key character map file %s.", status, filename.string());
1175912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    } else {
1185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        status = load(tokenizer, format, outMap);
1195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        delete tokenizer;
1205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return status;
1225912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1245912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatus_t KeyCharacterMap::loadContents(const String8& filename, const char* contents,
1255912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        Format format, sp<KeyCharacterMap>* outMap) {
1265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    outMap->clear();
1275912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    Tokenizer* tokenizer;
1295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    status_t status = Tokenizer::fromContents(filename, contents, &tokenizer);
1305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (status) {
1315912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGE("Error %d opening key character map.", status);
1325912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    } else {
1335912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        status = load(tokenizer, format, outMap);
1345912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        delete tokenizer;
1355912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1365912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return status;
1375912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1385912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1395912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatus_t KeyCharacterMap::load(Tokenizer* tokenizer,
1405912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        Format format, sp<KeyCharacterMap>* outMap) {
1415912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    status_t status = OK;
1425912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    sp<KeyCharacterMap> map = new KeyCharacterMap();
1435912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (!map.get()) {
1445912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGE("Error allocating key character map.");
1455912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        status = NO_MEMORY;
1465912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    } else {
1475912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PARSER_PERFORMANCE
1485912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
1495912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
1505912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        Parser parser(map.get(), tokenizer, format);
1515912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        status = parser.parse();
1525912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PARSER_PERFORMANCE
1535912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
1545912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
1555912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                tokenizer->getFilename().string(), tokenizer->getLineNumber(),
1565912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                elapsedTime / 1000000.0);
1575912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
1585912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (!status) {
1595912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            *outMap = map;
1605912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
1615912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1625912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return status;
1635912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1645912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1655912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownsp<KeyCharacterMap> KeyCharacterMap::combine(const sp<KeyCharacterMap>& base,
1665912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        const sp<KeyCharacterMap>& overlay) {
1675912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (overlay == NULL) {
1685912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return base;
1695912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1705912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (base == NULL) {
1715912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return overlay;
1725912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1735912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1745912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    sp<KeyCharacterMap> map = new KeyCharacterMap(*base.get());
1755912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    for (size_t i = 0; i < overlay->mKeys.size(); i++) {
1765912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t keyCode = overlay->mKeys.keyAt(i);
1775912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        Key* key = overlay->mKeys.valueAt(i);
1785912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ssize_t oldIndex = map->mKeys.indexOfKey(keyCode);
1795912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (oldIndex >= 0) {
1805912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            delete map->mKeys.valueAt(oldIndex);
1815912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            map->mKeys.editValueAt(oldIndex) = new Key(*key);
1825912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        } else {
1835912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            map->mKeys.add(keyCode, new Key(*key));
1845912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
1855912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1865912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1875912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    for (size_t i = 0; i < overlay->mKeysByScanCode.size(); i++) {
1885912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        map->mKeysByScanCode.replaceValueFor(overlay->mKeysByScanCode.keyAt(i),
1895912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                overlay->mKeysByScanCode.valueAt(i));
1905912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1915912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1925912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    for (size_t i = 0; i < overlay->mKeysByUsageCode.size(); i++) {
1935912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        map->mKeysByUsageCode.replaceValueFor(overlay->mKeysByUsageCode.keyAt(i),
1945912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                overlay->mKeysByUsageCode.valueAt(i));
1955912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1965912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return map;
1975912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1985912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1995912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownsp<KeyCharacterMap> KeyCharacterMap::empty() {
2005912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return sEmpty;
2015912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
2025912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
2035912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownint32_t KeyCharacterMap::getKeyboardType() const {
2045912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return mType;
2055912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
2065912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
2075912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownchar16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const {
2085912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    char16_t result = 0;
2095912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    const Key* key;
2105912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (getKey(keyCode, &key)) {
2115912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        result = key->label;
2125912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
2135912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_MAPPING
2145912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result);
2155912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
2165912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return result;
2175912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
2185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
2195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownchar16_t KeyCharacterMap::getNumber(int32_t keyCode) const {
2205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    char16_t result = 0;
2215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    const Key* key;
2225912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (getKey(keyCode, &key)) {
2235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        result = key->number;
2245912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
2255912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_MAPPING
2265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result);
2275912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
2285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return result;
2295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
2305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
2315912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownchar16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
2325912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    char16_t result = 0;
2335912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    const Key* key;
2345912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    const Behavior* behavior;
2355912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
2365912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        result = behavior->character;
2375912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
2385912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_MAPPING
2395912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result);
2405912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
2415912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return result;
2425912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
2435912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
2445912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownbool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState,
2455912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        FallbackAction* outFallbackAction) const {
2465912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    outFallbackAction->keyCode = 0;
2475912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    outFallbackAction->metaState = 0;
2485912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
2495912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    bool result = false;
2505912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    const Key* key;
2515912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    const Behavior* behavior;
2525912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
2535912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (behavior->fallbackKeyCode) {
2545912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            outFallbackAction->keyCode = behavior->fallbackKeyCode;
2555912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            outFallbackAction->metaState = metaState & ~behavior->metaState;
2565912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            result = true;
2575912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
2585912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
2595912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_MAPPING
2605912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, "
2615912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            "fallback keyCode=%d, fallback metaState=0x%08x.",
2625912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            keyCode, metaState, result ? "true" : "false",
2635912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            outFallbackAction->keyCode, outFallbackAction->metaState);
2645912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
2655912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return result;
2665912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
2675912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
2685912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownchar16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars,
2695912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t metaState) const {
2705912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    char16_t result = 0;
2715912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    const Key* key;
2725912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (getKey(keyCode, &key)) {
2735912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        // Try to find the most general behavior that maps to this character.
2745912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        // For example, the base key behavior will usually be last in the list.
2755912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        // However, if we find a perfect meta state match for one behavior then use that one.
2765912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
2775912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (behavior->character) {
2785912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                for (size_t i = 0; i < numChars; i++) {
2795912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    if (behavior->character == chars[i]) {
2805912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        result = behavior->character;
2815912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        if ((behavior->metaState & metaState) == behavior->metaState) {
2825912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                            goto ExactMatch;
2835912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        }
2845912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        break;
2855912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    }
2865912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                }
2875912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
2885912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
2895912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ExactMatch: ;
2905912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
2915912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_MAPPING
2925912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.",
2935912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            keyCode, toString(chars, numChars).string(), metaState, result);
2945912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
2955912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return result;
2965912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
2975912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
2985912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownbool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
2995912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        Vector<KeyEvent>& outEvents) const {
3005912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
3015912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
3025912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    for (size_t i = 0; i < numChars; i++) {
3035912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t keyCode, metaState;
3045912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        char16_t ch = chars[i];
3055912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (!findKey(ch, &keyCode, &metaState)) {
3065912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_MAPPING
3075912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.",
3085912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    deviceId, toString(chars, numChars).string(), ch);
3095912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
3105912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            return false;
3115912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
3125912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
3135912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t currentMetaState = 0;
3145912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addMetaKeys(outEvents, deviceId, metaState, true, now, &currentMetaState);
3155912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addKey(outEvents, deviceId, keyCode, currentMetaState, true, now);
3165912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addKey(outEvents, deviceId, keyCode, currentMetaState, false, now);
3175912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addMetaKeys(outEvents, deviceId, metaState, false, now, &currentMetaState);
3185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
3195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_MAPPING
3205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.",
3215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            deviceId, toString(chars, numChars).string(), int32_t(outEvents.size()));
3225912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    for (size_t i = 0; i < outEvents.size(); i++) {
3235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGD("  Key: keyCode=%d, metaState=0x%08x, %s.",
3245912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                outEvents[i].getKeyCode(), outEvents[i].getMetaState(),
3255912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up");
3265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
3275912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
3285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return true;
3295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
3305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
3315912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatus_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
3325912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (usageCode) {
3335912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
3345912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (index >= 0) {
335115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            *outKeyCode = mKeysByUsageCode.valueAt(index);
3365912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_MAPPING
337115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
338115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                    scanCode, usageCode, *outKeyCode);
3395912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
3405912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            return OK;
3415912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
3425912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
3435912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (scanCode) {
3445912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
3455912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (index >= 0) {
346115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            *outKeyCode = mKeysByScanCode.valueAt(index);
3475912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_MAPPING
348115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
349115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                    scanCode, usageCode, *outKeyCode);
3505912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
3515912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            return OK;
3525912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
3535912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
3545912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
3555912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_MAPPING
356115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov    ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
3575912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
3585912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    *outKeyCode = AKEYCODE_UNKNOWN;
3595912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return NAME_NOT_FOUND;
3605912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
3615912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
362115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhovvoid KeyCharacterMap::tryRemapKey(int32_t keyCode, int32_t metaState,
363115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                                  int32_t *outKeyCode, int32_t *outMetaState) const {
364115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov    *outKeyCode = keyCode;
365115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov    *outMetaState = metaState;
366115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov
367115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov    const Key* key;
368115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov    const Behavior* behavior;
369115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov    if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
370115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov        if (behavior->replacementKeyCode) {
371115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            *outKeyCode = behavior->replacementKeyCode;
372115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            int32_t newMetaState = metaState & ~behavior->metaState;
373115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            // Reset dependent meta states.
374115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            if (behavior->metaState & AMETA_ALT_ON) {
375115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                newMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
376115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            }
377115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            if (behavior->metaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
378115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                newMetaState &= ~AMETA_ALT_ON;
379115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            }
380115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            if (behavior->metaState & AMETA_CTRL_ON) {
381115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                newMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
382115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            }
383115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            if (behavior->metaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
384115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                newMetaState &= ~AMETA_CTRL_ON;
385115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            }
386115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            if (behavior->metaState & AMETA_SHIFT_ON) {
387115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                newMetaState &= ~(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON);
388115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            }
389115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            if (behavior->metaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
390115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                newMetaState &= ~AMETA_SHIFT_ON;
391115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            }
392115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            // ... and put universal bits back if needed
393115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            *outMetaState = normalizeMetaState(newMetaState);
394115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov        }
395115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov    }
396115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov
397115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov#if DEBUG_MAPPING
398115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov    ALOGD("tryRemapKey: keyCode=%d, metaState=0x%08x ~ "
399115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            "replacement keyCode=%d, replacement metaState=0x%08x.",
400115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            keyCode, metaState, *outKeyCode, *outMetaState);
401115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov#endif
402115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov}
403115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov
4045912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownbool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
4055912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ssize_t index = mKeys.indexOfKey(keyCode);
4065912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (index >= 0) {
4075912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        *outKey = mKeys.valueAt(index);
4085912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return true;
4095912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
4105912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return false;
4115912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
4125912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
4135912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownbool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState,
4145912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        const Key** outKey, const Behavior** outBehavior) const {
4155912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    const Key* key;
4165912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (getKey(keyCode, &key)) {
4175912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        const Behavior* behavior = key->firstBehavior;
4185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        while (behavior) {
4195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (matchesMetaState(metaState, behavior->metaState)) {
4205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                *outKey = key;
4215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                *outBehavior = behavior;
4225912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                return true;
4235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
4245912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            behavior = behavior->next;
4255912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
4265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
4275912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return false;
4285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
4295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
4305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownbool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
4315912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    // Behavior must have at least the set of meta states specified.
4325912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    // And if the key event has CTRL, ALT or META then the behavior must exactly
4335912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    // match those, taking into account that a behavior can specify that it handles
4345912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    // one, both or either of a left/right modifier pair.
4355912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if ((eventMetaState & behaviorMetaState) == behaviorMetaState) {
4365912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        const int32_t EXACT_META_STATES =
4375912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON
4385912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON
4395912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON;
4405912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES;
4415912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (behaviorMetaState & AMETA_CTRL_ON) {
4425912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
4435912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
4445912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            unmatchedMetaState &= ~AMETA_CTRL_ON;
4455912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
4465912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (behaviorMetaState & AMETA_ALT_ON) {
4475912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
4485912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
4495912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            unmatchedMetaState &= ~AMETA_ALT_ON;
4505912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
4515912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (behaviorMetaState & AMETA_META_ON) {
4525912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
4535912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
4545912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            unmatchedMetaState &= ~AMETA_META_ON;
4555912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
4565912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return !unmatchedMetaState;
4575912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
4585912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return false;
4595912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
4605912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
4615912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownbool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
4625912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (!ch) {
4635912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return false;
4645912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
4655912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
4665912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    for (size_t i = 0; i < mKeys.size(); i++) {
4675912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        const Key* key = mKeys.valueAt(i);
4685912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
4695912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        // Try to find the most general behavior that maps to this character.
4705912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        // For example, the base key behavior will usually be last in the list.
4715912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        const Behavior* found = NULL;
4725912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
4735912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (behavior->character == ch) {
4745912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                found = behavior;
4755912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
4765912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
4775912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (found) {
4785912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            *outKeyCode = mKeys.keyAt(i);
4795912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            *outMetaState = found->metaState;
4805912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            return true;
4815912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
4825912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
4835912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return false;
4845912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
4855912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
4865912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownvoid KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents,
4875912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
4885912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    outEvents.push();
4895912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    KeyEvent& event = outEvents.editTop();
4905912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD,
4915912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
4925912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            0, keyCode, 0, metaState, 0, time, time);
4935912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
4945912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
4955912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownvoid KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
4965912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
4975912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t* currentMetaState) {
4985912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    // Add and remove meta keys symmetrically.
4995912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (down) {
5005912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addLockedMetaKey(outEvents, deviceId, metaState, time,
5015912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
5025912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addLockedMetaKey(outEvents, deviceId, metaState, time,
5035912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
5045912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addLockedMetaKey(outEvents, deviceId, metaState, time,
5055912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
5065912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
5075912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
5085912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
5095912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
5105912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AMETA_SHIFT_ON, currentMetaState);
5115912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
5125912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
5135912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
5145912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AMETA_ALT_ON, currentMetaState);
5155912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
5165912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
5175912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
5185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AMETA_CTRL_ON, currentMetaState);
5195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
5205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
5215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
5225912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AMETA_META_ON, currentMetaState);
5235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
5245912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
5255912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
5265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
5275912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
5285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    } else {
5295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
5305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
5315912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
5325912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
5335912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
5345912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
5355912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
5365912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
5375912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AMETA_META_ON, currentMetaState);
5385912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
5395912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
5405912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
5415912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AMETA_CTRL_ON, currentMetaState);
5425912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
5435912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
5445912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
5455912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AMETA_ALT_ON, currentMetaState);
5465912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
5475912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
5485912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
5495912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AMETA_SHIFT_ON, currentMetaState);
5505912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
5515912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addLockedMetaKey(outEvents, deviceId, metaState, time,
5525912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
5535912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addLockedMetaKey(outEvents, deviceId, metaState, time,
5545912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
5555912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addLockedMetaKey(outEvents, deviceId, metaState, time,
5565912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
5575912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
5585912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
5595912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
5605912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownbool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
5615912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
5625912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t keyCode, int32_t keyMetaState,
5635912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t* currentMetaState) {
5645912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if ((metaState & keyMetaState) == keyMetaState) {
5655912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        *currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
5665912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
5675912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return true;
5685912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
5695912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return false;
5705912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
5715912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
5725912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownvoid KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
5735912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
5745912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t leftKeyCode, int32_t leftKeyMetaState,
5755912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t rightKeyCode, int32_t rightKeyMetaState,
5765912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t eitherKeyMetaState,
5775912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t* currentMetaState) {
5785912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    bool specific = false;
5795912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
5805912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            leftKeyCode, leftKeyMetaState, currentMetaState);
5815912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
5825912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            rightKeyCode, rightKeyMetaState, currentMetaState);
5835912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
5845912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (!specific) {
5855912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
5865912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                leftKeyCode, eitherKeyMetaState, currentMetaState);
5875912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
5885912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
5895912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
5905912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownvoid KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
5915912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t deviceId, int32_t metaState, nsecs_t time,
5925912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t keyCode, int32_t keyMetaState,
5935912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t* currentMetaState) {
5945912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if ((metaState & keyMetaState) == keyMetaState) {
5955912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        *currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
5965912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
5975912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        *currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
5985912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
5995912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
6005912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
6015912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
6026071da7ef84c60645572654504813d492b8b21d5Elliott Hughes#ifdef __ANDROID__
6035912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownsp<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
6045912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    sp<KeyCharacterMap> map = new KeyCharacterMap();
6055912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    map->mType = parcel->readInt32();
6065912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    size_t numKeys = parcel->readInt32();
6075912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (parcel->errorCheck()) {
6085912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return NULL;
6095912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
6104c971c001f401d7742db326c8e5654693eb3687eMichael Wright    if (numKeys > MAX_KEYS) {
611d57d9b900da83b1b5431d90e250f86c0047c618aIan Pedowitz        ALOGE("Too many keys in KeyCharacterMap (%zu > %d)", numKeys, MAX_KEYS);
6124c971c001f401d7742db326c8e5654693eb3687eMichael Wright        return NULL;
6134c971c001f401d7742db326c8e5654693eb3687eMichael Wright    }
6145912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
6155912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    for (size_t i = 0; i < numKeys; i++) {
6165912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t keyCode = parcel->readInt32();
6175912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        char16_t label = parcel->readInt32();
6185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        char16_t number = parcel->readInt32();
6195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (parcel->errorCheck()) {
6205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            return NULL;
6215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
6225912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
6235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        Key* key = new Key();
6245912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        key->label = label;
6255912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        key->number = number;
6265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        map->mKeys.add(keyCode, key);
6275912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
6285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        Behavior* lastBehavior = NULL;
6295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        while (parcel->readInt32()) {
6305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            int32_t metaState = parcel->readInt32();
6315912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            char16_t character = parcel->readInt32();
6325912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            int32_t fallbackKeyCode = parcel->readInt32();
633115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            int32_t replacementKeyCode = parcel->readInt32();
6345912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (parcel->errorCheck()) {
6355912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                return NULL;
6365912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
6375912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
6385912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            Behavior* behavior = new Behavior();
6395912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            behavior->metaState = metaState;
6405912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            behavior->character = character;
6415912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            behavior->fallbackKeyCode = fallbackKeyCode;
642115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            behavior->replacementKeyCode = replacementKeyCode;
6435912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (lastBehavior) {
6445912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                lastBehavior->next = behavior;
6455912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            } else {
6465912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                key->firstBehavior = behavior;
6475912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
6485912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            lastBehavior = behavior;
6495912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
6505912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
6515912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (parcel->errorCheck()) {
6525912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            return NULL;
6535912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
6545912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
6555912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return map;
6565912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
6575912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
6585912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownvoid KeyCharacterMap::writeToParcel(Parcel* parcel) const {
6595912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    parcel->writeInt32(mType);
6605912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
6615912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    size_t numKeys = mKeys.size();
6625912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    parcel->writeInt32(numKeys);
6635912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    for (size_t i = 0; i < numKeys; i++) {
6645912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t keyCode = mKeys.keyAt(i);
6655912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        const Key* key = mKeys.valueAt(i);
6665912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        parcel->writeInt32(keyCode);
6675912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        parcel->writeInt32(key->label);
6685912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        parcel->writeInt32(key->number);
6695912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        for (const Behavior* behavior = key->firstBehavior; behavior != NULL;
6705912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                behavior = behavior->next) {
6715912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            parcel->writeInt32(1);
6725912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            parcel->writeInt32(behavior->metaState);
6735912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            parcel->writeInt32(behavior->character);
6745912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            parcel->writeInt32(behavior->fallbackKeyCode);
675115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            parcel->writeInt32(behavior->replacementKeyCode);
6765912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
6775912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        parcel->writeInt32(0);
6785912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
6795912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
6805912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
6815912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
6825912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
6835912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown// --- KeyCharacterMap::Key ---
6845912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
6855912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownKeyCharacterMap::Key::Key() :
6865912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        label(0), number(0), firstBehavior(NULL) {
6875912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
6885912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
6895912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownKeyCharacterMap::Key::Key(const Key& other) :
6905912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        label(other.label), number(other.number),
6915912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) {
6925912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
6935912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
6945912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownKeyCharacterMap::Key::~Key() {
6955912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    Behavior* behavior = firstBehavior;
6965912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    while (behavior) {
6975912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        Behavior* next = behavior->next;
6985912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        delete behavior;
6995912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        behavior = next;
7005912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
7015912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
7025912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7035912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7045912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown// --- KeyCharacterMap::Behavior ---
7055912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7065912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownKeyCharacterMap::Behavior::Behavior() :
707115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov        next(NULL), metaState(0), character(0), fallbackKeyCode(0), replacementKeyCode(0) {
7085912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
7095912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7105912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownKeyCharacterMap::Behavior::Behavior(const Behavior& other) :
7115912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        next(other.next ? new Behavior(*other.next) : NULL),
7125912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        metaState(other.metaState), character(other.character),
713115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov        fallbackKeyCode(other.fallbackKeyCode),
714115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov        replacementKeyCode(other.replacementKeyCode) {
7155912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
7165912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7175912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown// --- KeyCharacterMap::Parser ---
7195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownKeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
7215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
7225912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
7235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7245912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownKeyCharacterMap::Parser::~Parser() {
7255912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
7265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7275912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatus_t KeyCharacterMap::Parser::parse() {
7285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    while (!mTokenizer->isEof()) {
7295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PARSER
7305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
7315912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                mTokenizer->peekRemainderOfLine().string());
7325912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
7335912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7345912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        mTokenizer->skipDelimiters(WHITESPACE);
7355912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7365912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
7375912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            switch (mState) {
7385912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            case STATE_TOP: {
7395912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
7405912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                if (keywordToken == "type") {
7415912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    mTokenizer->skipDelimiters(WHITESPACE);
7425912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    status_t status = parseType();
7435912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    if (status) return status;
7445912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                } else if (keywordToken == "map") {
7455912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    mTokenizer->skipDelimiters(WHITESPACE);
7465912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    status_t status = parseMap();
7475912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    if (status) return status;
7485912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                } else if (keywordToken == "key") {
7495912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    mTokenizer->skipDelimiters(WHITESPACE);
7505912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    status_t status = parseKey();
7515912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    if (status) return status;
7525912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                } else {
7535912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
7545912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                            keywordToken.string());
7555912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    return BAD_VALUE;
7565912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                }
7575912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                break;
7585912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
7595912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7605912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            case STATE_KEY: {
7615912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                status_t status = parseKeyProperty();
7625912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                if (status) return status;
7635912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                break;
7645912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
7655912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
7665912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7675912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            mTokenizer->skipDelimiters(WHITESPACE);
7685912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
7695912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
7705912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        mTokenizer->getLocation().string(),
7715912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        mTokenizer->peekRemainderOfLine().string());
7725912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                return BAD_VALUE;
7735912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
7745912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
7755912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7765912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        mTokenizer->nextLine();
7775912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
7785912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7795912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (mState != STATE_TOP) {
7805912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGE("%s: Unterminated key description at end of file.",
7815912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                mTokenizer->getLocation().string());
7825912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return BAD_VALUE;
7835912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
7845912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7855912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
7865912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
7875912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                mTokenizer->getLocation().string());
7885912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return BAD_VALUE;
7895912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
7905912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
7915912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (mFormat == FORMAT_BASE) {
7925912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (mMap->mType == KEYBOARD_TYPE_OVERLAY) {
7935912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
7945912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    mTokenizer->getLocation().string());
7955912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            return BAD_VALUE;
7965912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
7975912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    } else if (mFormat == FORMAT_OVERLAY) {
7985912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (mMap->mType != KEYBOARD_TYPE_OVERLAY) {
7995912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            ALOGE("%s: Overlay keyboard layout missing required keyboard "
8005912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    "'type OVERLAY' declaration.",
8015912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    mTokenizer->getLocation().string());
8025912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            return BAD_VALUE;
8035912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
8045912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
8055912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
8065912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return NO_ERROR;
8075912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
8085912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
8095912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatus_t KeyCharacterMap::Parser::parseType() {
8105912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) {
8115912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGE("%s: Duplicate keyboard 'type' declaration.",
8125912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                mTokenizer->getLocation().string());
8135912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return BAD_VALUE;
8145912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
8155912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
8165912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    KeyboardType type;
8175912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    String8 typeToken = mTokenizer->nextToken(WHITESPACE);
8185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (typeToken == "NUMERIC") {
8195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        type = KEYBOARD_TYPE_NUMERIC;
8205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    } else if (typeToken == "PREDICTIVE") {
8215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        type = KEYBOARD_TYPE_PREDICTIVE;
8225912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    } else if (typeToken == "ALPHA") {
8235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        type = KEYBOARD_TYPE_ALPHA;
8245912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    } else if (typeToken == "FULL") {
8255912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        type = KEYBOARD_TYPE_FULL;
8265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    } else if (typeToken == "SPECIAL_FUNCTION") {
8275912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        type = KEYBOARD_TYPE_SPECIAL_FUNCTION;
8285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    } else if (typeToken == "OVERLAY") {
8295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        type = KEYBOARD_TYPE_OVERLAY;
8305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    } else {
8315912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(),
8325912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                typeToken.string());
8335912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return BAD_VALUE;
8345912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
8355912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
8365912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PARSER
8375912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ALOGD("Parsed type: type=%d.", type);
8385912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
8395912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mMap->mType = type;
8405912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return NO_ERROR;
8415912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
8425912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
8435912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatus_t KeyCharacterMap::Parser::parseMap() {
8445912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
8455912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (keywordToken == "key") {
8465912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        mTokenizer->skipDelimiters(WHITESPACE);
8475912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return parseMapKey();
8485912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
8495912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(),
8505912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            keywordToken.string());
8515912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return BAD_VALUE;
8525912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
8535912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
8545912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatus_t KeyCharacterMap::Parser::parseMapKey() {
8555912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    String8 codeToken = mTokenizer->nextToken(WHITESPACE);
8565912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    bool mapUsage = false;
8575912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (codeToken == "usage") {
8585912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        mapUsage = true;
8595912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        mTokenizer->skipDelimiters(WHITESPACE);
8605912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        codeToken = mTokenizer->nextToken(WHITESPACE);
8615912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
8625912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
8635912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    char* end;
8645912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
8655912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (*end) {
8665912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
8675912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                mapUsage ? "usage" : "scan code", codeToken.string());
8685912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return BAD_VALUE;
8695912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
8705912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    KeyedVector<int32_t, int32_t>& map =
8715912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
8725912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (map.indexOfKey(code) >= 0) {
8735912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
8745912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                mapUsage ? "usage" : "scan code", codeToken.string());
8755912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return BAD_VALUE;
8765912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
8775912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
8785912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mTokenizer->skipDelimiters(WHITESPACE);
8795912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
8805912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
8815912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (!keyCode) {
8825912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
8835912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                keyCodeToken.string());
8845912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return BAD_VALUE;
8855912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
8865912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
8875912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PARSER
8885912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
8895912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            mapUsage ? "usage" : "scan code", code, keyCode);
8905912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
8915912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    map.add(code, keyCode);
8925912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return NO_ERROR;
8935912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
8945912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
8955912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatus_t KeyCharacterMap::Parser::parseKey() {
8965912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
8975912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
8985912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (!keyCode) {
8995912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
9005912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                keyCodeToken.string());
9015912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return BAD_VALUE;
9025912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
9035912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (mMap->mKeys.indexOfKey(keyCode) >= 0) {
9045912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(),
9055912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                keyCodeToken.string());
9065912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return BAD_VALUE;
9075912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
9085912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
9095912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mTokenizer->skipDelimiters(WHITESPACE);
9105912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
9115912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (openBraceToken != "{") {
9125912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGE("%s: Expected '{' after key code label, got '%s'.",
9135912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                mTokenizer->getLocation().string(), openBraceToken.string());
9145912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return BAD_VALUE;
9155912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
9165912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
9175912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PARSER
9185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ALOGD("Parsed beginning of key: keyCode=%d.", keyCode);
9195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
9205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mKeyCode = keyCode;
9215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mMap->mKeys.add(keyCode, new Key());
9225912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mState = STATE_KEY;
9235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return NO_ERROR;
9245912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
9255912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
9265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatus_t KeyCharacterMap::Parser::parseKeyProperty() {
9275912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    Key* key = mMap->mKeys.valueFor(mKeyCode);
9285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
9295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (token == "}") {
9305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        mState = STATE_TOP;
9315912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return finishKey(key);
9325912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
9335912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
9345912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    Vector<Property> properties;
9355912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
9365912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    // Parse all comma-delimited property names up to the first colon.
9375912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    for (;;) {
9385912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (token == "label") {
9395912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            properties.add(Property(PROPERTY_LABEL));
9405912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        } else if (token == "number") {
9415912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            properties.add(Property(PROPERTY_NUMBER));
9425912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        } else {
9435912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            int32_t metaState;
9445912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            status_t status = parseModifier(token, &metaState);
9455912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (status) {
9465912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                ALOGE("%s: Expected a property name or modifier, got '%s'.",
9475912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        mTokenizer->getLocation().string(), token.string());
9485912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                return status;
9495912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
9505912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            properties.add(Property(PROPERTY_META, metaState));
9515912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
9525912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
9535912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        mTokenizer->skipDelimiters(WHITESPACE);
9545912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (!mTokenizer->isEol()) {
9555912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            char ch = mTokenizer->nextChar();
9565912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (ch == ':') {
9575912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                break;
9585912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            } else if (ch == ',') {
9595912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                mTokenizer->skipDelimiters(WHITESPACE);
9605912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
9615912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                continue;
9625912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
9635912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
9645912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
9655912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGE("%s: Expected ',' or ':' after property name.",
9665912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                mTokenizer->getLocation().string());
9675912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return BAD_VALUE;
9685912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
9695912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
9705912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    // Parse behavior after the colon.
9715912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mTokenizer->skipDelimiters(WHITESPACE);
9725912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
9735912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    Behavior behavior;
9745912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    bool haveCharacter = false;
9755912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    bool haveFallback = false;
976115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov    bool haveReplacement = false;
9775912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
9785912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    do {
9795912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        char ch = mTokenizer->peekChar();
9805912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (ch == '\'') {
9815912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            char16_t character;
9825912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            status_t status = parseCharacterLiteral(&character);
9835912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (status || !character) {
9845912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                ALOGE("%s: Invalid character literal for key.",
9855912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        mTokenizer->getLocation().string());
9865912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                return BAD_VALUE;
9875912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
9885912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (haveCharacter) {
9895912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                ALOGE("%s: Cannot combine multiple character literals or 'none'.",
9905912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        mTokenizer->getLocation().string());
9915912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                return BAD_VALUE;
9925912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
993115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            if (haveReplacement) {
994115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                ALOGE("%s: Cannot combine character literal with replace action.",
995115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                        mTokenizer->getLocation().string());
996115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                return BAD_VALUE;
997115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            }
9985912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            behavior.character = character;
9995912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            haveCharacter = true;
10005912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        } else {
10015912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            token = mTokenizer->nextToken(WHITESPACE);
10025912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (token == "none") {
10035912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                if (haveCharacter) {
10045912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    ALOGE("%s: Cannot combine multiple character literals or 'none'.",
10055912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                            mTokenizer->getLocation().string());
10065912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    return BAD_VALUE;
10075912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                }
1008115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                if (haveReplacement) {
1009115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                    ALOGE("%s: Cannot combine 'none' with replace action.",
1010115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                            mTokenizer->getLocation().string());
1011115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                    return BAD_VALUE;
1012115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                }
10135912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                haveCharacter = true;
10145912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            } else if (token == "fallback") {
10155912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                mTokenizer->skipDelimiters(WHITESPACE);
10165912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                token = mTokenizer->nextToken(WHITESPACE);
10175912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                int32_t keyCode = getKeyCodeByLabel(token.string());
10185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                if (!keyCode) {
10195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
10205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                            mTokenizer->getLocation().string(),
10215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                            token.string());
10225912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    return BAD_VALUE;
10235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                }
1024115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                if (haveFallback || haveReplacement) {
1025115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                    ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
10265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                            mTokenizer->getLocation().string());
10275912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    return BAD_VALUE;
10285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                }
10295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                behavior.fallbackKeyCode = keyCode;
10305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                haveFallback = true;
1031115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            } else if (token == "replace") {
1032115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                mTokenizer->skipDelimiters(WHITESPACE);
1033115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                token = mTokenizer->nextToken(WHITESPACE);
1034115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                int32_t keyCode = getKeyCodeByLabel(token.string());
1035115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                if (!keyCode) {
1036115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                    ALOGE("%s: Invalid key code label for replace, got '%s'.",
1037115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                            mTokenizer->getLocation().string(),
1038115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                            token.string());
1039115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                    return BAD_VALUE;
1040115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                }
1041115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                if (haveCharacter) {
1042115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                    ALOGE("%s: Cannot combine character literal with replace action.",
1043115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                            mTokenizer->getLocation().string());
1044115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                    return BAD_VALUE;
1045115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                }
1046115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                if (haveFallback || haveReplacement) {
1047115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                    ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
1048115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                            mTokenizer->getLocation().string());
1049115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                    return BAD_VALUE;
1050115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                }
1051115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                behavior.replacementKeyCode = keyCode;
1052115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                haveReplacement = true;
1053115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov
10545912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            } else {
10555912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                ALOGE("%s: Expected a key behavior after ':'.",
10565912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        mTokenizer->getLocation().string());
10575912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                return BAD_VALUE;
10585912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
10595912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
10605912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
10615912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        mTokenizer->skipDelimiters(WHITESPACE);
10625912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#');
10635912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
10645912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    // Add the behavior.
10655912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    for (size_t i = 0; i < properties.size(); i++) {
10665912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        const Property& property = properties.itemAt(i);
10675912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        switch (property.property) {
10685912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        case PROPERTY_LABEL:
10695912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (key->label) {
10705912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                ALOGE("%s: Duplicate label for key.",
10715912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        mTokenizer->getLocation().string());
10725912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                return BAD_VALUE;
10735912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
10745912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            key->label = behavior.character;
10755912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PARSER
10765912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label);
10775912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
10785912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            break;
10795912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        case PROPERTY_NUMBER:
10805912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (key->number) {
10815912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                ALOGE("%s: Duplicate number for key.",
10825912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        mTokenizer->getLocation().string());
10835912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                return BAD_VALUE;
10845912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
10855912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            key->number = behavior.character;
10865912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PARSER
10875912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number);
10885912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
10895912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            break;
10905912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        case PROPERTY_META: {
10915912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            for (Behavior* b = key->firstBehavior; b; b = b->next) {
10925912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                if (b->metaState == property.metaState) {
10935912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    ALOGE("%s: Duplicate key behavior for modifier.",
10945912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                            mTokenizer->getLocation().string());
10955912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    return BAD_VALUE;
10965912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                }
10975912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
10985912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            Behavior* newBehavior = new Behavior(behavior);
10995912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            newBehavior->metaState = property.metaState;
11005912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            newBehavior->next = key->firstBehavior;
11015912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            key->firstBehavior = newBehavior;
11025912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PARSER
1103115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov            ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
1104115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                    mKeyCode,
1105115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                    newBehavior->metaState, newBehavior->character,
1106115f93eeebf7f33b56ed090de70d6e8c733e5d88Dmitry Torokhov                    newBehavior->fallbackKeyCode, newBehavior->replacementKeyCode);
11075912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
11085912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            break;
11095912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
11105912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
11115912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
11125912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return NO_ERROR;
11135912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
11145912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
11155912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatus_t KeyCharacterMap::Parser::finishKey(Key* key) {
11165912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    // Fill in default number property.
11175912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (!key->number) {
11185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        char16_t digit = 0;
11195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        char16_t symbol = 0;
11205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        for (Behavior* b = key->firstBehavior; b; b = b->next) {
11215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            char16_t ch = b->character;
11225912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (ch) {
11235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                if (ch >= '0' && ch <= '9') {
11245912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    digit = ch;
11255912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
11265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        || ch == '-' || ch == '+' || ch == ',' || ch == '.'
11275912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
11285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    symbol = ch;
11295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                }
11305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
11315912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
11325912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        key->number = digit ? digit : symbol;
11335912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
11345912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return NO_ERROR;
11355912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
11365912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
11375912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatus_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) {
11385912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (token == "base") {
11395912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        *outMetaState = 0;
11405912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return NO_ERROR;
11415912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
11425912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
11435912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    int32_t combinedMeta = 0;
11445912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
11455912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    const char* str = token.string();
11465912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    const char* start = str;
11475912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    for (const char* cur = str; ; cur++) {
11485912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        char ch = *cur;
11495912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (ch == '+' || ch == '\0') {
11505912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            size_t len = cur - start;
11515912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            int32_t metaState = 0;
11525912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
11535912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                if (strlen(modifiers[i].label) == len
11545912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        && strncmp(modifiers[i].label, start, len) == 0) {
11555912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    metaState = modifiers[i].metaState;
11565912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    break;
11575912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                }
11585912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
11595912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (!metaState) {
11605912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                return BAD_VALUE;
11615912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
11625912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (combinedMeta & metaState) {
11635912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                ALOGE("%s: Duplicate modifier combination '%s'.",
11645912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        mTokenizer->getLocation().string(), token.string());
11655912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                return BAD_VALUE;
11665912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
11675912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
11685912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            combinedMeta |= metaState;
11695912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            start = cur + 1;
11705912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
11715912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (ch == '\0') {
11725912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                break;
11735912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
11745912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
11755912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
11765912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    *outMetaState = combinedMeta;
11775912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return NO_ERROR;
11785912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
11795912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
11805912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatus_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
11815912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    char ch = mTokenizer->nextChar();
11825912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (ch != '\'') {
11835912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        goto Error;
11845912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
11855912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
11865912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ch = mTokenizer->nextChar();
11875912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (ch == '\\') {
11885912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        // Escape sequence.
11895912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ch = mTokenizer->nextChar();
11905912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (ch == 'n') {
11915912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            *outCharacter = '\n';
11925912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        } else if (ch == 't') {
11935912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            *outCharacter = '\t';
11945912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        } else if (ch == '\\') {
11955912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            *outCharacter = '\\';
11965912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        } else if (ch == '\'') {
11975912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            *outCharacter = '\'';
11985912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        } else if (ch == '"') {
11995912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            *outCharacter = '"';
12005912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        } else if (ch == 'u') {
12015912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            *outCharacter = 0;
12025912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            for (int i = 0; i < 4; i++) {
12035912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                ch = mTokenizer->nextChar();
12045912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                int digit;
12055912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                if (ch >= '0' && ch <= '9') {
12065912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    digit = ch - '0';
12075912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                } else if (ch >= 'A' && ch <= 'F') {
12085912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    digit = ch - 'A' + 10;
12095912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                } else if (ch >= 'a' && ch <= 'f') {
12105912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    digit = ch - 'a' + 10;
12115912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                } else {
12125912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    goto Error;
12135912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                }
12145912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                *outCharacter = (*outCharacter << 4) | digit;
12155912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
12165912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        } else {
12175912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            goto Error;
12185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
12195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    } else if (ch >= 32 && ch <= 126 && ch != '\'') {
12205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        // ASCII literal character.
12215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        *outCharacter = ch;
12225912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    } else {
12235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        goto Error;
12245912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
12255912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
12265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ch = mTokenizer->nextChar();
12275912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (ch != '\'') {
12285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        goto Error;
12295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
12305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
12315912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    // Ensure that we consumed the entire token.
12325912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (mTokenizer->nextToken(WHITESPACE).isEmpty()) {
12335912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return NO_ERROR;
12345912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
12355912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
12365912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownError:
12375912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string());
12385912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return BAD_VALUE;
12395912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
12405912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
12415912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown} // namespace android
1242