blob: 31aed517dd3fe53803ee67d5889bc0f52f0a289d [file] [log] [blame]
Jeff Brown5912f952013-07-01 19:10:31 -07001/*
2 * Copyright (C) 2008 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 "KeyLayoutMap"
18
Jeff Brown5912f952013-07-01 19:10:31 -070019#include <android/keycodes.h>
Dominik Laskowski75788452021-02-09 18:51:25 -080020#include <ftl/enum.h>
Michael Wright872db4f2014-04-22 15:03:51 -070021#include <input/InputEventLabels.h>
Jeff Brown5912f952013-07-01 19:10:31 -070022#include <input/KeyLayoutMap.h>
Chris Yef59a2f42020-10-16 12:55:26 -070023#include <input/Keyboard.h>
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -070024#include <log/log.h>
Jeff Brown5912f952013-07-01 19:10:31 -070025#include <utils/Errors.h>
Jeff Brown5912f952013-07-01 19:10:31 -070026#include <utils/Timers.h>
Chris Yef59a2f42020-10-16 12:55:26 -070027#include <utils/Tokenizer.h>
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -070028#include <vintf/RuntimeInfo.h>
29#include <vintf/VintfObject.h>
Jeff Brown5912f952013-07-01 19:10:31 -070030
Dominik Laskowski75788452021-02-09 18:51:25 -080031#include <cstdlib>
32#include <string_view>
33#include <unordered_map>
34
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -070035/**
36 * Log debug output for the parser.
37 * Enable this via "adb shell setprop log.tag.KeyLayoutMapParser DEBUG" (requires restart)
38 */
39const bool DEBUG_PARSER =
40 __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Parser", ANDROID_LOG_INFO);
Jeff Brown5912f952013-07-01 19:10:31 -070041
42// Enables debug output for parser performance.
43#define DEBUG_PARSER_PERFORMANCE 0
44
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -070045/**
46 * Log debug output for mapping.
47 * Enable this via "adb shell setprop log.tag.KeyLayoutMapMapping DEBUG" (requires restart)
48 */
49const bool DEBUG_MAPPING =
50 __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Mapping", ANDROID_LOG_INFO);
Jeff Brown5912f952013-07-01 19:10:31 -070051
52namespace android {
Dominik Laskowski75788452021-02-09 18:51:25 -080053namespace {
Jeff Brown5912f952013-07-01 19:10:31 -070054
Dominik Laskowski75788452021-02-09 18:51:25 -080055constexpr const char* WHITESPACE = " \t\r";
Jeff Brown5912f952013-07-01 19:10:31 -070056
Dominik Laskowski75788452021-02-09 18:51:25 -080057template <InputDeviceSensorType S>
58constexpr auto sensorPair() {
59 return std::make_pair(ftl::enum_name<S>(), S);
Jeff Brown5912f952013-07-01 19:10:31 -070060}
61
Dominik Laskowski75788452021-02-09 18:51:25 -080062static const std::unordered_map<std::string_view, InputDeviceSensorType> SENSOR_LIST =
63 {sensorPair<InputDeviceSensorType::ACCELEROMETER>(),
64 sensorPair<InputDeviceSensorType::MAGNETIC_FIELD>(),
65 sensorPair<InputDeviceSensorType::ORIENTATION>(),
66 sensorPair<InputDeviceSensorType::GYROSCOPE>(),
67 sensorPair<InputDeviceSensorType::LIGHT>(),
68 sensorPair<InputDeviceSensorType::PRESSURE>(),
69 sensorPair<InputDeviceSensorType::TEMPERATURE>(),
70 sensorPair<InputDeviceSensorType::PROXIMITY>(),
71 sensorPair<InputDeviceSensorType::GRAVITY>(),
72 sensorPair<InputDeviceSensorType::LINEAR_ACCELERATION>(),
73 sensorPair<InputDeviceSensorType::ROTATION_VECTOR>(),
74 sensorPair<InputDeviceSensorType::RELATIVE_HUMIDITY>(),
75 sensorPair<InputDeviceSensorType::AMBIENT_TEMPERATURE>(),
76 sensorPair<InputDeviceSensorType::MAGNETIC_FIELD_UNCALIBRATED>(),
77 sensorPair<InputDeviceSensorType::GAME_ROTATION_VECTOR>(),
78 sensorPair<InputDeviceSensorType::GYROSCOPE_UNCALIBRATED>(),
79 sensorPair<InputDeviceSensorType::SIGNIFICANT_MOTION>()};
80
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -070081bool kernelConfigsArePresent(const std::set<std::string>& configs) {
82 std::shared_ptr<const android::vintf::RuntimeInfo> runtimeInfo =
83 android::vintf::VintfObject::GetInstance()->getRuntimeInfo(
84 vintf::RuntimeInfo::FetchFlag::CONFIG_GZ);
85 LOG_ALWAYS_FATAL_IF(runtimeInfo == nullptr, "Kernel configs could not be fetched");
86
87 const std::map<std::string, std::string>& kernelConfigs = runtimeInfo->kernelConfigs();
88 for (const std::string& requiredConfig : configs) {
89 const auto configIt = kernelConfigs.find(requiredConfig);
90 if (configIt == kernelConfigs.end()) {
91 ALOGI("Required kernel config %s is not found", requiredConfig.c_str());
92 return false;
93 }
94 const std::string& option = configIt->second;
95 if (option != "y" && option != "m") {
96 ALOGI("Required kernel config %s has option %s", requiredConfig.c_str(),
97 option.c_str());
98 return false;
99 }
100 }
101 return true;
102}
103
Dominik Laskowski75788452021-02-09 18:51:25 -0800104} // namespace
105
106KeyLayoutMap::KeyLayoutMap() = default;
107KeyLayoutMap::~KeyLayoutMap() = default;
Jeff Brown5912f952013-07-01 19:10:31 -0700108
Chris Ye1abffbd2020-08-18 12:50:12 -0700109base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::loadContents(const std::string& filename,
110 const char* contents) {
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700111 return load(filename, contents);
Chris Ye1abffbd2020-08-18 12:50:12 -0700112}
Jeff Brown5912f952013-07-01 19:10:31 -0700113
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700114base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::load(const std::string& filename,
115 const char* contents) {
Jeff Brown5912f952013-07-01 19:10:31 -0700116 Tokenizer* tokenizer;
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700117 status_t status;
118 if (contents == nullptr) {
119 status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
120 } else {
121 status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
122 }
Jeff Brown5912f952013-07-01 19:10:31 -0700123 if (status) {
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100124 ALOGE("Error %d opening key layout map file %s.", status, filename.c_str());
Chris Ye1abffbd2020-08-18 12:50:12 -0700125 return Errorf("Error {} opening key layout map file {}.", status, filename.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700126 }
Chris Ye1abffbd2020-08-18 12:50:12 -0700127 std::unique_ptr<Tokenizer> t(tokenizer);
128 auto ret = load(t.get());
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700129 if (!ret.ok()) {
130 return ret;
Chris Ye1abffbd2020-08-18 12:50:12 -0700131 }
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700132 const std::shared_ptr<KeyLayoutMap>& map = *ret;
133 LOG_ALWAYS_FATAL_IF(map == nullptr, "Returned map should not be null if there's no error");
134 if (!kernelConfigsArePresent(map->mRequiredKernelConfigs)) {
135 ALOGI("Not loading %s because the required kernel configs are not set", filename.c_str());
136 return Errorf("Missing kernel config");
137 }
138 map->mLoadFileName = filename;
Chris Ye1abffbd2020-08-18 12:50:12 -0700139 return ret;
140}
141
142base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::load(Tokenizer* tokenizer) {
143 std::shared_ptr<KeyLayoutMap> map = std::shared_ptr<KeyLayoutMap>(new KeyLayoutMap());
144 status_t status = OK;
145 if (!map.get()) {
146 ALOGE("Error allocating key layout map.");
147 return Errorf("Error allocating key layout map.");
148 } else {
149#if DEBUG_PARSER_PERFORMANCE
150 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
151#endif
152 Parser parser(map.get(), tokenizer);
153 status = parser.parse();
154#if DEBUG_PARSER_PERFORMANCE
155 nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
156 ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.",
157 tokenizer->getFilename().string(), tokenizer->getLineNumber(),
158 elapsedTime / 1000000.0);
159#endif
160 if (!status) {
161 return std::move(map);
162 }
163 }
164 return Errorf("Load KeyLayoutMap failed {}.", status);
Jeff Brown5912f952013-07-01 19:10:31 -0700165}
166
167status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t usageCode,
168 int32_t* outKeyCode, uint32_t* outFlags) const {
169 const Key* key = getKey(scanCode, usageCode);
170 if (!key) {
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700171 ALOGD_IF(DEBUG_MAPPING, "mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode,
172 usageCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700173 *outKeyCode = AKEYCODE_UNKNOWN;
174 *outFlags = 0;
175 return NAME_NOT_FOUND;
176 }
177
178 *outKeyCode = key->keyCode;
179 *outFlags = key->flags;
180
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700181 ALOGD_IF(DEBUG_MAPPING,
182 "mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.",
183 scanCode, usageCode, *outKeyCode, *outFlags);
Jeff Brown5912f952013-07-01 19:10:31 -0700184 return NO_ERROR;
185}
186
Chris Yef59a2f42020-10-16 12:55:26 -0700187// Return pair of sensor type and sensor data index, for the input device abs code
Prabir Pradhanae4ff282022-08-23 16:21:39 +0000188base::Result<std::pair<InputDeviceSensorType, int32_t>> KeyLayoutMap::mapSensor(
189 int32_t absCode) const {
Chris Yef59a2f42020-10-16 12:55:26 -0700190 auto it = mSensorsByAbsCode.find(absCode);
191 if (it == mSensorsByAbsCode.end()) {
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700192 ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, ~ Failed.", absCode);
Chris Yef59a2f42020-10-16 12:55:26 -0700193 return Errorf("Can't find abs code {}.", absCode);
194 }
195 const Sensor& sensor = it->second;
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700196 ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, sensorType=%s, sensorDataIndex=0x%x.", absCode,
197 ftl::enum_string(sensor.sensorType).c_str(), sensor.sensorDataIndex);
Chris Yef59a2f42020-10-16 12:55:26 -0700198 return std::make_pair(sensor.sensorType, sensor.sensorDataIndex);
199}
200
Jeff Brown5912f952013-07-01 19:10:31 -0700201const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const {
202 if (usageCode) {
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700203 auto it = mKeysByUsageCode.find(usageCode);
204 if (it != mKeysByUsageCode.end()) {
205 return &it->second;
Jeff Brown5912f952013-07-01 19:10:31 -0700206 }
207 }
208 if (scanCode) {
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700209 auto it = mKeysByScanCode.find(scanCode);
210 if (it != mKeysByScanCode.end()) {
211 return &it->second;
Jeff Brown5912f952013-07-01 19:10:31 -0700212 }
213 }
Yi Kong5bed83b2018-07-17 12:53:47 -0700214 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700215}
216
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700217std::vector<int32_t> KeyLayoutMap::findScanCodesForKey(int32_t keyCode) const {
218 std::vector<int32_t> scanCodes;
219 for (const auto& [scanCode, key] : mKeysByScanCode) {
220 if (keyCode == key.keyCode) {
221 scanCodes.push_back(scanCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700222 }
223 }
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700224 return scanCodes;
Jeff Brown5912f952013-07-01 19:10:31 -0700225}
226
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700227std::optional<AxisInfo> KeyLayoutMap::mapAxis(int32_t scanCode) const {
228 auto it = mAxes.find(scanCode);
229 if (it == mAxes.end()) {
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700230 ALOGD_IF(DEBUG_MAPPING, "mapAxis: scanCode=%d ~ Failed.", scanCode);
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700231 return std::nullopt;
Jeff Brown5912f952013-07-01 19:10:31 -0700232 }
233
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700234 const AxisInfo& axisInfo = it->second;
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700235 ALOGD_IF(DEBUG_MAPPING,
236 "mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
237 "splitValue=%d, flatOverride=%d.",
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700238 scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue,
239 axisInfo.flatOverride);
240 return axisInfo;
Jeff Brown5912f952013-07-01 19:10:31 -0700241}
242
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700243std::optional<int32_t> KeyLayoutMap::findScanCodeForLed(int32_t ledCode) const {
244 for (const auto& [scanCode, led] : mLedsByScanCode) {
245 if (led.ledCode == ledCode) {
246 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d, scanCode=%d.", __func__, ledCode, scanCode);
247 return scanCode;
Michael Wright74bdd2e2013-10-17 17:35:53 -0700248 }
249 }
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700250 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d ~ Not found.", __func__, ledCode);
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700251 return std::nullopt;
Michael Wright74bdd2e2013-10-17 17:35:53 -0700252}
253
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700254std::optional<int32_t> KeyLayoutMap::findUsageCodeForLed(int32_t ledCode) const {
255 for (const auto& [usageCode, led] : mLedsByUsageCode) {
256 if (led.ledCode == ledCode) {
257 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d, usage=%x.", __func__, ledCode, usageCode);
258 return usageCode;
259 }
260 }
261 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d ~ Not found.", __func__, ledCode);
262 return std::nullopt;
263}
Jeff Brown5912f952013-07-01 19:10:31 -0700264
265// --- KeyLayoutMap::Parser ---
266
267KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
268 mMap(map), mTokenizer(tokenizer) {
269}
270
271KeyLayoutMap::Parser::~Parser() {
272}
273
274status_t KeyLayoutMap::Parser::parse() {
275 while (!mTokenizer->isEof()) {
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700276 ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().string(),
277 mTokenizer->peekRemainderOfLine().string());
Jeff Brown5912f952013-07-01 19:10:31 -0700278
279 mTokenizer->skipDelimiters(WHITESPACE);
280
281 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
282 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
283 if (keywordToken == "key") {
284 mTokenizer->skipDelimiters(WHITESPACE);
285 status_t status = parseKey();
286 if (status) return status;
287 } else if (keywordToken == "axis") {
288 mTokenizer->skipDelimiters(WHITESPACE);
289 status_t status = parseAxis();
290 if (status) return status;
Michael Wright74bdd2e2013-10-17 17:35:53 -0700291 } else if (keywordToken == "led") {
292 mTokenizer->skipDelimiters(WHITESPACE);
293 status_t status = parseLed();
294 if (status) return status;
Chris Yef59a2f42020-10-16 12:55:26 -0700295 } else if (keywordToken == "sensor") {
296 mTokenizer->skipDelimiters(WHITESPACE);
297 status_t status = parseSensor();
298 if (status) return status;
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700299 } else if (keywordToken == "requires_kernel_config") {
300 mTokenizer->skipDelimiters(WHITESPACE);
301 status_t status = parseRequiredKernelConfig();
302 if (status) return status;
Jeff Brown5912f952013-07-01 19:10:31 -0700303 } else {
304 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
305 keywordToken.string());
306 return BAD_VALUE;
307 }
308
309 mTokenizer->skipDelimiters(WHITESPACE);
310 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
311 ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
312 mTokenizer->getLocation().string(),
313 mTokenizer->peekRemainderOfLine().string());
314 return BAD_VALUE;
315 }
316 }
317
318 mTokenizer->nextLine();
319 }
320 return NO_ERROR;
321}
322
323status_t KeyLayoutMap::Parser::parseKey() {
324 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
325 bool mapUsage = false;
326 if (codeToken == "usage") {
327 mapUsage = true;
328 mTokenizer->skipDelimiters(WHITESPACE);
329 codeToken = mTokenizer->nextToken(WHITESPACE);
330 }
331
332 char* end;
333 int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
334 if (*end) {
335 ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
336 mapUsage ? "usage" : "scan code", codeToken.string());
337 return BAD_VALUE;
338 }
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700339 std::unordered_map<int32_t, Key>& map =
340 mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
341 if (map.find(code) != map.end()) {
Jeff Brown5912f952013-07-01 19:10:31 -0700342 ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
343 mapUsage ? "usage" : "scan code", codeToken.string());
344 return BAD_VALUE;
345 }
346
347 mTokenizer->skipDelimiters(WHITESPACE);
348 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700349 int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700350 if (!keyCode) {
351 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
352 keyCodeToken.string());
353 return BAD_VALUE;
354 }
355
356 uint32_t flags = 0;
357 for (;;) {
358 mTokenizer->skipDelimiters(WHITESPACE);
359 if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break;
360
361 String8 flagToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700362 uint32_t flag = InputEventLookup::getKeyFlagByLabel(flagToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700363 if (!flag) {
364 ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),
365 flagToken.string());
366 return BAD_VALUE;
367 }
368 if (flags & flag) {
369 ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(),
370 flagToken.string());
371 return BAD_VALUE;
372 }
373 flags |= flag;
374 }
375
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700376 ALOGD_IF(DEBUG_PARSER, "Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
377 mapUsage ? "usage" : "scan code", code, keyCode, flags);
378
Jeff Brown5912f952013-07-01 19:10:31 -0700379 Key key;
380 key.keyCode = keyCode;
381 key.flags = flags;
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700382 map.insert({code, key});
Jeff Brown5912f952013-07-01 19:10:31 -0700383 return NO_ERROR;
384}
385
386status_t KeyLayoutMap::Parser::parseAxis() {
387 String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
388 char* end;
389 int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
390 if (*end) {
391 ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(),
392 scanCodeToken.string());
393 return BAD_VALUE;
394 }
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700395 if (mMap->mAxes.find(scanCode) != mMap->mAxes.end()) {
Jeff Brown5912f952013-07-01 19:10:31 -0700396 ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(),
397 scanCodeToken.string());
398 return BAD_VALUE;
399 }
400
401 AxisInfo axisInfo;
402
403 mTokenizer->skipDelimiters(WHITESPACE);
404 String8 token = mTokenizer->nextToken(WHITESPACE);
405 if (token == "invert") {
406 axisInfo.mode = AxisInfo::MODE_INVERT;
407
408 mTokenizer->skipDelimiters(WHITESPACE);
409 String8 axisToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700410 axisInfo.axis = InputEventLookup::getAxisByLabel(axisToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700411 if (axisInfo.axis < 0) {
412 ALOGE("%s: Expected inverted axis label, got '%s'.",
413 mTokenizer->getLocation().string(), axisToken.string());
414 return BAD_VALUE;
415 }
416 } else if (token == "split") {
417 axisInfo.mode = AxisInfo::MODE_SPLIT;
418
419 mTokenizer->skipDelimiters(WHITESPACE);
420 String8 splitToken = mTokenizer->nextToken(WHITESPACE);
421 axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0));
422 if (*end) {
423 ALOGE("%s: Expected split value, got '%s'.",
424 mTokenizer->getLocation().string(), splitToken.string());
425 return BAD_VALUE;
426 }
427
428 mTokenizer->skipDelimiters(WHITESPACE);
429 String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700430 axisInfo.axis = InputEventLookup::getAxisByLabel(lowAxisToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700431 if (axisInfo.axis < 0) {
432 ALOGE("%s: Expected low axis label, got '%s'.",
433 mTokenizer->getLocation().string(), lowAxisToken.string());
434 return BAD_VALUE;
435 }
436
437 mTokenizer->skipDelimiters(WHITESPACE);
438 String8 highAxisToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700439 axisInfo.highAxis = InputEventLookup::getAxisByLabel(highAxisToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700440 if (axisInfo.highAxis < 0) {
441 ALOGE("%s: Expected high axis label, got '%s'.",
442 mTokenizer->getLocation().string(), highAxisToken.string());
443 return BAD_VALUE;
444 }
445 } else {
Chris Ye4958d062020-08-20 13:21:10 -0700446 axisInfo.axis = InputEventLookup::getAxisByLabel(token.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700447 if (axisInfo.axis < 0) {
448 ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.",
449 mTokenizer->getLocation().string(), token.string());
450 return BAD_VALUE;
451 }
452 }
453
454 for (;;) {
455 mTokenizer->skipDelimiters(WHITESPACE);
456 if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') {
457 break;
458 }
459 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
460 if (keywordToken == "flat") {
461 mTokenizer->skipDelimiters(WHITESPACE);
462 String8 flatToken = mTokenizer->nextToken(WHITESPACE);
463 axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0));
464 if (*end) {
465 ALOGE("%s: Expected flat value, got '%s'.",
466 mTokenizer->getLocation().string(), flatToken.string());
467 return BAD_VALUE;
468 }
469 } else {
470 ALOGE("%s: Expected keyword 'flat', got '%s'.",
471 mTokenizer->getLocation().string(), keywordToken.string());
472 return BAD_VALUE;
473 }
474 }
475
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700476 ALOGD_IF(DEBUG_PARSER,
477 "Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
478 "splitValue=%d, flatOverride=%d.",
479 scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue,
480 axisInfo.flatOverride);
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700481 mMap->mAxes.insert({scanCode, axisInfo});
Jeff Brown5912f952013-07-01 19:10:31 -0700482 return NO_ERROR;
483}
484
Michael Wright74bdd2e2013-10-17 17:35:53 -0700485status_t KeyLayoutMap::Parser::parseLed() {
486 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
487 bool mapUsage = false;
488 if (codeToken == "usage") {
489 mapUsage = true;
490 mTokenizer->skipDelimiters(WHITESPACE);
491 codeToken = mTokenizer->nextToken(WHITESPACE);
492 }
493 char* end;
494 int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
495 if (*end) {
496 ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().string(),
497 mapUsage ? "usage" : "scan code", codeToken.string());
498 return BAD_VALUE;
499 }
500
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700501 std::unordered_map<int32_t, Led>& map =
502 mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode;
503 if (map.find(code) != map.end()) {
Michael Wright74bdd2e2013-10-17 17:35:53 -0700504 ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(),
505 mapUsage ? "usage" : "scan code", codeToken.string());
506 return BAD_VALUE;
507 }
508
509 mTokenizer->skipDelimiters(WHITESPACE);
510 String8 ledCodeToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700511 int32_t ledCode = InputEventLookup::getLedByLabel(ledCodeToken.string());
Michael Wright74bdd2e2013-10-17 17:35:53 -0700512 if (ledCode < 0) {
513 ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().string(),
514 ledCodeToken.string());
515 return BAD_VALUE;
516 }
517
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700518 ALOGD_IF(DEBUG_PARSER, "Parsed led %s: code=%d, ledCode=%d.", mapUsage ? "usage" : "scan code",
519 code, ledCode);
Michael Wright74bdd2e2013-10-17 17:35:53 -0700520
521 Led led;
522 led.ledCode = ledCode;
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700523 map.insert({code, led});
Michael Wright74bdd2e2013-10-17 17:35:53 -0700524 return NO_ERROR;
525}
Chris Yef59a2f42020-10-16 12:55:26 -0700526
527static std::optional<InputDeviceSensorType> getSensorType(const char* token) {
Dominik Laskowski75788452021-02-09 18:51:25 -0800528 auto it = SENSOR_LIST.find(token);
Chris Yef59a2f42020-10-16 12:55:26 -0700529 if (it == SENSOR_LIST.end()) {
530 return std::nullopt;
531 }
532 return it->second;
533}
534
535static std::optional<int32_t> getSensorDataIndex(String8 token) {
536 std::string tokenStr(token.string());
537 if (tokenStr == "X") {
538 return 0;
539 } else if (tokenStr == "Y") {
540 return 1;
541 } else if (tokenStr == "Z") {
542 return 2;
543 }
544 return std::nullopt;
545}
546
547// Parse sensor type and data index mapping, as below format
548// sensor <raw abs> <sensor type> <sensor data index>
549// raw abs : the linux abs code of the axis
550// sensor type : string name of InputDeviceSensorType
551// sensor data index : the data index of sensor, out of [X, Y, Z]
552// Examples:
553// sensor 0x00 ACCELEROMETER X
554// sensor 0x01 ACCELEROMETER Y
555// sensor 0x02 ACCELEROMETER Z
556// sensor 0x03 GYROSCOPE X
557// sensor 0x04 GYROSCOPE Y
558// sensor 0x05 GYROSCOPE Z
559status_t KeyLayoutMap::Parser::parseSensor() {
560 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
561 char* end;
562 int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
563 if (*end) {
564 ALOGE("%s: Expected sensor %s number, got '%s'.", mTokenizer->getLocation().string(),
565 "abs code", codeToken.string());
566 return BAD_VALUE;
567 }
568
569 std::unordered_map<int32_t, Sensor>& map = mMap->mSensorsByAbsCode;
570 if (map.find(code) != map.end()) {
571 ALOGE("%s: Duplicate entry for sensor %s '%s'.", mTokenizer->getLocation().string(),
572 "abs code", codeToken.string());
573 return BAD_VALUE;
574 }
575
576 mTokenizer->skipDelimiters(WHITESPACE);
577 String8 sensorTypeToken = mTokenizer->nextToken(WHITESPACE);
578 std::optional<InputDeviceSensorType> typeOpt = getSensorType(sensorTypeToken.string());
579 if (!typeOpt) {
580 ALOGE("%s: Expected sensor code label, got '%s'.", mTokenizer->getLocation().string(),
581 sensorTypeToken.string());
582 return BAD_VALUE;
583 }
584 InputDeviceSensorType sensorType = typeOpt.value();
585 mTokenizer->skipDelimiters(WHITESPACE);
586 String8 sensorDataIndexToken = mTokenizer->nextToken(WHITESPACE);
587 std::optional<int32_t> indexOpt = getSensorDataIndex(sensorDataIndexToken);
588 if (!indexOpt) {
589 ALOGE("%s: Expected sensor data index label, got '%s'.", mTokenizer->getLocation().string(),
590 sensorDataIndexToken.string());
591 return BAD_VALUE;
592 }
593 int32_t sensorDataIndex = indexOpt.value();
594
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700595 ALOGD_IF(DEBUG_PARSER, "Parsed sensor: abs code=%d, sensorType=%s, sensorDataIndex=%d.", code,
596 ftl::enum_string(sensorType).c_str(), sensorDataIndex);
Chris Yef59a2f42020-10-16 12:55:26 -0700597
598 Sensor sensor;
599 sensor.sensorType = sensorType;
600 sensor.sensorDataIndex = sensorDataIndex;
601 map.emplace(code, sensor);
602 return NO_ERROR;
603}
Dominik Laskowski75788452021-02-09 18:51:25 -0800604
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700605// Parse the name of a required kernel config.
606// The layout won't be used if the specified kernel config is not present
607// Examples:
608// requires_kernel_config CONFIG_HID_PLAYSTATION
609status_t KeyLayoutMap::Parser::parseRequiredKernelConfig() {
610 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
611 std::string configName = codeToken.string();
612
613 const auto result = mMap->mRequiredKernelConfigs.emplace(configName);
614 if (!result.second) {
615 ALOGE("%s: Duplicate entry for required kernel config %s.",
616 mTokenizer->getLocation().string(), configName.c_str());
617 return BAD_VALUE;
618 }
619
620 ALOGD_IF(DEBUG_PARSER, "Parsed required kernel config: name=%s", configName.c_str());
621 return NO_ERROR;
622}
623
Dominik Laskowski75788452021-02-09 18:51:25 -0800624} // namespace android