15912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown/*
25912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * Copyright (C) 2012 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 "InputDevice"
185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <stdlib.h>
205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <unistd.h>
215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <ctype.h>
225912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <input/InputDevice.h>
247ead73ed26403405bddd625c6ea0f009bff92939Jaekyun Seok#include <input/InputEventLabels.h>
255912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownnamespace android {
275912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatic const char* CONFIGURATION_FILE_DIR[] = {
295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        "idc/",
305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        "keylayout/",
315912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        "keychars/",
325912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown};
335912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
345912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatic const char* CONFIGURATION_FILE_EXTENSION[] = {
355912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ".idc",
365912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ".kl",
375912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ".kcm",
385912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown};
395912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
405912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatic bool isValidNameChar(char ch) {
415912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
425912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
435912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
445912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatic void appendInputDeviceConfigurationFileRelativePath(String8& path,
455912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        const String8& name, InputDeviceConfigurationFileType type) {
465912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    path.append(CONFIGURATION_FILE_DIR[type]);
475912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    for (size_t i = 0; i < name.length(); i++) {
485912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        char ch = name[i];
495912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (!isValidNameChar(ch)) {
505912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            ch = '_';
515912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
525912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        path.append(&ch, 1);
535912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
545912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    path.append(CONFIGURATION_FILE_EXTENSION[type]);
555912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
565912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
575912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownString8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
585912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        const InputDeviceIdentifier& deviceIdentifier,
595912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        InputDeviceConfigurationFileType type) {
605912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
615912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (deviceIdentifier.version != 0) {
625912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            // Try vendor product version.
635912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            String8 versionPath(getInputDeviceConfigurationFilePathByName(
645912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    String8::format("Vendor_%04x_Product_%04x_Version_%04x",
655912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                            deviceIdentifier.vendor, deviceIdentifier.product,
665912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                            deviceIdentifier.version),
675912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    type));
685912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (!versionPath.isEmpty()) {
695912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                return versionPath;
705912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
715912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
725912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
735912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        // Try vendor product.
745912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        String8 productPath(getInputDeviceConfigurationFilePathByName(
755912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                String8::format("Vendor_%04x_Product_%04x",
765912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        deviceIdentifier.vendor, deviceIdentifier.product),
775912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                type));
785912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (!productPath.isEmpty()) {
795912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            return productPath;
805912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
815912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
825912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
835912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    // Try device name.
845912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
855912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
865912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
875912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownString8 getInputDeviceConfigurationFilePathByName(
885912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        const String8& name, InputDeviceConfigurationFileType type) {
895912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    // Search system repository.
905912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    String8 path;
917ead73ed26403405bddd625c6ea0f009bff92939Jaekyun Seok
927ead73ed26403405bddd625c6ea0f009bff92939Jaekyun Seok    // Treblized input device config files will be located /odm/usr or /vendor/usr.
939e94788e8a8388eeb1113dc42c932ed42008de5dFrank Barchard    const char *rootsForPartition[] {"/odm", "/vendor", getenv("ANDROID_ROOT")};
947ead73ed26403405bddd625c6ea0f009bff92939Jaekyun Seok    for (size_t i = 0; i < size(rootsForPartition); i++) {
957ead73ed26403405bddd625c6ea0f009bff92939Jaekyun Seok        path.setTo(rootsForPartition[i]);
967ead73ed26403405bddd625c6ea0f009bff92939Jaekyun Seok        path.append("/usr/");
977ead73ed26403405bddd625c6ea0f009bff92939Jaekyun Seok        appendInputDeviceConfigurationFileRelativePath(path, name, type);
985912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PROBE
997ead73ed26403405bddd625c6ea0f009bff92939Jaekyun Seok        ALOGD("Probing for system provided input device configuration file: path='%s'",
1007ead73ed26403405bddd625c6ea0f009bff92939Jaekyun Seok              path.string());
1015912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
1027ead73ed26403405bddd625c6ea0f009bff92939Jaekyun Seok        if (!access(path.string(), R_OK)) {
1035912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PROBE
1047ead73ed26403405bddd625c6ea0f009bff92939Jaekyun Seok            ALOGD("Found");
1055912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
1067ead73ed26403405bddd625c6ea0f009bff92939Jaekyun Seok            return path;
1077ead73ed26403405bddd625c6ea0f009bff92939Jaekyun Seok        }
1085912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1095912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1105912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    // Search user repository.
1115912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    // TODO Should only look here if not in safe mode.
1125912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    path.setTo(getenv("ANDROID_DATA"));
1135912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    path.append("/system/devices/");
1145912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    appendInputDeviceConfigurationFileRelativePath(path, name, type);
1155912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PROBE
1165912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ALOGD("Probing for system user input device configuration file: path='%s'", path.string());
1175912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
1185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (!access(path.string(), R_OK)) {
1195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PROBE
1205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGD("Found");
1215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
1225912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return path;
1235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1245912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1255912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    // Not found.
1265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PROBE
1275912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
1285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            name.string(), type);
1295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
1305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return String8();
1315912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1325912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1335912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1345912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown// --- InputDeviceInfo ---
1355912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1365912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownInputDeviceInfo::InputDeviceInfo() {
137063ff53d0b0a0d670ea0185e687526d8fd302820Tim Kilbourn    initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false, false);
1385912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1395912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1405912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownInputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
1410415d63b1adf15f6546fea902c66f8bd508afbfcMichael Wright        mId(other.mId), mGeneration(other.mGeneration), mControllerNumber(other.mControllerNumber),
1420415d63b1adf15f6546fea902c66f8bd508afbfcMichael Wright        mIdentifier(other.mIdentifier), mAlias(other.mAlias), mIsExternal(other.mIsExternal),
143063ff53d0b0a0d670ea0185e687526d8fd302820Tim Kilbourn        mHasMic(other.mHasMic), mSources(other.mSources),
144063ff53d0b0a0d670ea0185e687526d8fd302820Tim Kilbourn        mKeyboardType(other.mKeyboardType), mKeyCharacterMap(other.mKeyCharacterMap),
145063ff53d0b0a0d670ea0185e687526d8fd302820Tim Kilbourn        mHasVibrator(other.mHasVibrator), mHasButtonUnderPad(other.mHasButtonUnderPad),
146063ff53d0b0a0d670ea0185e687526d8fd302820Tim Kilbourn        mMotionRanges(other.mMotionRanges) {
1475912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1485912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1495912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownInputDeviceInfo::~InputDeviceInfo() {
1505912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1515912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1520415d63b1adf15f6546fea902c66f8bd508afbfcMichael Wrightvoid InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
153063ff53d0b0a0d670ea0185e687526d8fd302820Tim Kilbourn        const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal,
154063ff53d0b0a0d670ea0185e687526d8fd302820Tim Kilbourn        bool hasMic) {
1555912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mId = id;
1565912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mGeneration = generation;
1570415d63b1adf15f6546fea902c66f8bd508afbfcMichael Wright    mControllerNumber = controllerNumber;
1585912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mIdentifier = identifier;
1595912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mAlias = alias;
1605912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mIsExternal = isExternal;
161063ff53d0b0a0d670ea0185e687526d8fd302820Tim Kilbourn    mHasMic = hasMic;
1625912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mSources = 0;
1635912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
1645912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mHasVibrator = false;
165931fd6dee7891e94650353c09956ccf24b4dfff3Michael Wright    mHasButtonUnderPad = false;
1665912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mMotionRanges.clear();
1675912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1685912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1695912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownconst InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
1705912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        int32_t axis, uint32_t source) const {
1715912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    size_t numRanges = mMotionRanges.size();
1725912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    for (size_t i = 0; i < numRanges; i++) {
1735912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        const MotionRange& range = mMotionRanges.itemAt(i);
1745912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (range.axis == axis && range.source == source) {
1755912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            return &range;
1765912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
1775912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1785912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return NULL;
1795912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1805912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1815912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownvoid InputDeviceInfo::addSource(uint32_t source) {
1825912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mSources |= source;
1835912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1845912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1855912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownvoid InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
1865912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        float flat, float fuzz, float resolution) {
1875912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    MotionRange range = { axis, source, min, max, flat, fuzz, resolution };
1885912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mMotionRanges.add(range);
1895912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1905912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1915912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownvoid InputDeviceInfo::addMotionRange(const MotionRange& range) {
1925912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mMotionRanges.add(range);
1935912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1945912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1955912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown} // namespace android
196