michael@0: /* michael@0: * Copyright (C) 2012 The Android Open Source Project michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: michael@0: #define LOG_TAG "InputDevice" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "InputDevice.h" michael@0: michael@0: namespace android { michael@0: michael@0: static const char* CONFIGURATION_FILE_DIR[] = { michael@0: "idc/", michael@0: "keylayout/", michael@0: "keychars/", michael@0: }; michael@0: michael@0: static const char* CONFIGURATION_FILE_EXTENSION[] = { michael@0: ".idc", michael@0: ".kl", michael@0: ".kcm", michael@0: }; michael@0: michael@0: static bool isValidNameChar(char ch) { michael@0: return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_'); michael@0: } michael@0: michael@0: static void appendInputDeviceConfigurationFileRelativePath(String8& path, michael@0: const String8& name, InputDeviceConfigurationFileType type) { michael@0: path.append(CONFIGURATION_FILE_DIR[type]); michael@0: for (size_t i = 0; i < name.length(); i++) { michael@0: char ch = name[i]; michael@0: if (!isValidNameChar(ch)) { michael@0: ch = '_'; michael@0: } michael@0: path.append(&ch, 1); michael@0: } michael@0: path.append(CONFIGURATION_FILE_EXTENSION[type]); michael@0: } michael@0: michael@0: String8 getInputDeviceConfigurationFilePathByDeviceIdentifier( michael@0: const InputDeviceIdentifier& deviceIdentifier, michael@0: InputDeviceConfigurationFileType type) { michael@0: if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) { michael@0: if (deviceIdentifier.version != 0) { michael@0: // Try vendor product version. michael@0: String8 versionPath(getInputDeviceConfigurationFilePathByName( michael@0: String8::format("Vendor_%04x_Product_%04x_Version_%04x", michael@0: deviceIdentifier.vendor, deviceIdentifier.product, michael@0: deviceIdentifier.version), michael@0: type)); michael@0: if (!versionPath.isEmpty()) { michael@0: return versionPath; michael@0: } michael@0: } michael@0: michael@0: // Try vendor product. michael@0: String8 productPath(getInputDeviceConfigurationFilePathByName( michael@0: String8::format("Vendor_%04x_Product_%04x", michael@0: deviceIdentifier.vendor, deviceIdentifier.product), michael@0: type)); michael@0: if (!productPath.isEmpty()) { michael@0: return productPath; michael@0: } michael@0: } michael@0: michael@0: // Try device name. michael@0: return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type); michael@0: } michael@0: michael@0: String8 getInputDeviceConfigurationFilePathByName( michael@0: const String8& name, InputDeviceConfigurationFileType type) { michael@0: // Search system repository. michael@0: String8 path; michael@0: path.setTo(getenv("ANDROID_ROOT")); michael@0: path.append("/usr/"); michael@0: appendInputDeviceConfigurationFileRelativePath(path, name, type); michael@0: #if DEBUG_PROBE michael@0: ALOGD("Probing for system provided input device configuration file: path='%s'", path.string()); michael@0: #endif michael@0: if (!access(path.string(), R_OK)) { michael@0: #if DEBUG_PROBE michael@0: ALOGD("Found"); michael@0: #endif michael@0: return path; michael@0: } michael@0: michael@0: // Search user repository. michael@0: // TODO Should only look here if not in safe mode. michael@0: path.setTo(getenv("ANDROID_DATA")); michael@0: path.append("/system/devices/"); michael@0: appendInputDeviceConfigurationFileRelativePath(path, name, type); michael@0: #if DEBUG_PROBE michael@0: ALOGD("Probing for system user input device configuration file: path='%s'", path.string()); michael@0: #endif michael@0: if (!access(path.string(), R_OK)) { michael@0: #if DEBUG_PROBE michael@0: ALOGD("Found"); michael@0: #endif michael@0: return path; michael@0: } michael@0: michael@0: // Not found. michael@0: #if DEBUG_PROBE michael@0: ALOGD("Probe failed to find input device configuration file: name='%s', type=%d", michael@0: name.string(), type); michael@0: #endif michael@0: return String8(); michael@0: } michael@0: michael@0: michael@0: // --- InputDeviceInfo --- michael@0: michael@0: InputDeviceInfo::InputDeviceInfo() { michael@0: initialize(-1, -1, InputDeviceIdentifier(), String8(), false); michael@0: } michael@0: michael@0: InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) : michael@0: mId(other.mId), mGeneration(other.mGeneration), mIdentifier(other.mIdentifier), michael@0: mAlias(other.mAlias), mIsExternal(other.mIsExternal), mSources(other.mSources), michael@0: mKeyboardType(other.mKeyboardType), michael@0: mKeyCharacterMap(other.mKeyCharacterMap), michael@0: mHasVibrator(other.mHasVibrator), michael@0: mMotionRanges(other.mMotionRanges) { michael@0: } michael@0: michael@0: InputDeviceInfo::~InputDeviceInfo() { michael@0: } michael@0: michael@0: void InputDeviceInfo::initialize(int32_t id, int32_t generation, michael@0: const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal) { michael@0: mId = id; michael@0: mGeneration = generation; michael@0: mIdentifier = identifier; michael@0: mAlias = alias; michael@0: mIsExternal = isExternal; michael@0: mSources = 0; michael@0: mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; michael@0: mHasVibrator = false; michael@0: mMotionRanges.clear(); michael@0: } michael@0: michael@0: const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange( michael@0: int32_t axis, uint32_t source) const { michael@0: size_t numRanges = mMotionRanges.size(); michael@0: for (size_t i = 0; i < numRanges; i++) { michael@0: const MotionRange& range = mMotionRanges.itemAt(i); michael@0: if (range.axis == axis && range.source == source) { michael@0: return ⦥ michael@0: } michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: void InputDeviceInfo::addSource(uint32_t source) { michael@0: mSources |= source; michael@0: } michael@0: michael@0: void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max, michael@0: float flat, float fuzz, float resolution) { michael@0: MotionRange range = { axis, source, min, max, flat, fuzz, resolution }; michael@0: mMotionRanges.add(range); michael@0: } michael@0: michael@0: void InputDeviceInfo::addMotionRange(const MotionRange& range) { michael@0: mMotionRanges.add(range); michael@0: } michael@0: michael@0: } // namespace android