Home | History | Annotate | Download | only in input
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "InputDevice"
     18 
     19 #include <stdlib.h>
     20 #include <unistd.h>
     21 #include <ctype.h>
     22 
     23 #include <input/InputDevice.h>
     24 
     25 namespace android {
     26 
     27 static const char* CONFIGURATION_FILE_DIR[] = {
     28         "idc/",
     29         "keylayout/",
     30         "keychars/",
     31 };
     32 
     33 static const char* CONFIGURATION_FILE_EXTENSION[] = {
     34         ".idc",
     35         ".kl",
     36         ".kcm",
     37 };
     38 
     39 static bool isValidNameChar(char ch) {
     40     return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
     41 }
     42 
     43 static void appendInputDeviceConfigurationFileRelativePath(String8& path,
     44         const String8& name, InputDeviceConfigurationFileType type) {
     45     path.append(CONFIGURATION_FILE_DIR[type]);
     46     for (size_t i = 0; i < name.length(); i++) {
     47         char ch = name[i];
     48         if (!isValidNameChar(ch)) {
     49             ch = '_';
     50         }
     51         path.append(&ch, 1);
     52     }
     53     path.append(CONFIGURATION_FILE_EXTENSION[type]);
     54 }
     55 
     56 String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
     57         const InputDeviceIdentifier& deviceIdentifier,
     58         InputDeviceConfigurationFileType type) {
     59     if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
     60         if (deviceIdentifier.version != 0) {
     61             // Try vendor product version.
     62             String8 versionPath(getInputDeviceConfigurationFilePathByName(
     63                     String8::format("Vendor_%04x_Product_%04x_Version_%04x",
     64                             deviceIdentifier.vendor, deviceIdentifier.product,
     65                             deviceIdentifier.version),
     66                     type));
     67             if (!versionPath.isEmpty()) {
     68                 return versionPath;
     69             }
     70         }
     71 
     72         // Try vendor product.
     73         String8 productPath(getInputDeviceConfigurationFilePathByName(
     74                 String8::format("Vendor_%04x_Product_%04x",
     75                         deviceIdentifier.vendor, deviceIdentifier.product),
     76                 type));
     77         if (!productPath.isEmpty()) {
     78             return productPath;
     79         }
     80     }
     81 
     82     // Try device name.
     83     return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
     84 }
     85 
     86 String8 getInputDeviceConfigurationFilePathByName(
     87         const String8& name, InputDeviceConfigurationFileType type) {
     88     // Search system repository.
     89     String8 path;
     90     path.setTo(getenv("ANDROID_ROOT"));
     91     path.append("/usr/");
     92     appendInputDeviceConfigurationFileRelativePath(path, name, type);
     93 #if DEBUG_PROBE
     94     ALOGD("Probing for system provided input device configuration file: path='%s'", path.string());
     95 #endif
     96     if (!access(path.string(), R_OK)) {
     97 #if DEBUG_PROBE
     98         ALOGD("Found");
     99 #endif
    100         return path;
    101     }
    102 
    103     // Search user repository.
    104     // TODO Should only look here if not in safe mode.
    105     path.setTo(getenv("ANDROID_DATA"));
    106     path.append("/system/devices/");
    107     appendInputDeviceConfigurationFileRelativePath(path, name, type);
    108 #if DEBUG_PROBE
    109     ALOGD("Probing for system user input device configuration file: path='%s'", path.string());
    110 #endif
    111     if (!access(path.string(), R_OK)) {
    112 #if DEBUG_PROBE
    113         ALOGD("Found");
    114 #endif
    115         return path;
    116     }
    117 
    118     // Not found.
    119 #if DEBUG_PROBE
    120     ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
    121             name.string(), type);
    122 #endif
    123     return String8();
    124 }
    125 
    126 
    127 // --- InputDeviceInfo ---
    128 
    129 InputDeviceInfo::InputDeviceInfo() {
    130     initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false);
    131 }
    132 
    133 InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
    134         mId(other.mId), mGeneration(other.mGeneration), mControllerNumber(other.mControllerNumber),
    135         mIdentifier(other.mIdentifier), mAlias(other.mAlias), mIsExternal(other.mIsExternal),
    136         mSources(other.mSources), mKeyboardType(other.mKeyboardType),
    137         mKeyCharacterMap(other.mKeyCharacterMap), mHasVibrator(other.mHasVibrator),
    138         mHasButtonUnderPad(other.mHasButtonUnderPad), mMotionRanges(other.mMotionRanges) {
    139 }
    140 
    141 InputDeviceInfo::~InputDeviceInfo() {
    142 }
    143 
    144 void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
    145         const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal) {
    146     mId = id;
    147     mGeneration = generation;
    148     mControllerNumber = controllerNumber;
    149     mIdentifier = identifier;
    150     mAlias = alias;
    151     mIsExternal = isExternal;
    152     mSources = 0;
    153     mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
    154     mHasVibrator = false;
    155     mHasButtonUnderPad = false;
    156     mMotionRanges.clear();
    157 }
    158 
    159 const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
    160         int32_t axis, uint32_t source) const {
    161     size_t numRanges = mMotionRanges.size();
    162     for (size_t i = 0; i < numRanges; i++) {
    163         const MotionRange& range = mMotionRanges.itemAt(i);
    164         if (range.axis == axis && range.source == source) {
    165             return &range;
    166         }
    167     }
    168     return NULL;
    169 }
    170 
    171 void InputDeviceInfo::addSource(uint32_t source) {
    172     mSources |= source;
    173 }
    174 
    175 void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
    176         float flat, float fuzz, float resolution) {
    177     MotionRange range = { axis, source, min, max, flat, fuzz, resolution };
    178     mMotionRanges.add(range);
    179 }
    180 
    181 void InputDeviceInfo::addMotionRange(const MotionRange& range) {
    182     mMotionRanges.add(range);
    183 }
    184 
    185 } // namespace android
    186