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
isValidNameChar(char ch)43 static bool isValidNameChar(char ch) {
44 return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
45 }
46
appendInputDeviceConfigurationFileRelativePath(std::string & path,const std::string & name,InputDeviceConfigurationFileType type)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
getInputDeviceConfigurationFilePathByDeviceIdentifier(const InputDeviceIdentifier & deviceIdentifier,InputDeviceConfigurationFileType type)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
getInputDeviceConfigurationFilePathByName(const std::string & name,InputDeviceConfigurationFileType type)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
getCanonicalName() const139 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
InputDeviceInfo()152 InputDeviceInfo::InputDeviceInfo() {
153 initialize(-1, 0, -1, InputDeviceIdentifier(), "", false, false);
154 }
155
InputDeviceInfo(const InputDeviceInfo & other)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
~InputDeviceInfo()165 InputDeviceInfo::~InputDeviceInfo() {
166 }
167
initialize(int32_t id,int32_t generation,int32_t controllerNumber,const InputDeviceIdentifier & identifier,const std::string & alias,bool isExternal,bool hasMic)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
getMotionRange(int32_t axis,uint32_t source) const185 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
addSource(uint32_t source)197 void InputDeviceInfo::addSource(uint32_t source) {
198 mSources |= source;
199 }
200
addMotionRange(int32_t axis,uint32_t source,float min,float max,float flat,float fuzz,float resolution)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
addMotionRange(const MotionRange & range)207 void InputDeviceInfo::addMotionRange(const MotionRange& range) {
208 mMotionRanges.push_back(range);
209 }
210
211 } // namespace android
212