16b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown/*
26b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * Copyright (C) 2010 The Android Open Source Project
36b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown *
46b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
56b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * you may not use this file except in compliance with the License.
66b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * You may obtain a copy of the License at
76b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown *
86b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
96b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown *
106b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * Unless required by applicable law or agreed to in writing, software
116b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
126b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * See the License for the specific language governing permissions and
146b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * limitations under the License.
156b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown */
166b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
176b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown#define LOG_TAG "Keyboard"
186b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
196b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown#include <stdlib.h>
206b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown#include <unistd.h>
216b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown#include <limits.h>
226b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
23b93a03f841d93498bfea6cc92a22faa34bce1337Mathias Agopian#include <androidfw/Keyboard.h>
24b93a03f841d93498bfea6cc92a22faa34bce1337Mathias Agopian#include <androidfw/KeycodeLabels.h>
25b93a03f841d93498bfea6cc92a22faa34bce1337Mathias Agopian#include <androidfw/KeyLayoutMap.h>
26b93a03f841d93498bfea6cc92a22faa34bce1337Mathias Agopian#include <androidfw/KeyCharacterMap.h>
279f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#include <androidfw/InputDevice.h>
286b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown#include <utils/Errors.h>
296b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown#include <utils/Log.h>
306b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown#include <cutils/properties.h>
316b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
326b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brownnamespace android {
336b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
349065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown// --- KeyMap ---
356b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
369f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff BrownKeyMap::KeyMap() {
379065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown}
386b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
399065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff BrownKeyMap::~KeyMap() {
406b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown}
416b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
429065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brownstatus_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
439065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        const PropertyMap* deviceConfiguration) {
4447e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown    // Use the configured key layout if available.
4547e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown    if (deviceConfiguration) {
4647e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown        String8 keyLayoutName;
4747e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown        if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
4847e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown                keyLayoutName)) {
499065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown            status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName);
509065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown            if (status == NAME_NOT_FOUND) {
513762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
5247e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown                        "it was not found.",
539065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown                        deviceIdenfifier.name.string(), keyLayoutName.string());
5447e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown            }
5547e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown        }
566b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
5747e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown        String8 keyCharacterMapName;
5847e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown        if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
5947e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown                keyCharacterMapName)) {
609065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown            status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName);
619065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown            if (status == NAME_NOT_FOUND) {
623762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                ALOGE("Configuration for keyboard device '%s' requested keyboard character "
6347e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown                        "map '%s' but it was not found.",
649065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown                        deviceIdenfifier.name.string(), keyLayoutName.string());
6547e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown            }
6647e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown        }
676b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
689065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        if (isComplete()) {
6947e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown            return OK;
7047e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown        }
7147e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown    }
7247e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown
739065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    // Try searching by device identifier.
749065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    if (probeKeyMap(deviceIdenfifier, String8::empty())) {
7547e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown        return OK;
7647e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown    }
776b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
7847e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown    // Fall back on the Generic key map.
796b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    // TODO Apply some additional heuristics here to figure out what kind of
809065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    //      generic key map to use (US English, etc.) for typical external keyboards.
819065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {
829065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        return OK;
839065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    }
849065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown
859065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    // Try the Virtual key map as a last resort.
869065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) {
8747e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown        return OK;
8847e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown    }
896b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
906b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    // Give up!
913762c311729fe9f3af085c14c5c1fb471d994c03Steve Block    ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
929065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown            deviceIdenfifier.name.string());
936b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    return NAME_NOT_FOUND;
946b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown}
956b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
969065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brownbool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
979065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        const String8& keyMapName) {
989065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    if (!haveKeyLayout()) {
999065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        loadKeyLayout(deviceIdentifier, keyMapName);
1009065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    }
1019065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    if (!haveKeyCharacterMap()) {
1029065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        loadKeyCharacterMap(deviceIdentifier, keyMapName);
1039065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    }
1049065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    return isComplete();
1059065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown}
1069065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown
1079065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brownstatus_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
1089065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        const String8& name) {
1099065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    String8 path(getPath(deviceIdentifier, name,
1109065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown            INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
1119065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    if (path.isEmpty()) {
1129065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        return NAME_NOT_FOUND;
1139065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    }
1149065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown
1159f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown    status_t status = KeyLayoutMap::load(path, &keyLayoutMap);
1169065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    if (status) {
1179065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        return status;
1189065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    }
1199065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown
1209065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    keyLayoutFile.setTo(path);
1219065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    return OK;
1229065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown}
1239065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown
1249065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brownstatus_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
1259065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        const String8& name) {
1269065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    String8 path(getPath(deviceIdentifier, name,
1279065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown            INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
1289065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    if (path.isEmpty()) {
1299065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        return NAME_NOT_FOUND;
1309065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    }
1319065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown
1326ec6f79e1ac1714e3b837796e99f07ff88f66601Jeff Brown    status_t status = KeyCharacterMap::load(path,
1336ec6f79e1ac1714e3b837796e99f07ff88f66601Jeff Brown            KeyCharacterMap::FORMAT_BASE, &keyCharacterMap);
1349065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    if (status) {
1359065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        return status;
1369065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    }
1379065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown
1389065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    keyCharacterMapFile.setTo(path);
1399065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    return OK;
1409065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown}
1419065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown
1429065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff BrownString8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
1439065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        const String8& name, InputDeviceConfigurationFileType type) {
1449065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    return name.isEmpty()
1459065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown            ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
1469065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown            : getInputDeviceConfigurationFilePathByName(name, type);
1479065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown}
1489065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown
1499065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown
1509065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown// --- Global functions ---
1519065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown
1529065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brownbool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
1539065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        const PropertyMap* deviceConfiguration, const KeyMap* keyMap) {
1549065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    if (!keyMap->haveKeyCharacterMap()
1559065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown            || keyMap->keyCharacterMap->getKeyboardType()
1569065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown                    == KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) {
1579065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        return false;
1589065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    }
1599065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown
1609065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    if (deviceConfiguration) {
1619065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        bool builtIn = false;
1629065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn)
1639065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown                && builtIn) {
1649065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown            return true;
1659065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown        }
1669065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    }
1679065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown
1689065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown    return strstr(deviceIdentifier.name.string(), "-keypad");
1699065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown}
1709065504a63d6bf37bf621191fda1d1fe4da76ee3Jeff Brown
1716f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brownstatic int lookupValueByLabel(const char* literal, const KeycodeLabel *list) {
1726b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    while (list->literal) {
1736b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        if (strcmp(literal, list->literal) == 0) {
1746b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown            return list->value;
1756b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        }
1766b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        list++;
1776b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    }
1786b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    return list->value;
1796b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown}
1806b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
1816f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brownstatic const char* lookupLabelByValue(int value, const KeycodeLabel *list) {
1826f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown    while (list->literal) {
1836f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown        if (list->value == value) {
1846f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown            return list->literal;
1856f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown        }
1866f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown        list++;
1876f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown    }
1886f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown    return NULL;
1896f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown}
1906f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown
1916b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brownint32_t getKeyCodeByLabel(const char* label) {
1926f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown    return int32_t(lookupValueByLabel(label, KEYCODES));
1936b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown}
1946b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
1956b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brownuint32_t getKeyFlagByLabel(const char* label) {
1966f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown    return uint32_t(lookupValueByLabel(label, FLAGS));
1976f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown}
1986f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown
1996f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brownint32_t getAxisByLabel(const char* label) {
2006f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown    return int32_t(lookupValueByLabel(label, AXES));
2016f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown}
2026f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown
2036f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brownconst char* getAxisLabel(int32_t axisId) {
2046f2fba428ca5e77a26d991ad728e346cc47609eeJeff Brown    return lookupLabelByValue(axisId, AXES);
2056b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown}
2066b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
2076b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brownstatic int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) {
2086b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    int32_t newMetaState;
2096b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    if (down) {
2106b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        newMetaState = oldMetaState | mask;
2116b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    } else {
2126b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        newMetaState = oldMetaState &
2136b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown                ~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON);
2146b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    }
2156b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
2166b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
2176b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        newMetaState |= AMETA_ALT_ON;
2186b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    }
2196b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
2206b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
2216b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        newMetaState |= AMETA_SHIFT_ON;
2226b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    }
2236b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
2246b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    if (newMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
2256b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        newMetaState |= AMETA_CTRL_ON;
2266b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    }
2276b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
2286b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    if (newMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
2296b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        newMetaState |= AMETA_META_ON;
2306b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    }
2316b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    return newMetaState;
2326b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown}
2336b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
2346b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brownstatic int32_t toggleLockedMetaState(int32_t mask, bool down, int32_t oldMetaState) {
2356b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    if (down) {
2366b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return oldMetaState;
2376b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    } else {
2386b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return oldMetaState ^ mask;
2396b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    }
2406b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown}
2416b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
2426b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brownint32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
2436b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    int32_t mask;
2446b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    switch (keyCode) {
2456b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    case AKEYCODE_ALT_LEFT:
2466b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState);
2476b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    case AKEYCODE_ALT_RIGHT:
2486b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return setEphemeralMetaState(AMETA_ALT_RIGHT_ON, down, oldMetaState);
2496b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    case AKEYCODE_SHIFT_LEFT:
2506b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return setEphemeralMetaState(AMETA_SHIFT_LEFT_ON, down, oldMetaState);
2516b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    case AKEYCODE_SHIFT_RIGHT:
2526b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return setEphemeralMetaState(AMETA_SHIFT_RIGHT_ON, down, oldMetaState);
2536b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    case AKEYCODE_SYM:
2546b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return setEphemeralMetaState(AMETA_SYM_ON, down, oldMetaState);
2556b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    case AKEYCODE_FUNCTION:
2566b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return setEphemeralMetaState(AMETA_FUNCTION_ON, down, oldMetaState);
2576b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    case AKEYCODE_CTRL_LEFT:
2586b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return setEphemeralMetaState(AMETA_CTRL_LEFT_ON, down, oldMetaState);
2596b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    case AKEYCODE_CTRL_RIGHT:
2606b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return setEphemeralMetaState(AMETA_CTRL_RIGHT_ON, down, oldMetaState);
2616b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    case AKEYCODE_META_LEFT:
2626b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return setEphemeralMetaState(AMETA_META_LEFT_ON, down, oldMetaState);
2636b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    case AKEYCODE_META_RIGHT:
2646b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return setEphemeralMetaState(AMETA_META_RIGHT_ON, down, oldMetaState);
2656b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    case AKEYCODE_CAPS_LOCK:
2666b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return toggleLockedMetaState(AMETA_CAPS_LOCK_ON, down, oldMetaState);
2676b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    case AKEYCODE_NUM_LOCK:
2686b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return toggleLockedMetaState(AMETA_NUM_LOCK_ON, down, oldMetaState);
2696b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    case AKEYCODE_SCROLL_LOCK:
2706b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return toggleLockedMetaState(AMETA_SCROLL_LOCK_ON, down, oldMetaState);
2716b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    default:
2726b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown        return oldMetaState;
2736b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown    }
2746b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown}
2756b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
27605dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brownbool isMetaKey(int32_t keyCode) {
27705dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown    switch (keyCode) {
27805dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown    case AKEYCODE_ALT_LEFT:
27905dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown    case AKEYCODE_ALT_RIGHT:
28005dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown    case AKEYCODE_SHIFT_LEFT:
28105dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown    case AKEYCODE_SHIFT_RIGHT:
28205dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown    case AKEYCODE_SYM:
28305dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown    case AKEYCODE_FUNCTION:
28405dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown    case AKEYCODE_CTRL_LEFT:
28505dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown    case AKEYCODE_CTRL_RIGHT:
28605dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown    case AKEYCODE_META_LEFT:
28705dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown    case AKEYCODE_META_RIGHT:
28805dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown    case AKEYCODE_CAPS_LOCK:
28905dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown    case AKEYCODE_NUM_LOCK:
29005dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown    case AKEYCODE_SCROLL_LOCK:
29105dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown        return true;
29205dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown    default:
29305dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown        return false;
29405dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown    }
29505dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown}
29605dc66ada6b61a6bdf806ffaa62617ac5394695dJeff Brown
2976b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown
2986b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown} // namespace android
299