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, 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 mHasMic(other.mHasMic), mSources(other.mSources), 137 mKeyboardType(other.mKeyboardType), mKeyCharacterMap(other.mKeyCharacterMap), 138 mHasVibrator(other.mHasVibrator), mHasButtonUnderPad(other.mHasButtonUnderPad), 139 mMotionRanges(other.mMotionRanges) { 140 } 141 142 InputDeviceInfo::~InputDeviceInfo() { 143 } 144 145 void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber, 146 const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal, 147 bool hasMic) { 148 mId = id; 149 mGeneration = generation; 150 mControllerNumber = controllerNumber; 151 mIdentifier = identifier; 152 mAlias = alias; 153 mIsExternal = isExternal; 154 mHasMic = hasMic; 155 mSources = 0; 156 mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; 157 mHasVibrator = false; 158 mHasButtonUnderPad = false; 159 mMotionRanges.clear(); 160 } 161 162 const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange( 163 int32_t axis, uint32_t source) const { 164 size_t numRanges = mMotionRanges.size(); 165 for (size_t i = 0; i < numRanges; i++) { 166 const MotionRange& range = mMotionRanges.itemAt(i); 167 if (range.axis == axis && range.source == source) { 168 return ⦥ 169 } 170 } 171 return NULL; 172 } 173 174 void InputDeviceInfo::addSource(uint32_t source) { 175 mSources |= source; 176 } 177 178 void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max, 179 float flat, float fuzz, float resolution) { 180 MotionRange range = { axis, source, min, max, flat, fuzz, resolution }; 181 mMotionRanges.add(range); 182 } 183 184 void InputDeviceInfo::addMotionRange(const MotionRange& range) { 185 mMotionRanges.add(range); 186 } 187 188 } // namespace android 189