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