blob: 00fc051ceabb08f89eb214b670dcf68c952b7ac1 [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 Vishniakouac7f2e72022-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>
Jeff Brown5912f952013-07-01 19:10:31 -070028
Dominik Laskowski75788452021-02-09 18:51:25 -080029#include <cstdlib>
30#include <string_view>
31#include <unordered_map>
32
Siarhei Vishniakouac7f2e72022-05-18 12:30:16 -070033/**
34 * Log debug output for the parser.
35 * Enable this via "adb shell setprop log.tag.KeyLayoutMapParser DEBUG" (requires restart)
36 */
37const bool DEBUG_PARSER =
38 __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Parser", ANDROID_LOG_INFO);
Jeff Brown5912f952013-07-01 19:10:31 -070039
40// Enables debug output for parser performance.
41#define DEBUG_PARSER_PERFORMANCE 0
42
Siarhei Vishniakouac7f2e72022-05-18 12:30:16 -070043/**
44 * Log debug output for mapping.
45 * Enable this via "adb shell setprop log.tag.KeyLayoutMapMapping DEBUG" (requires restart)
46 */
47const bool DEBUG_MAPPING =
48 __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Mapping", ANDROID_LOG_INFO);
Jeff Brown5912f952013-07-01 19:10:31 -070049
50namespace android {
Dominik Laskowski75788452021-02-09 18:51:25 -080051namespace {
Jeff Brown5912f952013-07-01 19:10:31 -070052
Dominik Laskowski75788452021-02-09 18:51:25 -080053constexpr const char* WHITESPACE = " \t\r";
Jeff Brown5912f952013-07-01 19:10:31 -070054
Dominik Laskowski75788452021-02-09 18:51:25 -080055template <InputDeviceSensorType S>
56constexpr auto sensorPair() {
57 return std::make_pair(ftl::enum_name<S>(), S);
Jeff Brown5912f952013-07-01 19:10:31 -070058}
59
Dominik Laskowski75788452021-02-09 18:51:25 -080060static const std::unordered_map<std::string_view, InputDeviceSensorType> SENSOR_LIST =
61 {sensorPair<InputDeviceSensorType::ACCELEROMETER>(),
62 sensorPair<InputDeviceSensorType::MAGNETIC_FIELD>(),
63 sensorPair<InputDeviceSensorType::ORIENTATION>(),
64 sensorPair<InputDeviceSensorType::GYROSCOPE>(),
65 sensorPair<InputDeviceSensorType::LIGHT>(),
66 sensorPair<InputDeviceSensorType::PRESSURE>(),
67 sensorPair<InputDeviceSensorType::TEMPERATURE>(),
68 sensorPair<InputDeviceSensorType::PROXIMITY>(),
69 sensorPair<InputDeviceSensorType::GRAVITY>(),
70 sensorPair<InputDeviceSensorType::LINEAR_ACCELERATION>(),
71 sensorPair<InputDeviceSensorType::ROTATION_VECTOR>(),
72 sensorPair<InputDeviceSensorType::RELATIVE_HUMIDITY>(),
73 sensorPair<InputDeviceSensorType::AMBIENT_TEMPERATURE>(),
74 sensorPair<InputDeviceSensorType::MAGNETIC_FIELD_UNCALIBRATED>(),
75 sensorPair<InputDeviceSensorType::GAME_ROTATION_VECTOR>(),
76 sensorPair<InputDeviceSensorType::GYROSCOPE_UNCALIBRATED>(),
77 sensorPair<InputDeviceSensorType::SIGNIFICANT_MOTION>()};
78
79} // namespace
80
81KeyLayoutMap::KeyLayoutMap() = default;
82KeyLayoutMap::~KeyLayoutMap() = default;
Jeff Brown5912f952013-07-01 19:10:31 -070083
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 Vishniakouac7f2e72022-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 Vishniakouac7f2e72022-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 Vishniakouac7f2e72022-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 Vishniakouac7f2e72022-05-18 12:30:16 -0700168 ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, sensorType=%s, sensorDataIndex=0x%x.", absCode,
169 ftl::enum_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 Vishniakou53f0a5e2022-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 Vishniakou53f0a5e2022-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 Vishniakou53f0a5e2022-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 Vishniakou53f0a5e2022-05-18 09:45:54 -0700196 return scanCodes;
Jeff Brown5912f952013-07-01 19:10:31 -0700197}
198
Siarhei Vishniakou53f0a5e2022-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 Vishniakouac7f2e72022-05-18 12:30:16 -0700202 ALOGD_IF(DEBUG_MAPPING, "mapAxis: scanCode=%d ~ Failed.", scanCode);
Siarhei Vishniakou53f0a5e2022-05-18 09:45:54 -0700203 return std::nullopt;
Jeff Brown5912f952013-07-01 19:10:31 -0700204 }
205
Siarhei Vishniakou53f0a5e2022-05-18 09:45:54 -0700206 const AxisInfo& axisInfo = it->second;
Siarhei Vishniakouac7f2e72022-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 Vishniakou53f0a5e2022-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 Vishniakou53f0a5e2022-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 Vishniakouac7f2e72022-05-18 12:30:16 -0700222 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d ~ Not found.", __func__, ledCode);
Siarhei Vishniakou53f0a5e2022-05-18 09:45:54 -0700223 return std::nullopt;
Michael Wright74bdd2e2013-10-17 17:35:53 -0700224}
225
Siarhei Vishniakou53f0a5e2022-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 Vishniakouac7f2e72022-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 Vishniakou53f0a5e2022-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 Vishniakouac7f2e72022-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 Vishniakou53f0a5e2022-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 Vishniakou53f0a5e2022-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 Vishniakouac7f2e72022-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 Vishniakou53f0a5e2022-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 Vishniakou53f0a5e2022-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 Vishniakouac7f2e72022-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 Vishniakou53f0a5e2022-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) {
Dominik Laskowski75788452021-02-09 18:51:25 -0800496 auto it = SENSOR_LIST.find(token);
Chris Yef59a2f42020-10-16 12:55:26 -0700497 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 Vishniakouac7f2e72022-05-18 12:30:16 -0700563 ALOGD_IF(DEBUG_PARSER, "Parsed sensor: abs code=%d, sensorType=%s, sensorDataIndex=%d.", code,
564 ftl::enum_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}
Dominik Laskowski75788452021-02-09 18:51:25 -0800572
573} // namespace android