blob: 29df793a20e6f1a97fe49a1c67691f4c9d7e9068 [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
19#include <stdlib.h>
20
21#include <android/keycodes.h>
chaviw3277faf2021-05-19 16:45:23 -050022#include <ftl/NamedEnum.h>
Michael Wright872db4f2014-04-22 15:03:51 -070023#include <input/InputEventLabels.h>
Jeff Brown5912f952013-07-01 19:10:31 -070024#include <input/KeyLayoutMap.h>
Chris Yef59a2f42020-10-16 12:55:26 -070025#include <input/Keyboard.h>
Siarhei Vishniakou0a448ac2022-05-18 12:30:16 -070026#include <log/log.h>
Jeff Brown5912f952013-07-01 19:10:31 -070027#include <utils/Errors.h>
Jeff Brown5912f952013-07-01 19:10:31 -070028#include <utils/Timers.h>
Chris Yef59a2f42020-10-16 12:55:26 -070029#include <utils/Tokenizer.h>
Jeff Brown5912f952013-07-01 19:10:31 -070030
Siarhei Vishniakou0a448ac2022-05-18 12:30:16 -070031#include <cstdlib>
32#include <string_view>
33#include <unordered_map>
34
35/**
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 Vishniakou0a448ac2022-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 {
53
54static const char* WHITESPACE = " \t\r";
55
Chris Yef59a2f42020-10-16 12:55:26 -070056#define SENSOR_ENTRY(type) NamedEnum::string(type), type
57static const std::unordered_map<std::string, InputDeviceSensorType> SENSOR_LIST =
58 {{SENSOR_ENTRY(InputDeviceSensorType::ACCELEROMETER)},
59 {SENSOR_ENTRY(InputDeviceSensorType::MAGNETIC_FIELD)},
60 {SENSOR_ENTRY(InputDeviceSensorType::ORIENTATION)},
61 {SENSOR_ENTRY(InputDeviceSensorType::GYROSCOPE)},
62 {SENSOR_ENTRY(InputDeviceSensorType::LIGHT)},
63 {SENSOR_ENTRY(InputDeviceSensorType::PRESSURE)},
64 {SENSOR_ENTRY(InputDeviceSensorType::TEMPERATURE)},
65 {SENSOR_ENTRY(InputDeviceSensorType::PROXIMITY)},
66 {SENSOR_ENTRY(InputDeviceSensorType::GRAVITY)},
67 {SENSOR_ENTRY(InputDeviceSensorType::LINEAR_ACCELERATION)},
68 {SENSOR_ENTRY(InputDeviceSensorType::ROTATION_VECTOR)},
69 {SENSOR_ENTRY(InputDeviceSensorType::RELATIVE_HUMIDITY)},
70 {SENSOR_ENTRY(InputDeviceSensorType::AMBIENT_TEMPERATURE)},
71 {SENSOR_ENTRY(InputDeviceSensorType::MAGNETIC_FIELD_UNCALIBRATED)},
72 {SENSOR_ENTRY(InputDeviceSensorType::GAME_ROTATION_VECTOR)},
73 {SENSOR_ENTRY(InputDeviceSensorType::GYROSCOPE_UNCALIBRATED)},
74 {SENSOR_ENTRY(InputDeviceSensorType::SIGNIFICANT_MOTION)}};
75
Jeff Brown5912f952013-07-01 19:10:31 -070076// --- KeyLayoutMap ---
77
78KeyLayoutMap::KeyLayoutMap() {
79}
80
81KeyLayoutMap::~KeyLayoutMap() {
82}
83
Chris Ye1abffbd2020-08-18 12:50:12 -070084base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::loadContents(const std::string& filename,
85 const char* contents) {
86 Tokenizer* tokenizer;
87 status_t status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
88 if (status) {
89 ALOGE("Error %d opening key layout map.", status);
90 return Errorf("Error {} opening key layout map file {}.", status, filename.c_str());
91 }
92 std::unique_ptr<Tokenizer> t(tokenizer);
93 auto ret = load(t.get());
Bernie Innocenti147c86e2020-12-21 21:01:45 +090094 if (ret.ok()) {
Chris Ye1abffbd2020-08-18 12:50:12 -070095 (*ret)->mLoadFileName = filename;
96 }
97 return ret;
98}
Jeff Brown5912f952013-07-01 19:10:31 -070099
Chris Ye1abffbd2020-08-18 12:50:12 -0700100base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::load(const std::string& filename) {
Jeff Brown5912f952013-07-01 19:10:31 -0700101 Tokenizer* tokenizer;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100102 status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
Jeff Brown5912f952013-07-01 19:10:31 -0700103 if (status) {
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100104 ALOGE("Error %d opening key layout map file %s.", status, filename.c_str());
Chris Ye1abffbd2020-08-18 12:50:12 -0700105 return Errorf("Error {} opening key layout map file {}.", status, filename.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700106 }
Chris Ye1abffbd2020-08-18 12:50:12 -0700107 std::unique_ptr<Tokenizer> t(tokenizer);
108 auto ret = load(t.get());
Bernie Innocenti147c86e2020-12-21 21:01:45 +0900109 if (ret.ok()) {
Chris Ye1abffbd2020-08-18 12:50:12 -0700110 (*ret)->mLoadFileName = filename;
111 }
112 return ret;
113}
114
115base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::load(Tokenizer* tokenizer) {
116 std::shared_ptr<KeyLayoutMap> map = std::shared_ptr<KeyLayoutMap>(new KeyLayoutMap());
117 status_t status = OK;
118 if (!map.get()) {
119 ALOGE("Error allocating key layout map.");
120 return Errorf("Error allocating key layout map.");
121 } else {
122#if DEBUG_PARSER_PERFORMANCE
123 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
124#endif
125 Parser parser(map.get(), tokenizer);
126 status = parser.parse();
127#if DEBUG_PARSER_PERFORMANCE
128 nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
129 ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.",
130 tokenizer->getFilename().string(), tokenizer->getLineNumber(),
131 elapsedTime / 1000000.0);
132#endif
133 if (!status) {
134 return std::move(map);
135 }
136 }
137 return Errorf("Load KeyLayoutMap failed {}.", status);
Jeff Brown5912f952013-07-01 19:10:31 -0700138}
139
140status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t usageCode,
141 int32_t* outKeyCode, uint32_t* outFlags) const {
142 const Key* key = getKey(scanCode, usageCode);
143 if (!key) {
Siarhei Vishniakou0a448ac2022-05-18 12:30:16 -0700144 ALOGD_IF(DEBUG_MAPPING, "mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode,
145 usageCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700146 *outKeyCode = AKEYCODE_UNKNOWN;
147 *outFlags = 0;
148 return NAME_NOT_FOUND;
149 }
150
151 *outKeyCode = key->keyCode;
152 *outFlags = key->flags;
153
Siarhei Vishniakou0a448ac2022-05-18 12:30:16 -0700154 ALOGD_IF(DEBUG_MAPPING,
155 "mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.",
156 scanCode, usageCode, *outKeyCode, *outFlags);
Jeff Brown5912f952013-07-01 19:10:31 -0700157 return NO_ERROR;
158}
159
Chris Yef59a2f42020-10-16 12:55:26 -0700160// Return pair of sensor type and sensor data index, for the input device abs code
161base::Result<std::pair<InputDeviceSensorType, int32_t>> KeyLayoutMap::mapSensor(int32_t absCode) {
162 auto it = mSensorsByAbsCode.find(absCode);
163 if (it == mSensorsByAbsCode.end()) {
Siarhei Vishniakou0a448ac2022-05-18 12:30:16 -0700164 ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, ~ Failed.", absCode);
Chris Yef59a2f42020-10-16 12:55:26 -0700165 return Errorf("Can't find abs code {}.", absCode);
166 }
167 const Sensor& sensor = it->second;
Siarhei Vishniakou0a448ac2022-05-18 12:30:16 -0700168 ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, sensorType=%s, sensorDataIndex=0x%x.", absCode,
169 NamedEnum::string(sensor.sensorType).c_str(), sensor.sensorDataIndex);
Chris Yef59a2f42020-10-16 12:55:26 -0700170 return std::make_pair(sensor.sensorType, sensor.sensorDataIndex);
171}
172
Jeff Brown5912f952013-07-01 19:10:31 -0700173const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const {
174 if (usageCode) {
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700175 auto it = mKeysByUsageCode.find(usageCode);
176 if (it != mKeysByUsageCode.end()) {
177 return &it->second;
Jeff Brown5912f952013-07-01 19:10:31 -0700178 }
179 }
180 if (scanCode) {
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700181 auto it = mKeysByScanCode.find(scanCode);
182 if (it != mKeysByScanCode.end()) {
183 return &it->second;
Jeff Brown5912f952013-07-01 19:10:31 -0700184 }
185 }
Yi Kong5bed83b2018-07-17 12:53:47 -0700186 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700187}
188
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700189std::vector<int32_t> KeyLayoutMap::findScanCodesForKey(int32_t keyCode) const {
190 std::vector<int32_t> scanCodes;
191 for (const auto& [scanCode, key] : mKeysByScanCode) {
192 if (keyCode == key.keyCode) {
193 scanCodes.push_back(scanCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700194 }
195 }
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700196 return scanCodes;
Jeff Brown5912f952013-07-01 19:10:31 -0700197}
198
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700199std::optional<AxisInfo> KeyLayoutMap::mapAxis(int32_t scanCode) const {
200 auto it = mAxes.find(scanCode);
201 if (it == mAxes.end()) {
Siarhei Vishniakou0a448ac2022-05-18 12:30:16 -0700202 ALOGD_IF(DEBUG_MAPPING, "mapAxis: scanCode=%d ~ Failed.", scanCode);
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700203 return std::nullopt;
Jeff Brown5912f952013-07-01 19:10:31 -0700204 }
205
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700206 const AxisInfo& axisInfo = it->second;
Siarhei Vishniakou0a448ac2022-05-18 12:30:16 -0700207 ALOGD_IF(DEBUG_MAPPING,
208 "mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
209 "splitValue=%d, flatOverride=%d.",
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700210 scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue,
211 axisInfo.flatOverride);
212 return axisInfo;
Jeff Brown5912f952013-07-01 19:10:31 -0700213}
214
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700215std::optional<int32_t> KeyLayoutMap::findScanCodeForLed(int32_t ledCode) const {
216 for (const auto& [scanCode, led] : mLedsByScanCode) {
217 if (led.ledCode == ledCode) {
218 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d, scanCode=%d.", __func__, ledCode, scanCode);
219 return scanCode;
Michael Wright74bdd2e2013-10-17 17:35:53 -0700220 }
221 }
Siarhei Vishniakou0a448ac2022-05-18 12:30:16 -0700222 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d ~ Not found.", __func__, ledCode);
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700223 return std::nullopt;
Michael Wright74bdd2e2013-10-17 17:35:53 -0700224}
225
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700226std::optional<int32_t> KeyLayoutMap::findUsageCodeForLed(int32_t ledCode) const {
227 for (const auto& [usageCode, led] : mLedsByUsageCode) {
228 if (led.ledCode == ledCode) {
229 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d, usage=%x.", __func__, ledCode, usageCode);
230 return usageCode;
231 }
232 }
233 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d ~ Not found.", __func__, ledCode);
234 return std::nullopt;
235}
Jeff Brown5912f952013-07-01 19:10:31 -0700236
237// --- KeyLayoutMap::Parser ---
238
239KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
240 mMap(map), mTokenizer(tokenizer) {
241}
242
243KeyLayoutMap::Parser::~Parser() {
244}
245
246status_t KeyLayoutMap::Parser::parse() {
247 while (!mTokenizer->isEof()) {
Siarhei Vishniakou0a448ac2022-05-18 12:30:16 -0700248 ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().string(),
249 mTokenizer->peekRemainderOfLine().string());
Jeff Brown5912f952013-07-01 19:10:31 -0700250
251 mTokenizer->skipDelimiters(WHITESPACE);
252
253 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
254 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
255 if (keywordToken == "key") {
256 mTokenizer->skipDelimiters(WHITESPACE);
257 status_t status = parseKey();
258 if (status) return status;
259 } else if (keywordToken == "axis") {
260 mTokenizer->skipDelimiters(WHITESPACE);
261 status_t status = parseAxis();
262 if (status) return status;
Michael Wright74bdd2e2013-10-17 17:35:53 -0700263 } else if (keywordToken == "led") {
264 mTokenizer->skipDelimiters(WHITESPACE);
265 status_t status = parseLed();
266 if (status) return status;
Chris Yef59a2f42020-10-16 12:55:26 -0700267 } else if (keywordToken == "sensor") {
268 mTokenizer->skipDelimiters(WHITESPACE);
269 status_t status = parseSensor();
270 if (status) return status;
Jeff Brown5912f952013-07-01 19:10:31 -0700271 } else {
272 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
273 keywordToken.string());
274 return BAD_VALUE;
275 }
276
277 mTokenizer->skipDelimiters(WHITESPACE);
278 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
279 ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
280 mTokenizer->getLocation().string(),
281 mTokenizer->peekRemainderOfLine().string());
282 return BAD_VALUE;
283 }
284 }
285
286 mTokenizer->nextLine();
287 }
288 return NO_ERROR;
289}
290
291status_t KeyLayoutMap::Parser::parseKey() {
292 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
293 bool mapUsage = false;
294 if (codeToken == "usage") {
295 mapUsage = true;
296 mTokenizer->skipDelimiters(WHITESPACE);
297 codeToken = mTokenizer->nextToken(WHITESPACE);
298 }
299
300 char* end;
301 int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
302 if (*end) {
303 ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
304 mapUsage ? "usage" : "scan code", codeToken.string());
305 return BAD_VALUE;
306 }
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700307 std::unordered_map<int32_t, Key>& map =
308 mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
309 if (map.find(code) != map.end()) {
Jeff Brown5912f952013-07-01 19:10:31 -0700310 ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
311 mapUsage ? "usage" : "scan code", codeToken.string());
312 return BAD_VALUE;
313 }
314
315 mTokenizer->skipDelimiters(WHITESPACE);
316 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700317 int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700318 if (!keyCode) {
319 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
320 keyCodeToken.string());
321 return BAD_VALUE;
322 }
323
324 uint32_t flags = 0;
325 for (;;) {
326 mTokenizer->skipDelimiters(WHITESPACE);
327 if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break;
328
329 String8 flagToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700330 uint32_t flag = InputEventLookup::getKeyFlagByLabel(flagToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700331 if (!flag) {
332 ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),
333 flagToken.string());
334 return BAD_VALUE;
335 }
336 if (flags & flag) {
337 ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(),
338 flagToken.string());
339 return BAD_VALUE;
340 }
341 flags |= flag;
342 }
343
Siarhei Vishniakou0a448ac2022-05-18 12:30:16 -0700344 ALOGD_IF(DEBUG_PARSER, "Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
345 mapUsage ? "usage" : "scan code", code, keyCode, flags);
346
Jeff Brown5912f952013-07-01 19:10:31 -0700347 Key key;
348 key.keyCode = keyCode;
349 key.flags = flags;
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700350 map.insert({code, key});
Jeff Brown5912f952013-07-01 19:10:31 -0700351 return NO_ERROR;
352}
353
354status_t KeyLayoutMap::Parser::parseAxis() {
355 String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
356 char* end;
357 int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
358 if (*end) {
359 ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(),
360 scanCodeToken.string());
361 return BAD_VALUE;
362 }
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700363 if (mMap->mAxes.find(scanCode) != mMap->mAxes.end()) {
Jeff Brown5912f952013-07-01 19:10:31 -0700364 ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(),
365 scanCodeToken.string());
366 return BAD_VALUE;
367 }
368
369 AxisInfo axisInfo;
370
371 mTokenizer->skipDelimiters(WHITESPACE);
372 String8 token = mTokenizer->nextToken(WHITESPACE);
373 if (token == "invert") {
374 axisInfo.mode = AxisInfo::MODE_INVERT;
375
376 mTokenizer->skipDelimiters(WHITESPACE);
377 String8 axisToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700378 axisInfo.axis = InputEventLookup::getAxisByLabel(axisToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700379 if (axisInfo.axis < 0) {
380 ALOGE("%s: Expected inverted axis label, got '%s'.",
381 mTokenizer->getLocation().string(), axisToken.string());
382 return BAD_VALUE;
383 }
384 } else if (token == "split") {
385 axisInfo.mode = AxisInfo::MODE_SPLIT;
386
387 mTokenizer->skipDelimiters(WHITESPACE);
388 String8 splitToken = mTokenizer->nextToken(WHITESPACE);
389 axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0));
390 if (*end) {
391 ALOGE("%s: Expected split value, got '%s'.",
392 mTokenizer->getLocation().string(), splitToken.string());
393 return BAD_VALUE;
394 }
395
396 mTokenizer->skipDelimiters(WHITESPACE);
397 String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700398 axisInfo.axis = InputEventLookup::getAxisByLabel(lowAxisToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700399 if (axisInfo.axis < 0) {
400 ALOGE("%s: Expected low axis label, got '%s'.",
401 mTokenizer->getLocation().string(), lowAxisToken.string());
402 return BAD_VALUE;
403 }
404
405 mTokenizer->skipDelimiters(WHITESPACE);
406 String8 highAxisToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700407 axisInfo.highAxis = InputEventLookup::getAxisByLabel(highAxisToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700408 if (axisInfo.highAxis < 0) {
409 ALOGE("%s: Expected high axis label, got '%s'.",
410 mTokenizer->getLocation().string(), highAxisToken.string());
411 return BAD_VALUE;
412 }
413 } else {
Chris Ye4958d062020-08-20 13:21:10 -0700414 axisInfo.axis = InputEventLookup::getAxisByLabel(token.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700415 if (axisInfo.axis < 0) {
416 ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.",
417 mTokenizer->getLocation().string(), token.string());
418 return BAD_VALUE;
419 }
420 }
421
422 for (;;) {
423 mTokenizer->skipDelimiters(WHITESPACE);
424 if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') {
425 break;
426 }
427 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
428 if (keywordToken == "flat") {
429 mTokenizer->skipDelimiters(WHITESPACE);
430 String8 flatToken = mTokenizer->nextToken(WHITESPACE);
431 axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0));
432 if (*end) {
433 ALOGE("%s: Expected flat value, got '%s'.",
434 mTokenizer->getLocation().string(), flatToken.string());
435 return BAD_VALUE;
436 }
437 } else {
438 ALOGE("%s: Expected keyword 'flat', got '%s'.",
439 mTokenizer->getLocation().string(), keywordToken.string());
440 return BAD_VALUE;
441 }
442 }
443
Siarhei Vishniakou0a448ac2022-05-18 12:30:16 -0700444 ALOGD_IF(DEBUG_PARSER,
445 "Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
446 "splitValue=%d, flatOverride=%d.",
447 scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue,
448 axisInfo.flatOverride);
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700449 mMap->mAxes.insert({scanCode, axisInfo});
Jeff Brown5912f952013-07-01 19:10:31 -0700450 return NO_ERROR;
451}
452
Michael Wright74bdd2e2013-10-17 17:35:53 -0700453status_t KeyLayoutMap::Parser::parseLed() {
454 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
455 bool mapUsage = false;
456 if (codeToken == "usage") {
457 mapUsage = true;
458 mTokenizer->skipDelimiters(WHITESPACE);
459 codeToken = mTokenizer->nextToken(WHITESPACE);
460 }
461 char* end;
462 int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
463 if (*end) {
464 ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().string(),
465 mapUsage ? "usage" : "scan code", codeToken.string());
466 return BAD_VALUE;
467 }
468
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700469 std::unordered_map<int32_t, Led>& map =
470 mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode;
471 if (map.find(code) != map.end()) {
Michael Wright74bdd2e2013-10-17 17:35:53 -0700472 ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(),
473 mapUsage ? "usage" : "scan code", codeToken.string());
474 return BAD_VALUE;
475 }
476
477 mTokenizer->skipDelimiters(WHITESPACE);
478 String8 ledCodeToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700479 int32_t ledCode = InputEventLookup::getLedByLabel(ledCodeToken.string());
Michael Wright74bdd2e2013-10-17 17:35:53 -0700480 if (ledCode < 0) {
481 ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().string(),
482 ledCodeToken.string());
483 return BAD_VALUE;
484 }
485
Siarhei Vishniakou0a448ac2022-05-18 12:30:16 -0700486 ALOGD_IF(DEBUG_PARSER, "Parsed led %s: code=%d, ledCode=%d.", mapUsage ? "usage" : "scan code",
487 code, ledCode);
Michael Wright74bdd2e2013-10-17 17:35:53 -0700488
489 Led led;
490 led.ledCode = ledCode;
Siarhei Vishniakou984f40b2022-05-18 09:45:54 -0700491 map.insert({code, led});
Michael Wright74bdd2e2013-10-17 17:35:53 -0700492 return NO_ERROR;
493}
Chris Yef59a2f42020-10-16 12:55:26 -0700494
495static std::optional<InputDeviceSensorType> getSensorType(const char* token) {
496 auto it = SENSOR_LIST.find(std::string(token));
497 if (it == SENSOR_LIST.end()) {
498 return std::nullopt;
499 }
500 return it->second;
501}
502
503static std::optional<int32_t> getSensorDataIndex(String8 token) {
504 std::string tokenStr(token.string());
505 if (tokenStr == "X") {
506 return 0;
507 } else if (tokenStr == "Y") {
508 return 1;
509 } else if (tokenStr == "Z") {
510 return 2;
511 }
512 return std::nullopt;
513}
514
515// Parse sensor type and data index mapping, as below format
516// sensor <raw abs> <sensor type> <sensor data index>
517// raw abs : the linux abs code of the axis
518// sensor type : string name of InputDeviceSensorType
519// sensor data index : the data index of sensor, out of [X, Y, Z]
520// Examples:
521// sensor 0x00 ACCELEROMETER X
522// sensor 0x01 ACCELEROMETER Y
523// sensor 0x02 ACCELEROMETER Z
524// sensor 0x03 GYROSCOPE X
525// sensor 0x04 GYROSCOPE Y
526// sensor 0x05 GYROSCOPE Z
527status_t KeyLayoutMap::Parser::parseSensor() {
528 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
529 char* end;
530 int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
531 if (*end) {
532 ALOGE("%s: Expected sensor %s number, got '%s'.", mTokenizer->getLocation().string(),
533 "abs code", codeToken.string());
534 return BAD_VALUE;
535 }
536
537 std::unordered_map<int32_t, Sensor>& map = mMap->mSensorsByAbsCode;
538 if (map.find(code) != map.end()) {
539 ALOGE("%s: Duplicate entry for sensor %s '%s'.", mTokenizer->getLocation().string(),
540 "abs code", codeToken.string());
541 return BAD_VALUE;
542 }
543
544 mTokenizer->skipDelimiters(WHITESPACE);
545 String8 sensorTypeToken = mTokenizer->nextToken(WHITESPACE);
546 std::optional<InputDeviceSensorType> typeOpt = getSensorType(sensorTypeToken.string());
547 if (!typeOpt) {
548 ALOGE("%s: Expected sensor code label, got '%s'.", mTokenizer->getLocation().string(),
549 sensorTypeToken.string());
550 return BAD_VALUE;
551 }
552 InputDeviceSensorType sensorType = typeOpt.value();
553 mTokenizer->skipDelimiters(WHITESPACE);
554 String8 sensorDataIndexToken = mTokenizer->nextToken(WHITESPACE);
555 std::optional<int32_t> indexOpt = getSensorDataIndex(sensorDataIndexToken);
556 if (!indexOpt) {
557 ALOGE("%s: Expected sensor data index label, got '%s'.", mTokenizer->getLocation().string(),
558 sensorDataIndexToken.string());
559 return BAD_VALUE;
560 }
561 int32_t sensorDataIndex = indexOpt.value();
562
Siarhei Vishniakou0a448ac2022-05-18 12:30:16 -0700563 ALOGD_IF(DEBUG_PARSER, "Parsed sensor: abs code=%d, sensorType=%s, sensorDataIndex=%d.", code,
564 NamedEnum::string(sensorType).c_str(), sensorDataIndex);
Chris Yef59a2f42020-10-16 12:55:26 -0700565
566 Sensor sensor;
567 sensor.sensorType = sensorType;
568 sensor.sensorDataIndex = sensorDataIndex;
569 map.emplace(code, sensor);
570 return NO_ERROR;
571}
Jeff Brown5912f952013-07-01 19:10:31 -0700572};