blob: 59cc7d1dcd61f9a34247f92dc40d920a57b23053 [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
188base::Result<std::pair<InputDeviceSensorType, int32_t>> KeyLayoutMap::mapSensor(int32_t absCode) {
189 auto it = mSensorsByAbsCode.find(absCode);
190 if (it == mSensorsByAbsCode.end()) {
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700191 ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, ~ Failed.", absCode);
Chris Yef59a2f42020-10-16 12:55:26 -0700192 return Errorf("Can't find abs code {}.", absCode);
193 }
194 const Sensor& sensor = it->second;
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700195 ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, sensorType=%s, sensorDataIndex=0x%x.", absCode,
196 ftl::enum_string(sensor.sensorType).c_str(), sensor.sensorDataIndex);
Chris Yef59a2f42020-10-16 12:55:26 -0700197 return std::make_pair(sensor.sensorType, sensor.sensorDataIndex);
198}
199
Jeff Brown5912f952013-07-01 19:10:31 -0700200const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const {
201 if (usageCode) {
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700202 auto it = mKeysByUsageCode.find(usageCode);
203 if (it != mKeysByUsageCode.end()) {
204 return &it->second;
Jeff Brown5912f952013-07-01 19:10:31 -0700205 }
206 }
207 if (scanCode) {
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700208 auto it = mKeysByScanCode.find(scanCode);
209 if (it != mKeysByScanCode.end()) {
210 return &it->second;
Jeff Brown5912f952013-07-01 19:10:31 -0700211 }
212 }
Yi Kong5bed83b2018-07-17 12:53:47 -0700213 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700214}
215
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700216std::vector<int32_t> KeyLayoutMap::findScanCodesForKey(int32_t keyCode) const {
217 std::vector<int32_t> scanCodes;
218 for (const auto& [scanCode, key] : mKeysByScanCode) {
219 if (keyCode == key.keyCode) {
220 scanCodes.push_back(scanCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700221 }
222 }
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700223 return scanCodes;
Jeff Brown5912f952013-07-01 19:10:31 -0700224}
225
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700226std::optional<AxisInfo> KeyLayoutMap::mapAxis(int32_t scanCode) const {
227 auto it = mAxes.find(scanCode);
228 if (it == mAxes.end()) {
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700229 ALOGD_IF(DEBUG_MAPPING, "mapAxis: scanCode=%d ~ Failed.", scanCode);
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700230 return std::nullopt;
Jeff Brown5912f952013-07-01 19:10:31 -0700231 }
232
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700233 const AxisInfo& axisInfo = it->second;
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700234 ALOGD_IF(DEBUG_MAPPING,
235 "mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
236 "splitValue=%d, flatOverride=%d.",
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700237 scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue,
238 axisInfo.flatOverride);
239 return axisInfo;
Jeff Brown5912f952013-07-01 19:10:31 -0700240}
241
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700242std::optional<int32_t> KeyLayoutMap::findScanCodeForLed(int32_t ledCode) const {
243 for (const auto& [scanCode, led] : mLedsByScanCode) {
244 if (led.ledCode == ledCode) {
245 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d, scanCode=%d.", __func__, ledCode, scanCode);
246 return scanCode;
Michael Wright74bdd2e2013-10-17 17:35:53 -0700247 }
248 }
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700249 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d ~ Not found.", __func__, ledCode);
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700250 return std::nullopt;
Michael Wright74bdd2e2013-10-17 17:35:53 -0700251}
252
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700253std::optional<int32_t> KeyLayoutMap::findUsageCodeForLed(int32_t ledCode) const {
254 for (const auto& [usageCode, led] : mLedsByUsageCode) {
255 if (led.ledCode == ledCode) {
256 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d, usage=%x.", __func__, ledCode, usageCode);
257 return usageCode;
258 }
259 }
260 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d ~ Not found.", __func__, ledCode);
261 return std::nullopt;
262}
Jeff Brown5912f952013-07-01 19:10:31 -0700263
264// --- KeyLayoutMap::Parser ---
265
266KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
267 mMap(map), mTokenizer(tokenizer) {
268}
269
270KeyLayoutMap::Parser::~Parser() {
271}
272
273status_t KeyLayoutMap::Parser::parse() {
274 while (!mTokenizer->isEof()) {
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700275 ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().string(),
276 mTokenizer->peekRemainderOfLine().string());
Jeff Brown5912f952013-07-01 19:10:31 -0700277
278 mTokenizer->skipDelimiters(WHITESPACE);
279
280 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
281 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
282 if (keywordToken == "key") {
283 mTokenizer->skipDelimiters(WHITESPACE);
284 status_t status = parseKey();
285 if (status) return status;
286 } else if (keywordToken == "axis") {
287 mTokenizer->skipDelimiters(WHITESPACE);
288 status_t status = parseAxis();
289 if (status) return status;
Michael Wright74bdd2e2013-10-17 17:35:53 -0700290 } else if (keywordToken == "led") {
291 mTokenizer->skipDelimiters(WHITESPACE);
292 status_t status = parseLed();
293 if (status) return status;
Chris Yef59a2f42020-10-16 12:55:26 -0700294 } else if (keywordToken == "sensor") {
295 mTokenizer->skipDelimiters(WHITESPACE);
296 status_t status = parseSensor();
297 if (status) return status;
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700298 } else if (keywordToken == "requires_kernel_config") {
299 mTokenizer->skipDelimiters(WHITESPACE);
300 status_t status = parseRequiredKernelConfig();
301 if (status) return status;
Jeff Brown5912f952013-07-01 19:10:31 -0700302 } else {
303 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
304 keywordToken.string());
305 return BAD_VALUE;
306 }
307
308 mTokenizer->skipDelimiters(WHITESPACE);
309 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
310 ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
311 mTokenizer->getLocation().string(),
312 mTokenizer->peekRemainderOfLine().string());
313 return BAD_VALUE;
314 }
315 }
316
317 mTokenizer->nextLine();
318 }
319 return NO_ERROR;
320}
321
322status_t KeyLayoutMap::Parser::parseKey() {
323 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
324 bool mapUsage = false;
325 if (codeToken == "usage") {
326 mapUsage = true;
327 mTokenizer->skipDelimiters(WHITESPACE);
328 codeToken = mTokenizer->nextToken(WHITESPACE);
329 }
330
331 char* end;
332 int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
333 if (*end) {
334 ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
335 mapUsage ? "usage" : "scan code", codeToken.string());
336 return BAD_VALUE;
337 }
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700338 std::unordered_map<int32_t, Key>& map =
339 mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
340 if (map.find(code) != map.end()) {
Jeff Brown5912f952013-07-01 19:10:31 -0700341 ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
342 mapUsage ? "usage" : "scan code", codeToken.string());
343 return BAD_VALUE;
344 }
345
346 mTokenizer->skipDelimiters(WHITESPACE);
347 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700348 int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700349 if (!keyCode) {
350 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
351 keyCodeToken.string());
352 return BAD_VALUE;
353 }
354
355 uint32_t flags = 0;
356 for (;;) {
357 mTokenizer->skipDelimiters(WHITESPACE);
358 if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break;
359
360 String8 flagToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700361 uint32_t flag = InputEventLookup::getKeyFlagByLabel(flagToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700362 if (!flag) {
363 ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),
364 flagToken.string());
365 return BAD_VALUE;
366 }
367 if (flags & flag) {
368 ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(),
369 flagToken.string());
370 return BAD_VALUE;
371 }
372 flags |= flag;
373 }
374
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700375 ALOGD_IF(DEBUG_PARSER, "Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
376 mapUsage ? "usage" : "scan code", code, keyCode, flags);
377
Jeff Brown5912f952013-07-01 19:10:31 -0700378 Key key;
379 key.keyCode = keyCode;
380 key.flags = flags;
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700381 map.insert({code, key});
Jeff Brown5912f952013-07-01 19:10:31 -0700382 return NO_ERROR;
383}
384
385status_t KeyLayoutMap::Parser::parseAxis() {
386 String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
387 char* end;
388 int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
389 if (*end) {
390 ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(),
391 scanCodeToken.string());
392 return BAD_VALUE;
393 }
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700394 if (mMap->mAxes.find(scanCode) != mMap->mAxes.end()) {
Jeff Brown5912f952013-07-01 19:10:31 -0700395 ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(),
396 scanCodeToken.string());
397 return BAD_VALUE;
398 }
399
400 AxisInfo axisInfo;
401
402 mTokenizer->skipDelimiters(WHITESPACE);
403 String8 token = mTokenizer->nextToken(WHITESPACE);
404 if (token == "invert") {
405 axisInfo.mode = AxisInfo::MODE_INVERT;
406
407 mTokenizer->skipDelimiters(WHITESPACE);
408 String8 axisToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700409 axisInfo.axis = InputEventLookup::getAxisByLabel(axisToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700410 if (axisInfo.axis < 0) {
411 ALOGE("%s: Expected inverted axis label, got '%s'.",
412 mTokenizer->getLocation().string(), axisToken.string());
413 return BAD_VALUE;
414 }
415 } else if (token == "split") {
416 axisInfo.mode = AxisInfo::MODE_SPLIT;
417
418 mTokenizer->skipDelimiters(WHITESPACE);
419 String8 splitToken = mTokenizer->nextToken(WHITESPACE);
420 axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0));
421 if (*end) {
422 ALOGE("%s: Expected split value, got '%s'.",
423 mTokenizer->getLocation().string(), splitToken.string());
424 return BAD_VALUE;
425 }
426
427 mTokenizer->skipDelimiters(WHITESPACE);
428 String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700429 axisInfo.axis = InputEventLookup::getAxisByLabel(lowAxisToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700430 if (axisInfo.axis < 0) {
431 ALOGE("%s: Expected low axis label, got '%s'.",
432 mTokenizer->getLocation().string(), lowAxisToken.string());
433 return BAD_VALUE;
434 }
435
436 mTokenizer->skipDelimiters(WHITESPACE);
437 String8 highAxisToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700438 axisInfo.highAxis = InputEventLookup::getAxisByLabel(highAxisToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700439 if (axisInfo.highAxis < 0) {
440 ALOGE("%s: Expected high axis label, got '%s'.",
441 mTokenizer->getLocation().string(), highAxisToken.string());
442 return BAD_VALUE;
443 }
444 } else {
Chris Ye4958d062020-08-20 13:21:10 -0700445 axisInfo.axis = InputEventLookup::getAxisByLabel(token.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700446 if (axisInfo.axis < 0) {
447 ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.",
448 mTokenizer->getLocation().string(), token.string());
449 return BAD_VALUE;
450 }
451 }
452
453 for (;;) {
454 mTokenizer->skipDelimiters(WHITESPACE);
455 if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') {
456 break;
457 }
458 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
459 if (keywordToken == "flat") {
460 mTokenizer->skipDelimiters(WHITESPACE);
461 String8 flatToken = mTokenizer->nextToken(WHITESPACE);
462 axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0));
463 if (*end) {
464 ALOGE("%s: Expected flat value, got '%s'.",
465 mTokenizer->getLocation().string(), flatToken.string());
466 return BAD_VALUE;
467 }
468 } else {
469 ALOGE("%s: Expected keyword 'flat', got '%s'.",
470 mTokenizer->getLocation().string(), keywordToken.string());
471 return BAD_VALUE;
472 }
473 }
474
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700475 ALOGD_IF(DEBUG_PARSER,
476 "Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
477 "splitValue=%d, flatOverride=%d.",
478 scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue,
479 axisInfo.flatOverride);
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700480 mMap->mAxes.insert({scanCode, axisInfo});
Jeff Brown5912f952013-07-01 19:10:31 -0700481 return NO_ERROR;
482}
483
Michael Wright74bdd2e2013-10-17 17:35:53 -0700484status_t KeyLayoutMap::Parser::parseLed() {
485 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
486 bool mapUsage = false;
487 if (codeToken == "usage") {
488 mapUsage = true;
489 mTokenizer->skipDelimiters(WHITESPACE);
490 codeToken = mTokenizer->nextToken(WHITESPACE);
491 }
492 char* end;
493 int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
494 if (*end) {
495 ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().string(),
496 mapUsage ? "usage" : "scan code", codeToken.string());
497 return BAD_VALUE;
498 }
499
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700500 std::unordered_map<int32_t, Led>& map =
501 mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode;
502 if (map.find(code) != map.end()) {
Michael Wright74bdd2e2013-10-17 17:35:53 -0700503 ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(),
504 mapUsage ? "usage" : "scan code", codeToken.string());
505 return BAD_VALUE;
506 }
507
508 mTokenizer->skipDelimiters(WHITESPACE);
509 String8 ledCodeToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700510 int32_t ledCode = InputEventLookup::getLedByLabel(ledCodeToken.string());
Michael Wright74bdd2e2013-10-17 17:35:53 -0700511 if (ledCode < 0) {
512 ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().string(),
513 ledCodeToken.string());
514 return BAD_VALUE;
515 }
516
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700517 ALOGD_IF(DEBUG_PARSER, "Parsed led %s: code=%d, ledCode=%d.", mapUsage ? "usage" : "scan code",
518 code, ledCode);
Michael Wright74bdd2e2013-10-17 17:35:53 -0700519
520 Led led;
521 led.ledCode = ledCode;
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700522 map.insert({code, led});
Michael Wright74bdd2e2013-10-17 17:35:53 -0700523 return NO_ERROR;
524}
Chris Yef59a2f42020-10-16 12:55:26 -0700525
526static std::optional<InputDeviceSensorType> getSensorType(const char* token) {
Dominik Laskowski75788452021-02-09 18:51:25 -0800527 auto it = SENSOR_LIST.find(token);
Chris Yef59a2f42020-10-16 12:55:26 -0700528 if (it == SENSOR_LIST.end()) {
529 return std::nullopt;
530 }
531 return it->second;
532}
533
534static std::optional<int32_t> getSensorDataIndex(String8 token) {
535 std::string tokenStr(token.string());
536 if (tokenStr == "X") {
537 return 0;
538 } else if (tokenStr == "Y") {
539 return 1;
540 } else if (tokenStr == "Z") {
541 return 2;
542 }
543 return std::nullopt;
544}
545
546// Parse sensor type and data index mapping, as below format
547// sensor <raw abs> <sensor type> <sensor data index>
548// raw abs : the linux abs code of the axis
549// sensor type : string name of InputDeviceSensorType
550// sensor data index : the data index of sensor, out of [X, Y, Z]
551// Examples:
552// sensor 0x00 ACCELEROMETER X
553// sensor 0x01 ACCELEROMETER Y
554// sensor 0x02 ACCELEROMETER Z
555// sensor 0x03 GYROSCOPE X
556// sensor 0x04 GYROSCOPE Y
557// sensor 0x05 GYROSCOPE Z
558status_t KeyLayoutMap::Parser::parseSensor() {
559 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
560 char* end;
561 int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
562 if (*end) {
563 ALOGE("%s: Expected sensor %s number, got '%s'.", mTokenizer->getLocation().string(),
564 "abs code", codeToken.string());
565 return BAD_VALUE;
566 }
567
568 std::unordered_map<int32_t, Sensor>& map = mMap->mSensorsByAbsCode;
569 if (map.find(code) != map.end()) {
570 ALOGE("%s: Duplicate entry for sensor %s '%s'.", mTokenizer->getLocation().string(),
571 "abs code", codeToken.string());
572 return BAD_VALUE;
573 }
574
575 mTokenizer->skipDelimiters(WHITESPACE);
576 String8 sensorTypeToken = mTokenizer->nextToken(WHITESPACE);
577 std::optional<InputDeviceSensorType> typeOpt = getSensorType(sensorTypeToken.string());
578 if (!typeOpt) {
579 ALOGE("%s: Expected sensor code label, got '%s'.", mTokenizer->getLocation().string(),
580 sensorTypeToken.string());
581 return BAD_VALUE;
582 }
583 InputDeviceSensorType sensorType = typeOpt.value();
584 mTokenizer->skipDelimiters(WHITESPACE);
585 String8 sensorDataIndexToken = mTokenizer->nextToken(WHITESPACE);
586 std::optional<int32_t> indexOpt = getSensorDataIndex(sensorDataIndexToken);
587 if (!indexOpt) {
588 ALOGE("%s: Expected sensor data index label, got '%s'.", mTokenizer->getLocation().string(),
589 sensorDataIndexToken.string());
590 return BAD_VALUE;
591 }
592 int32_t sensorDataIndex = indexOpt.value();
593
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700594 ALOGD_IF(DEBUG_PARSER, "Parsed sensor: abs code=%d, sensorType=%s, sensorDataIndex=%d.", code,
595 ftl::enum_string(sensorType).c_str(), sensorDataIndex);
Chris Yef59a2f42020-10-16 12:55:26 -0700596
597 Sensor sensor;
598 sensor.sensorType = sensorType;
599 sensor.sensorDataIndex = sensorDataIndex;
600 map.emplace(code, sensor);
601 return NO_ERROR;
602}
Dominik Laskowski75788452021-02-09 18:51:25 -0800603
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700604// Parse the name of a required kernel config.
605// The layout won't be used if the specified kernel config is not present
606// Examples:
607// requires_kernel_config CONFIG_HID_PLAYSTATION
608status_t KeyLayoutMap::Parser::parseRequiredKernelConfig() {
609 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
610 std::string configName = codeToken.string();
611
612 const auto result = mMap->mRequiredKernelConfigs.emplace(configName);
613 if (!result.second) {
614 ALOGE("%s: Duplicate entry for required kernel config %s.",
615 mTokenizer->getLocation().string(), configName.c_str());
616 return BAD_VALUE;
617 }
618
619 ALOGD_IF(DEBUG_PARSER, "Parsed required kernel config: name=%s", configName.c_str());
620 return NO_ERROR;
621}
622
Dominik Laskowski75788452021-02-09 18:51:25 -0800623} // namespace android