1 /*
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 <android/keycodes.h>
20 #include <ftl/enum.h>
21 #include <input/InputEventLabels.h>
22 #include <input/KeyLayoutMap.h>
23 #include <input/Keyboard.h>
24 #include <log/log.h>
25 #include <utils/Errors.h>
26 #include <utils/Timers.h>
27 #include <utils/Tokenizer.h>
28 #include <vintf/RuntimeInfo.h>
29 #include <vintf/VintfObject.h>
30
31 #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 */
39 const bool DEBUG_PARSER =
40 __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Parser", ANDROID_LOG_INFO);
41
42 // Enables debug output for parser performance.
43 #define DEBUG_PARSER_PERFORMANCE 0
44
45 /**
46 * Log debug output for mapping.
47 * Enable this via "adb shell setprop log.tag.KeyLayoutMapMapping DEBUG" (requires restart)
48 */
49 const bool DEBUG_MAPPING =
50 __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Mapping", ANDROID_LOG_INFO);
51
52 namespace android {
53 namespace {
54
55 constexpr const char* WHITESPACE = " \t\r";
56
57 template <InputDeviceSensorType S>
sensorPair()58 constexpr auto sensorPair() {
59 return std::make_pair(ftl::enum_name<S>(), S);
60 }
61
62 static 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
kernelConfigsArePresent(const std::set<std::string> & configs)81 bool 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
104 } // namespace
105
106 KeyLayoutMap::KeyLayoutMap() = default;
107 KeyLayoutMap::~KeyLayoutMap() = default;
108
loadContents(const std::string & filename,const char * contents)109 base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::loadContents(const std::string& filename,
110 const char* contents) {
111 return load(filename, contents);
112 }
113
load(const std::string & filename,const char * contents)114 base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::load(const std::string& filename,
115 const char* contents) {
116 Tokenizer* tokenizer;
117 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 }
123 if (status) {
124 ALOGE("Error %d opening key layout map file %s.", status, filename.c_str());
125 return Errorf("Error {} opening key layout map file {}.", status, filename.c_str());
126 }
127 std::unique_ptr<Tokenizer> t(tokenizer);
128 auto ret = load(t.get());
129 if (!ret.ok()) {
130 return ret;
131 }
132 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;
139 return ret;
140 }
141
load(Tokenizer * tokenizer)142 base::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);
165 }
166
mapKey(int32_t scanCode,int32_t usageCode,int32_t * outKeyCode,uint32_t * outFlags) const167 status_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) {
171 ALOGD_IF(DEBUG_MAPPING, "mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode,
172 usageCode);
173 *outKeyCode = AKEYCODE_UNKNOWN;
174 *outFlags = 0;
175 return NAME_NOT_FOUND;
176 }
177
178 *outKeyCode = key->keyCode;
179 *outFlags = key->flags;
180
181 ALOGD_IF(DEBUG_MAPPING,
182 "mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.",
183 scanCode, usageCode, *outKeyCode, *outFlags);
184 return NO_ERROR;
185 }
186
187 // Return pair of sensor type and sensor data index, for the input device abs code
mapSensor(int32_t absCode)188 base::Result<std::pair<InputDeviceSensorType, int32_t>> KeyLayoutMap::mapSensor(int32_t absCode) {
189 auto it = mSensorsByAbsCode.find(absCode);
190 if (it == mSensorsByAbsCode.end()) {
191 ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, ~ Failed.", absCode);
192 return Errorf("Can't find abs code {}.", absCode);
193 }
194 const Sensor& sensor = it->second;
195 ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, sensorType=%s, sensorDataIndex=0x%x.", absCode,
196 ftl::enum_string(sensor.sensorType).c_str(), sensor.sensorDataIndex);
197 return std::make_pair(sensor.sensorType, sensor.sensorDataIndex);
198 }
199
getKey(int32_t scanCode,int32_t usageCode) const200 const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const {
201 if (usageCode) {
202 ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
203 if (index >= 0) {
204 return &mKeysByUsageCode.valueAt(index);
205 }
206 }
207 if (scanCode) {
208 ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
209 if (index >= 0) {
210 return &mKeysByScanCode.valueAt(index);
211 }
212 }
213 return nullptr;
214 }
215
findScanCodesForKey(int32_t keyCode,std::vector<int32_t> * outScanCodes) const216 status_t KeyLayoutMap::findScanCodesForKey(
217 int32_t keyCode, std::vector<int32_t>* outScanCodes) const {
218 const size_t N = mKeysByScanCode.size();
219 for (size_t i=0; i<N; i++) {
220 if (mKeysByScanCode.valueAt(i).keyCode == keyCode) {
221 outScanCodes->push_back(mKeysByScanCode.keyAt(i));
222 }
223 }
224 return NO_ERROR;
225 }
226
mapAxis(int32_t scanCode,AxisInfo * outAxisInfo) const227 status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const {
228 ssize_t index = mAxes.indexOfKey(scanCode);
229 if (index < 0) {
230 ALOGD_IF(DEBUG_MAPPING, "mapAxis: scanCode=%d ~ Failed.", scanCode);
231 return NAME_NOT_FOUND;
232 }
233
234 *outAxisInfo = mAxes.valueAt(index);
235
236 ALOGD_IF(DEBUG_MAPPING,
237 "mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
238 "splitValue=%d, flatOverride=%d.",
239 scanCode, outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis,
240 outAxisInfo->splitValue, outAxisInfo->flatOverride);
241
242 return NO_ERROR;
243 }
244
findScanCodeForLed(int32_t ledCode,int32_t * outScanCode) const245 status_t KeyLayoutMap::findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const {
246 const size_t N = mLedsByScanCode.size();
247 for (size_t i = 0; i < N; i++) {
248 if (mLedsByScanCode.valueAt(i).ledCode == ledCode) {
249 *outScanCode = mLedsByScanCode.keyAt(i);
250 ALOGD_IF(DEBUG_MAPPING, "findScanCodeForLed: ledCode=%d, scanCode=%d.", ledCode,
251 *outScanCode);
252 return NO_ERROR;
253 }
254 }
255 ALOGD_IF(DEBUG_MAPPING, "findScanCodeForLed: ledCode=%d ~ Not found.", ledCode);
256 return NAME_NOT_FOUND;
257 }
258
findUsageCodeForLed(int32_t ledCode,int32_t * outUsageCode) const259 status_t KeyLayoutMap::findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const {
260 const size_t N = mLedsByUsageCode.size();
261 for (size_t i = 0; i < N; i++) {
262 if (mLedsByUsageCode.valueAt(i).ledCode == ledCode) {
263 *outUsageCode = mLedsByUsageCode.keyAt(i);
264 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d, usage=%x.", __func__, ledCode, *outUsageCode);
265 return NO_ERROR;
266 }
267 }
268 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d ~ Not found.", __func__, ledCode);
269
270 return NAME_NOT_FOUND;
271 }
272
273
274 // --- KeyLayoutMap::Parser ---
275
Parser(KeyLayoutMap * map,Tokenizer * tokenizer)276 KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
277 mMap(map), mTokenizer(tokenizer) {
278 }
279
~Parser()280 KeyLayoutMap::Parser::~Parser() {
281 }
282
parse()283 status_t KeyLayoutMap::Parser::parse() {
284 while (!mTokenizer->isEof()) {
285 ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().string(),
286 mTokenizer->peekRemainderOfLine().string());
287
288 mTokenizer->skipDelimiters(WHITESPACE);
289
290 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
291 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
292 if (keywordToken == "key") {
293 mTokenizer->skipDelimiters(WHITESPACE);
294 status_t status = parseKey();
295 if (status) return status;
296 } else if (keywordToken == "axis") {
297 mTokenizer->skipDelimiters(WHITESPACE);
298 status_t status = parseAxis();
299 if (status) return status;
300 } else if (keywordToken == "led") {
301 mTokenizer->skipDelimiters(WHITESPACE);
302 status_t status = parseLed();
303 if (status) return status;
304 } else if (keywordToken == "sensor") {
305 mTokenizer->skipDelimiters(WHITESPACE);
306 status_t status = parseSensor();
307 if (status) return status;
308 } else if (keywordToken == "requires_kernel_config") {
309 mTokenizer->skipDelimiters(WHITESPACE);
310 status_t status = parseRequiredKernelConfig();
311 if (status) return status;
312 } else {
313 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
314 keywordToken.string());
315 return BAD_VALUE;
316 }
317
318 mTokenizer->skipDelimiters(WHITESPACE);
319 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
320 ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
321 mTokenizer->getLocation().string(),
322 mTokenizer->peekRemainderOfLine().string());
323 return BAD_VALUE;
324 }
325 }
326
327 mTokenizer->nextLine();
328 }
329 return NO_ERROR;
330 }
331
parseKey()332 status_t KeyLayoutMap::Parser::parseKey() {
333 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
334 bool mapUsage = false;
335 if (codeToken == "usage") {
336 mapUsage = true;
337 mTokenizer->skipDelimiters(WHITESPACE);
338 codeToken = mTokenizer->nextToken(WHITESPACE);
339 }
340
341 char* end;
342 int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
343 if (*end) {
344 ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
345 mapUsage ? "usage" : "scan code", codeToken.string());
346 return BAD_VALUE;
347 }
348 KeyedVector<int32_t, Key>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
349 if (map.indexOfKey(code) >= 0) {
350 ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
351 mapUsage ? "usage" : "scan code", codeToken.string());
352 return BAD_VALUE;
353 }
354
355 mTokenizer->skipDelimiters(WHITESPACE);
356 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
357 int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
358 if (!keyCode) {
359 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
360 keyCodeToken.string());
361 return BAD_VALUE;
362 }
363
364 uint32_t flags = 0;
365 for (;;) {
366 mTokenizer->skipDelimiters(WHITESPACE);
367 if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break;
368
369 String8 flagToken = mTokenizer->nextToken(WHITESPACE);
370 uint32_t flag = InputEventLookup::getKeyFlagByLabel(flagToken.string());
371 if (!flag) {
372 ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),
373 flagToken.string());
374 return BAD_VALUE;
375 }
376 if (flags & flag) {
377 ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(),
378 flagToken.string());
379 return BAD_VALUE;
380 }
381 flags |= flag;
382 }
383
384 ALOGD_IF(DEBUG_PARSER, "Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
385 mapUsage ? "usage" : "scan code", code, keyCode, flags);
386
387 Key key;
388 key.keyCode = keyCode;
389 key.flags = flags;
390 map.add(code, key);
391 return NO_ERROR;
392 }
393
parseAxis()394 status_t KeyLayoutMap::Parser::parseAxis() {
395 String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
396 char* end;
397 int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
398 if (*end) {
399 ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(),
400 scanCodeToken.string());
401 return BAD_VALUE;
402 }
403 if (mMap->mAxes.indexOfKey(scanCode) >= 0) {
404 ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(),
405 scanCodeToken.string());
406 return BAD_VALUE;
407 }
408
409 AxisInfo axisInfo;
410
411 mTokenizer->skipDelimiters(WHITESPACE);
412 String8 token = mTokenizer->nextToken(WHITESPACE);
413 if (token == "invert") {
414 axisInfo.mode = AxisInfo::MODE_INVERT;
415
416 mTokenizer->skipDelimiters(WHITESPACE);
417 String8 axisToken = mTokenizer->nextToken(WHITESPACE);
418 axisInfo.axis = InputEventLookup::getAxisByLabel(axisToken.string());
419 if (axisInfo.axis < 0) {
420 ALOGE("%s: Expected inverted axis label, got '%s'.",
421 mTokenizer->getLocation().string(), axisToken.string());
422 return BAD_VALUE;
423 }
424 } else if (token == "split") {
425 axisInfo.mode = AxisInfo::MODE_SPLIT;
426
427 mTokenizer->skipDelimiters(WHITESPACE);
428 String8 splitToken = mTokenizer->nextToken(WHITESPACE);
429 axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0));
430 if (*end) {
431 ALOGE("%s: Expected split value, got '%s'.",
432 mTokenizer->getLocation().string(), splitToken.string());
433 return BAD_VALUE;
434 }
435
436 mTokenizer->skipDelimiters(WHITESPACE);
437 String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE);
438 axisInfo.axis = InputEventLookup::getAxisByLabel(lowAxisToken.string());
439 if (axisInfo.axis < 0) {
440 ALOGE("%s: Expected low axis label, got '%s'.",
441 mTokenizer->getLocation().string(), lowAxisToken.string());
442 return BAD_VALUE;
443 }
444
445 mTokenizer->skipDelimiters(WHITESPACE);
446 String8 highAxisToken = mTokenizer->nextToken(WHITESPACE);
447 axisInfo.highAxis = InputEventLookup::getAxisByLabel(highAxisToken.string());
448 if (axisInfo.highAxis < 0) {
449 ALOGE("%s: Expected high axis label, got '%s'.",
450 mTokenizer->getLocation().string(), highAxisToken.string());
451 return BAD_VALUE;
452 }
453 } else {
454 axisInfo.axis = InputEventLookup::getAxisByLabel(token.string());
455 if (axisInfo.axis < 0) {
456 ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.",
457 mTokenizer->getLocation().string(), token.string());
458 return BAD_VALUE;
459 }
460 }
461
462 for (;;) {
463 mTokenizer->skipDelimiters(WHITESPACE);
464 if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') {
465 break;
466 }
467 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
468 if (keywordToken == "flat") {
469 mTokenizer->skipDelimiters(WHITESPACE);
470 String8 flatToken = mTokenizer->nextToken(WHITESPACE);
471 axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0));
472 if (*end) {
473 ALOGE("%s: Expected flat value, got '%s'.",
474 mTokenizer->getLocation().string(), flatToken.string());
475 return BAD_VALUE;
476 }
477 } else {
478 ALOGE("%s: Expected keyword 'flat', got '%s'.",
479 mTokenizer->getLocation().string(), keywordToken.string());
480 return BAD_VALUE;
481 }
482 }
483
484 ALOGD_IF(DEBUG_PARSER,
485 "Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
486 "splitValue=%d, flatOverride=%d.",
487 scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue,
488 axisInfo.flatOverride);
489
490 mMap->mAxes.add(scanCode, axisInfo);
491 return NO_ERROR;
492 }
493
parseLed()494 status_t KeyLayoutMap::Parser::parseLed() {
495 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
496 bool mapUsage = false;
497 if (codeToken == "usage") {
498 mapUsage = true;
499 mTokenizer->skipDelimiters(WHITESPACE);
500 codeToken = mTokenizer->nextToken(WHITESPACE);
501 }
502 char* end;
503 int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
504 if (*end) {
505 ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().string(),
506 mapUsage ? "usage" : "scan code", codeToken.string());
507 return BAD_VALUE;
508 }
509
510 KeyedVector<int32_t, Led>& map = mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode;
511 if (map.indexOfKey(code) >= 0) {
512 ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(),
513 mapUsage ? "usage" : "scan code", codeToken.string());
514 return BAD_VALUE;
515 }
516
517 mTokenizer->skipDelimiters(WHITESPACE);
518 String8 ledCodeToken = mTokenizer->nextToken(WHITESPACE);
519 int32_t ledCode = InputEventLookup::getLedByLabel(ledCodeToken.string());
520 if (ledCode < 0) {
521 ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().string(),
522 ledCodeToken.string());
523 return BAD_VALUE;
524 }
525
526 ALOGD_IF(DEBUG_PARSER, "Parsed led %s: code=%d, ledCode=%d.", mapUsage ? "usage" : "scan code",
527 code, ledCode);
528
529 Led led;
530 led.ledCode = ledCode;
531 map.add(code, led);
532 return NO_ERROR;
533 }
534
getSensorType(const char * token)535 static std::optional<InputDeviceSensorType> getSensorType(const char* token) {
536 auto it = SENSOR_LIST.find(token);
537 if (it == SENSOR_LIST.end()) {
538 return std::nullopt;
539 }
540 return it->second;
541 }
542
getSensorDataIndex(String8 token)543 static std::optional<int32_t> getSensorDataIndex(String8 token) {
544 std::string tokenStr(token.string());
545 if (tokenStr == "X") {
546 return 0;
547 } else if (tokenStr == "Y") {
548 return 1;
549 } else if (tokenStr == "Z") {
550 return 2;
551 }
552 return std::nullopt;
553 }
554
555 // Parse sensor type and data index mapping, as below format
556 // sensor <raw abs> <sensor type> <sensor data index>
557 // raw abs : the linux abs code of the axis
558 // sensor type : string name of InputDeviceSensorType
559 // sensor data index : the data index of sensor, out of [X, Y, Z]
560 // Examples:
561 // sensor 0x00 ACCELEROMETER X
562 // sensor 0x01 ACCELEROMETER Y
563 // sensor 0x02 ACCELEROMETER Z
564 // sensor 0x03 GYROSCOPE X
565 // sensor 0x04 GYROSCOPE Y
566 // sensor 0x05 GYROSCOPE Z
parseSensor()567 status_t KeyLayoutMap::Parser::parseSensor() {
568 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
569 char* end;
570 int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
571 if (*end) {
572 ALOGE("%s: Expected sensor %s number, got '%s'.", mTokenizer->getLocation().string(),
573 "abs code", codeToken.string());
574 return BAD_VALUE;
575 }
576
577 std::unordered_map<int32_t, Sensor>& map = mMap->mSensorsByAbsCode;
578 if (map.find(code) != map.end()) {
579 ALOGE("%s: Duplicate entry for sensor %s '%s'.", mTokenizer->getLocation().string(),
580 "abs code", codeToken.string());
581 return BAD_VALUE;
582 }
583
584 mTokenizer->skipDelimiters(WHITESPACE);
585 String8 sensorTypeToken = mTokenizer->nextToken(WHITESPACE);
586 std::optional<InputDeviceSensorType> typeOpt = getSensorType(sensorTypeToken.string());
587 if (!typeOpt) {
588 ALOGE("%s: Expected sensor code label, got '%s'.", mTokenizer->getLocation().string(),
589 sensorTypeToken.string());
590 return BAD_VALUE;
591 }
592 InputDeviceSensorType sensorType = typeOpt.value();
593 mTokenizer->skipDelimiters(WHITESPACE);
594 String8 sensorDataIndexToken = mTokenizer->nextToken(WHITESPACE);
595 std::optional<int32_t> indexOpt = getSensorDataIndex(sensorDataIndexToken);
596 if (!indexOpt) {
597 ALOGE("%s: Expected sensor data index label, got '%s'.", mTokenizer->getLocation().string(),
598 sensorDataIndexToken.string());
599 return BAD_VALUE;
600 }
601 int32_t sensorDataIndex = indexOpt.value();
602
603 ALOGD_IF(DEBUG_PARSER, "Parsed sensor: abs code=%d, sensorType=%s, sensorDataIndex=%d.", code,
604 ftl::enum_string(sensorType).c_str(), sensorDataIndex);
605
606 Sensor sensor;
607 sensor.sensorType = sensorType;
608 sensor.sensorDataIndex = sensorDataIndex;
609 map.emplace(code, sensor);
610 return NO_ERROR;
611 }
612
613 // Parse the name of a required kernel config.
614 // The layout won't be used if the specified kernel config is not present
615 // Examples:
616 // requires_kernel_config CONFIG_HID_PLAYSTATION
parseRequiredKernelConfig()617 status_t KeyLayoutMap::Parser::parseRequiredKernelConfig() {
618 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
619 std::string configName = codeToken.string();
620
621 const auto result = mMap->mRequiredKernelConfigs.emplace(configName);
622 if (!result.second) {
623 ALOGE("%s: Duplicate entry for required kernel config %s.",
624 mTokenizer->getLocation().string(), configName.c_str());
625 return BAD_VALUE;
626 }
627
628 ALOGD_IF(DEBUG_PARSER, "Parsed required kernel config: name=%s", configName.c_str());
629 return NO_ERROR;
630 }
631
632 } // namespace android
633