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 <android-base/stringprintf.h> 24 #include <input/InputDevice.h> 25 #include <input/InputEventLabels.h> 26 27 using android::base::StringPrintf; 28 29 namespace android { 30 31 static const char* CONFIGURATION_FILE_DIR[] = { 32 "idc/", 33 "keylayout/", 34 "keychars/", 35 }; 36 37 static const char* CONFIGURATION_FILE_EXTENSION[] = { 38 ".idc", 39 ".kl", 40 ".kcm", 41 }; 42 43 static bool isValidNameChar(char ch) { 44 return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_'); 45 } 46 47 static void appendInputDeviceConfigurationFileRelativePath(std::string& path, 48 const std::string& name, InputDeviceConfigurationFileType type) { 49 path += CONFIGURATION_FILE_DIR[type]; 50 path += name; 51 path += CONFIGURATION_FILE_EXTENSION[type]; 52 } 53 54 std::string getInputDeviceConfigurationFilePathByDeviceIdentifier( 55 const InputDeviceIdentifier& deviceIdentifier, 56 InputDeviceConfigurationFileType type) { 57 if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) { 58 if (deviceIdentifier.version != 0) { 59 // Try vendor product version. 60 std::string versionPath = getInputDeviceConfigurationFilePathByName( 61 StringPrintf("Vendor_%04x_Product_%04x_Version_%04x", 62 deviceIdentifier.vendor, deviceIdentifier.product, 63 deviceIdentifier.version), 64 type); 65 if (!versionPath.empty()) { 66 return versionPath; 67 } 68 } 69 70 // Try vendor product. 71 std::string productPath = getInputDeviceConfigurationFilePathByName( 72 StringPrintf("Vendor_%04x_Product_%04x", 73 deviceIdentifier.vendor, deviceIdentifier.product), 74 type); 75 if (!productPath.empty()) { 76 return productPath; 77 } 78 } 79 80 // Try device name. 81 return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName(), type); 82 } 83 84 std::string getInputDeviceConfigurationFilePathByName( 85 const std::string& name, InputDeviceConfigurationFileType type) { 86 // Search system repository. 87 std::string path; 88 89 // Treblized input device config files will be located /odm/usr or /vendor/usr. 90 const char *rootsForPartition[] {"/odm", "/vendor", getenv("ANDROID_ROOT")}; 91 for (size_t i = 0; i < size(rootsForPartition); i++) { 92 if (rootsForPartition[i] == nullptr) { 93 continue; 94 } 95 path = rootsForPartition[i]; 96 path += "/usr/"; 97 appendInputDeviceConfigurationFileRelativePath(path, name, type); 98 #if DEBUG_PROBE 99 ALOGD("Probing for system provided input device configuration file: path='%s'", 100 path.c_str()); 101 #endif 102 if (!access(path.c_str(), R_OK)) { 103 #if DEBUG_PROBE 104 ALOGD("Found"); 105 #endif 106 return path; 107 } 108 } 109 110 // Search user repository. 111 // TODO Should only look here if not in safe mode. 112 path = ""; 113 char *androidData = getenv("ANDROID_DATA"); 114 if (androidData != nullptr) { 115 path += androidData; 116 } 117 path += "/system/devices/"; 118 appendInputDeviceConfigurationFileRelativePath(path, name, type); 119 #if DEBUG_PROBE 120 ALOGD("Probing for system user input device configuration file: path='%s'", path.c_str()); 121 #endif 122 if (!access(path.c_str(), R_OK)) { 123 #if DEBUG_PROBE 124 ALOGD("Found"); 125 #endif 126 return path; 127 } 128 129 // Not found. 130 #if DEBUG_PROBE 131 ALOGD("Probe failed to find input device configuration file: name='%s', type=%d", 132 name.c_str(), type); 133 #endif 134 return ""; 135 } 136 137 // --- InputDeviceIdentifier 138 139 std::string InputDeviceIdentifier::getCanonicalName() const { 140 std::string replacedName = name; 141 for (char& ch : replacedName) { 142 if (!isValidNameChar(ch)) { 143 ch = '_'; 144 } 145 } 146 return replacedName; 147 } 148 149 150 // --- InputDeviceInfo --- 151 152 InputDeviceInfo::InputDeviceInfo() { 153 initialize(-1, 0, -1, InputDeviceIdentifier(), "", false, false); 154 } 155 156 InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) : 157 mId(other.mId), mGeneration(other.mGeneration), mControllerNumber(other.mControllerNumber), 158 mIdentifier(other.mIdentifier), mAlias(other.mAlias), mIsExternal(other.mIsExternal), 159 mHasMic(other.mHasMic), mSources(other.mSources), 160 mKeyboardType(other.mKeyboardType), mKeyCharacterMap(other.mKeyCharacterMap), 161 mHasVibrator(other.mHasVibrator), mHasButtonUnderPad(other.mHasButtonUnderPad), 162 mMotionRanges(other.mMotionRanges) { 163 } 164 165 InputDeviceInfo::~InputDeviceInfo() { 166 } 167 168 void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber, 169 const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal, 170 bool hasMic) { 171 mId = id; 172 mGeneration = generation; 173 mControllerNumber = controllerNumber; 174 mIdentifier = identifier; 175 mAlias = alias; 176 mIsExternal = isExternal; 177 mHasMic = hasMic; 178 mSources = 0; 179 mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; 180 mHasVibrator = false; 181 mHasButtonUnderPad = false; 182 mMotionRanges.clear(); 183 } 184 185 const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange( 186 int32_t axis, uint32_t source) const { 187 size_t numRanges = mMotionRanges.size(); 188 for (size_t i = 0; i < numRanges; i++) { 189 const MotionRange& range = mMotionRanges[i]; 190 if (range.axis == axis && range.source == source) { 191 return ⦥ 192 } 193 } 194 return nullptr; 195 } 196 197 void InputDeviceInfo::addSource(uint32_t source) { 198 mSources |= source; 199 } 200 201 void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max, 202 float flat, float fuzz, float resolution) { 203 MotionRange range = { axis, source, min, max, flat, fuzz, resolution }; 204 mMotionRanges.push_back(range); 205 } 206 207 void InputDeviceInfo::addMotionRange(const MotionRange& range) { 208 mMotionRanges.push_back(range); 209 } 210 211 } // namespace android 212