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 ⦥ 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