blob: ab8c341b15558b25a7d04c46cea3f2bf9bb7369b [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
Siarhei Vishniakou5df34932023-01-23 12:41:01 -080019#include <android-base/logging.h>
Jeff Brown5912f952013-07-01 19:10:31 -070020#include <android/keycodes.h>
Dominik Laskowski75788452021-02-09 18:51:25 -080021#include <ftl/enum.h>
Michael Wright872db4f2014-04-22 15:03:51 -070022#include <input/InputEventLabels.h>
Jeff Brown5912f952013-07-01 19:10:31 -070023#include <input/KeyLayoutMap.h>
Chris Yef59a2f42020-10-16 12:55:26 -070024#include <input/Keyboard.h>
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -070025#include <log/log.h>
Jeff Brown5912f952013-07-01 19:10:31 -070026#include <utils/Errors.h>
Jeff Brown5912f952013-07-01 19:10:31 -070027#include <utils/Timers.h>
Chris Yef59a2f42020-10-16 12:55:26 -070028#include <utils/Tokenizer.h>
Siarhei Vishniakou8fc145f2022-08-17 16:07:40 -070029#if defined(__ANDROID__)
Jooyung Han3f669212023-12-05 14:18:19 +090030#include <vintf/KernelConfigs.h>
Siarhei Vishniakou8fc145f2022-08-17 16:07:40 -070031#endif
Jeff Brown5912f952013-07-01 19:10:31 -070032
Dominik Laskowski75788452021-02-09 18:51:25 -080033#include <cstdlib>
34#include <string_view>
35#include <unordered_map>
36
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -070037/**
38 * Log debug output for the parser.
39 * Enable this via "adb shell setprop log.tag.KeyLayoutMapParser DEBUG" (requires restart)
40 */
41const bool DEBUG_PARSER =
42 __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Parser", ANDROID_LOG_INFO);
Jeff Brown5912f952013-07-01 19:10:31 -070043
44// Enables debug output for parser performance.
45#define DEBUG_PARSER_PERFORMANCE 0
46
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -070047/**
48 * Log debug output for mapping.
49 * Enable this via "adb shell setprop log.tag.KeyLayoutMapMapping DEBUG" (requires restart)
50 */
51const bool DEBUG_MAPPING =
52 __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Mapping", ANDROID_LOG_INFO);
Jeff Brown5912f952013-07-01 19:10:31 -070053
54namespace android {
Dominik Laskowski75788452021-02-09 18:51:25 -080055namespace {
Jeff Brown5912f952013-07-01 19:10:31 -070056
Siarhei Vishniakou5df34932023-01-23 12:41:01 -080057std::optional<int> parseInt(const char* str) {
58 char* end;
59 errno = 0;
60 const int value = strtol(str, &end, 0);
61 if (end == str) {
62 LOG(ERROR) << "Could not parse " << str;
63 return {};
64 }
65 if (errno == ERANGE) {
66 LOG(ERROR) << "Out of bounds: " << str;
67 return {};
68 }
69 return value;
70}
71
Dominik Laskowski75788452021-02-09 18:51:25 -080072constexpr const char* WHITESPACE = " \t\r";
Jeff Brown5912f952013-07-01 19:10:31 -070073
Dominik Laskowski75788452021-02-09 18:51:25 -080074template <InputDeviceSensorType S>
75constexpr auto sensorPair() {
76 return std::make_pair(ftl::enum_name<S>(), S);
Jeff Brown5912f952013-07-01 19:10:31 -070077}
78
Dominik Laskowski75788452021-02-09 18:51:25 -080079static const std::unordered_map<std::string_view, InputDeviceSensorType> SENSOR_LIST =
80 {sensorPair<InputDeviceSensorType::ACCELEROMETER>(),
81 sensorPair<InputDeviceSensorType::MAGNETIC_FIELD>(),
82 sensorPair<InputDeviceSensorType::ORIENTATION>(),
83 sensorPair<InputDeviceSensorType::GYROSCOPE>(),
84 sensorPair<InputDeviceSensorType::LIGHT>(),
85 sensorPair<InputDeviceSensorType::PRESSURE>(),
86 sensorPair<InputDeviceSensorType::TEMPERATURE>(),
87 sensorPair<InputDeviceSensorType::PROXIMITY>(),
88 sensorPair<InputDeviceSensorType::GRAVITY>(),
89 sensorPair<InputDeviceSensorType::LINEAR_ACCELERATION>(),
90 sensorPair<InputDeviceSensorType::ROTATION_VECTOR>(),
91 sensorPair<InputDeviceSensorType::RELATIVE_HUMIDITY>(),
92 sensorPair<InputDeviceSensorType::AMBIENT_TEMPERATURE>(),
93 sensorPair<InputDeviceSensorType::MAGNETIC_FIELD_UNCALIBRATED>(),
94 sensorPair<InputDeviceSensorType::GAME_ROTATION_VECTOR>(),
95 sensorPair<InputDeviceSensorType::GYROSCOPE_UNCALIBRATED>(),
96 sensorPair<InputDeviceSensorType::SIGNIFICANT_MOTION>()};
97
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -070098bool kernelConfigsArePresent(const std::set<std::string>& configs) {
Siarhei Vishniakou8fc145f2022-08-17 16:07:40 -070099#if defined(__ANDROID__)
Jooyung Han3f669212023-12-05 14:18:19 +0900100 std::map<std::string, std::string> kernelConfigs;
101 const status_t result = android::kernelconfigs::LoadKernelConfigs(&kernelConfigs);
102 LOG_ALWAYS_FATAL_IF(result != OK, "Kernel configs could not be fetched");
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700103
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700104 for (const std::string& requiredConfig : configs) {
105 const auto configIt = kernelConfigs.find(requiredConfig);
106 if (configIt == kernelConfigs.end()) {
107 ALOGI("Required kernel config %s is not found", requiredConfig.c_str());
108 return false;
109 }
110 const std::string& option = configIt->second;
111 if (option != "y" && option != "m") {
112 ALOGI("Required kernel config %s has option %s", requiredConfig.c_str(),
113 option.c_str());
114 return false;
115 }
116 }
117 return true;
Siarhei Vishniakou8fc145f2022-08-17 16:07:40 -0700118#else
119 (void)configs; // Suppress 'unused variable' warning
120 return true;
121#endif
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700122}
123
Dominik Laskowski75788452021-02-09 18:51:25 -0800124} // namespace
125
126KeyLayoutMap::KeyLayoutMap() = default;
127KeyLayoutMap::~KeyLayoutMap() = default;
Jeff Brown5912f952013-07-01 19:10:31 -0700128
Chris Ye1abffbd2020-08-18 12:50:12 -0700129base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::loadContents(const std::string& filename,
130 const char* contents) {
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700131 return load(filename, contents);
Chris Ye1abffbd2020-08-18 12:50:12 -0700132}
Jeff Brown5912f952013-07-01 19:10:31 -0700133
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700134base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::load(const std::string& filename,
135 const char* contents) {
Jeff Brown5912f952013-07-01 19:10:31 -0700136 Tokenizer* tokenizer;
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700137 status_t status;
138 if (contents == nullptr) {
139 status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
140 } else {
141 status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
142 }
Jeff Brown5912f952013-07-01 19:10:31 -0700143 if (status) {
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100144 ALOGE("Error %d opening key layout map file %s.", status, filename.c_str());
Chris Ye1abffbd2020-08-18 12:50:12 -0700145 return Errorf("Error {} opening key layout map file {}.", status, filename.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700146 }
Chris Ye1abffbd2020-08-18 12:50:12 -0700147 std::unique_ptr<Tokenizer> t(tokenizer);
148 auto ret = load(t.get());
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700149 if (!ret.ok()) {
150 return ret;
Chris Ye1abffbd2020-08-18 12:50:12 -0700151 }
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700152 const std::shared_ptr<KeyLayoutMap>& map = *ret;
153 LOG_ALWAYS_FATAL_IF(map == nullptr, "Returned map should not be null if there's no error");
154 if (!kernelConfigsArePresent(map->mRequiredKernelConfigs)) {
155 ALOGI("Not loading %s because the required kernel configs are not set", filename.c_str());
156 return Errorf("Missing kernel config");
157 }
158 map->mLoadFileName = filename;
Chris Ye1abffbd2020-08-18 12:50:12 -0700159 return ret;
160}
161
162base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::load(Tokenizer* tokenizer) {
163 std::shared_ptr<KeyLayoutMap> map = std::shared_ptr<KeyLayoutMap>(new KeyLayoutMap());
164 status_t status = OK;
165 if (!map.get()) {
166 ALOGE("Error allocating key layout map.");
167 return Errorf("Error allocating key layout map.");
168 } else {
169#if DEBUG_PARSER_PERFORMANCE
170 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
171#endif
172 Parser parser(map.get(), tokenizer);
173 status = parser.parse();
174#if DEBUG_PARSER_PERFORMANCE
175 nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
176 ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000177 tokenizer->getFilename().c_str(), tokenizer->getLineNumber(),
Chris Ye1abffbd2020-08-18 12:50:12 -0700178 elapsedTime / 1000000.0);
179#endif
180 if (!status) {
181 return std::move(map);
182 }
183 }
184 return Errorf("Load KeyLayoutMap failed {}.", status);
Jeff Brown5912f952013-07-01 19:10:31 -0700185}
186
187status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t usageCode,
188 int32_t* outKeyCode, uint32_t* outFlags) const {
189 const Key* key = getKey(scanCode, usageCode);
190 if (!key) {
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700191 ALOGD_IF(DEBUG_MAPPING, "mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode,
192 usageCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700193 *outKeyCode = AKEYCODE_UNKNOWN;
194 *outFlags = 0;
195 return NAME_NOT_FOUND;
196 }
197
198 *outKeyCode = key->keyCode;
199 *outFlags = key->flags;
200
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700201 ALOGD_IF(DEBUG_MAPPING,
202 "mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.",
203 scanCode, usageCode, *outKeyCode, *outFlags);
Jeff Brown5912f952013-07-01 19:10:31 -0700204 return NO_ERROR;
205}
206
Chris Yef59a2f42020-10-16 12:55:26 -0700207// Return pair of sensor type and sensor data index, for the input device abs code
Prabir Pradhanae4ff282022-08-23 16:21:39 +0000208base::Result<std::pair<InputDeviceSensorType, int32_t>> KeyLayoutMap::mapSensor(
209 int32_t absCode) const {
Chris Yef59a2f42020-10-16 12:55:26 -0700210 auto it = mSensorsByAbsCode.find(absCode);
211 if (it == mSensorsByAbsCode.end()) {
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700212 ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, ~ Failed.", absCode);
Chris Yef59a2f42020-10-16 12:55:26 -0700213 return Errorf("Can't find abs code {}.", absCode);
214 }
215 const Sensor& sensor = it->second;
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700216 ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, sensorType=%s, sensorDataIndex=0x%x.", absCode,
217 ftl::enum_string(sensor.sensorType).c_str(), sensor.sensorDataIndex);
Chris Yef59a2f42020-10-16 12:55:26 -0700218 return std::make_pair(sensor.sensorType, sensor.sensorDataIndex);
219}
220
Jeff Brown5912f952013-07-01 19:10:31 -0700221const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const {
222 if (usageCode) {
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700223 auto it = mKeysByUsageCode.find(usageCode);
224 if (it != mKeysByUsageCode.end()) {
225 return &it->second;
Jeff Brown5912f952013-07-01 19:10:31 -0700226 }
227 }
228 if (scanCode) {
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700229 auto it = mKeysByScanCode.find(scanCode);
230 if (it != mKeysByScanCode.end()) {
231 return &it->second;
Jeff Brown5912f952013-07-01 19:10:31 -0700232 }
233 }
Yi Kong5bed83b2018-07-17 12:53:47 -0700234 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700235}
236
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700237std::vector<int32_t> KeyLayoutMap::findScanCodesForKey(int32_t keyCode) const {
238 std::vector<int32_t> scanCodes;
239 for (const auto& [scanCode, key] : mKeysByScanCode) {
240 if (keyCode == key.keyCode) {
241 scanCodes.push_back(scanCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700242 }
243 }
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700244 return scanCodes;
Jeff Brown5912f952013-07-01 19:10:31 -0700245}
246
Charles Linaadf8d52023-03-30 13:34:54 +0800247std::vector<int32_t> KeyLayoutMap::findUsageCodesForKey(int32_t keyCode) const {
248 std::vector<int32_t> usageCodes;
249 for (const auto& [usageCode, key] : mKeysByUsageCode) {
Arpit Singhb2aff842023-09-26 10:11:34 +0000250 if (keyCode == key.keyCode && !(key.flags & POLICY_FLAG_FALLBACK_USAGE_MAPPING)) {
Charles Linaadf8d52023-03-30 13:34:54 +0800251 usageCodes.push_back(usageCode);
252 }
253 }
254 return usageCodes;
255}
256
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700257std::optional<AxisInfo> KeyLayoutMap::mapAxis(int32_t scanCode) const {
258 auto it = mAxes.find(scanCode);
259 if (it == mAxes.end()) {
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700260 ALOGD_IF(DEBUG_MAPPING, "mapAxis: scanCode=%d ~ Failed.", scanCode);
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700261 return std::nullopt;
Jeff Brown5912f952013-07-01 19:10:31 -0700262 }
263
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700264 const AxisInfo& axisInfo = it->second;
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700265 ALOGD_IF(DEBUG_MAPPING,
266 "mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
267 "splitValue=%d, flatOverride=%d.",
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700268 scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue,
269 axisInfo.flatOverride);
270 return axisInfo;
Jeff Brown5912f952013-07-01 19:10:31 -0700271}
272
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700273std::optional<int32_t> KeyLayoutMap::findScanCodeForLed(int32_t ledCode) const {
274 for (const auto& [scanCode, led] : mLedsByScanCode) {
275 if (led.ledCode == ledCode) {
276 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d, scanCode=%d.", __func__, ledCode, scanCode);
277 return scanCode;
Michael Wright74bdd2e2013-10-17 17:35:53 -0700278 }
279 }
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700280 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d ~ Not found.", __func__, ledCode);
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700281 return std::nullopt;
Michael Wright74bdd2e2013-10-17 17:35:53 -0700282}
283
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700284std::optional<int32_t> KeyLayoutMap::findUsageCodeForLed(int32_t ledCode) const {
285 for (const auto& [usageCode, led] : mLedsByUsageCode) {
286 if (led.ledCode == ledCode) {
287 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d, usage=%x.", __func__, ledCode, usageCode);
288 return usageCode;
289 }
290 }
291 ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d ~ Not found.", __func__, ledCode);
292 return std::nullopt;
293}
Jeff Brown5912f952013-07-01 19:10:31 -0700294
295// --- KeyLayoutMap::Parser ---
296
297KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
298 mMap(map), mTokenizer(tokenizer) {
299}
300
301KeyLayoutMap::Parser::~Parser() {
302}
303
304status_t KeyLayoutMap::Parser::parse() {
305 while (!mTokenizer->isEof()) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000306 ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().c_str(),
307 mTokenizer->peekRemainderOfLine().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700308
309 mTokenizer->skipDelimiters(WHITESPACE);
310
311 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
312 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
313 if (keywordToken == "key") {
314 mTokenizer->skipDelimiters(WHITESPACE);
315 status_t status = parseKey();
316 if (status) return status;
317 } else if (keywordToken == "axis") {
318 mTokenizer->skipDelimiters(WHITESPACE);
319 status_t status = parseAxis();
320 if (status) return status;
Michael Wright74bdd2e2013-10-17 17:35:53 -0700321 } else if (keywordToken == "led") {
322 mTokenizer->skipDelimiters(WHITESPACE);
323 status_t status = parseLed();
324 if (status) return status;
Chris Yef59a2f42020-10-16 12:55:26 -0700325 } else if (keywordToken == "sensor") {
326 mTokenizer->skipDelimiters(WHITESPACE);
327 status_t status = parseSensor();
328 if (status) return status;
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700329 } else if (keywordToken == "requires_kernel_config") {
330 mTokenizer->skipDelimiters(WHITESPACE);
331 status_t status = parseRequiredKernelConfig();
332 if (status) return status;
Jeff Brown5912f952013-07-01 19:10:31 -0700333 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000334 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().c_str(),
335 keywordToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700336 return BAD_VALUE;
337 }
338
339 mTokenizer->skipDelimiters(WHITESPACE);
340 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
341 ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000342 mTokenizer->getLocation().c_str(), mTokenizer->peekRemainderOfLine().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700343 return BAD_VALUE;
344 }
345 }
346
347 mTokenizer->nextLine();
348 }
349 return NO_ERROR;
350}
351
352status_t KeyLayoutMap::Parser::parseKey() {
353 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
354 bool mapUsage = false;
355 if (codeToken == "usage") {
356 mapUsage = true;
357 mTokenizer->skipDelimiters(WHITESPACE);
358 codeToken = mTokenizer->nextToken(WHITESPACE);
359 }
360
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000361 std::optional<int> code = parseInt(codeToken.c_str());
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800362 if (!code) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000363 ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().c_str(),
364 mapUsage ? "usage" : "scan code", codeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700365 return BAD_VALUE;
366 }
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700367 std::unordered_map<int32_t, Key>& map =
368 mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800369 if (map.find(*code) != map.end()) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000370 ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().c_str(),
371 mapUsage ? "usage" : "scan code", codeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700372 return BAD_VALUE;
373 }
374
375 mTokenizer->skipDelimiters(WHITESPACE);
376 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000377 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700378 if (!keyCode) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000379 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(),
380 keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700381 return BAD_VALUE;
382 }
383
384 uint32_t flags = 0;
385 for (;;) {
386 mTokenizer->skipDelimiters(WHITESPACE);
387 if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break;
388
389 String8 flagToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000390 std::optional<int> flag = InputEventLookup::getKeyFlagByLabel(flagToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700391 if (!flag) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000392 ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().c_str(),
393 flagToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700394 return BAD_VALUE;
395 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800396 if (flags & *flag) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000397 ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().c_str(),
398 flagToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700399 return BAD_VALUE;
400 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800401 flags |= *flag;
Jeff Brown5912f952013-07-01 19:10:31 -0700402 }
403
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700404 ALOGD_IF(DEBUG_PARSER, "Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800405 mapUsage ? "usage" : "scan code", *code, *keyCode, flags);
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700406
Jeff Brown5912f952013-07-01 19:10:31 -0700407 Key key;
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800408 key.keyCode = *keyCode;
Jeff Brown5912f952013-07-01 19:10:31 -0700409 key.flags = flags;
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800410 map.insert({*code, key});
Jeff Brown5912f952013-07-01 19:10:31 -0700411 return NO_ERROR;
412}
413
414status_t KeyLayoutMap::Parser::parseAxis() {
415 String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000416 std::optional<int> scanCode = parseInt(scanCodeToken.c_str());
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800417 if (!scanCode) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000418 ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().c_str(),
419 scanCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700420 return BAD_VALUE;
421 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800422 if (mMap->mAxes.find(*scanCode) != mMap->mAxes.end()) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000423 ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().c_str(),
424 scanCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700425 return BAD_VALUE;
426 }
427
428 AxisInfo axisInfo;
429
430 mTokenizer->skipDelimiters(WHITESPACE);
431 String8 token = mTokenizer->nextToken(WHITESPACE);
432 if (token == "invert") {
433 axisInfo.mode = AxisInfo::MODE_INVERT;
434
435 mTokenizer->skipDelimiters(WHITESPACE);
436 String8 axisToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000437 std::optional<int> axis = InputEventLookup::getAxisByLabel(axisToken.c_str());
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800438 if (!axis) {
Jeff Brown5912f952013-07-01 19:10:31 -0700439 ALOGE("%s: Expected inverted axis label, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000440 mTokenizer->getLocation().c_str(), axisToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700441 return BAD_VALUE;
442 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800443 axisInfo.axis = *axis;
Jeff Brown5912f952013-07-01 19:10:31 -0700444 } else if (token == "split") {
445 axisInfo.mode = AxisInfo::MODE_SPLIT;
446
447 mTokenizer->skipDelimiters(WHITESPACE);
448 String8 splitToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000449 std::optional<int> splitValue = parseInt(splitToken.c_str());
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800450 if (!splitValue) {
Jeff Brown5912f952013-07-01 19:10:31 -0700451 ALOGE("%s: Expected split value, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000452 mTokenizer->getLocation().c_str(), splitToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700453 return BAD_VALUE;
454 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800455 axisInfo.splitValue = *splitValue;
Jeff Brown5912f952013-07-01 19:10:31 -0700456
457 mTokenizer->skipDelimiters(WHITESPACE);
458 String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000459 std::optional<int> axis = InputEventLookup::getAxisByLabel(lowAxisToken.c_str());
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800460 if (!axis) {
Jeff Brown5912f952013-07-01 19:10:31 -0700461 ALOGE("%s: Expected low axis label, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000462 mTokenizer->getLocation().c_str(), lowAxisToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700463 return BAD_VALUE;
464 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800465 axisInfo.axis = *axis;
Jeff Brown5912f952013-07-01 19:10:31 -0700466
467 mTokenizer->skipDelimiters(WHITESPACE);
468 String8 highAxisToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000469 std::optional<int> highAxis = InputEventLookup::getAxisByLabel(highAxisToken.c_str());
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800470 if (!highAxis) {
Jeff Brown5912f952013-07-01 19:10:31 -0700471 ALOGE("%s: Expected high axis label, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000472 mTokenizer->getLocation().c_str(), highAxisToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700473 return BAD_VALUE;
474 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800475 axisInfo.highAxis = *highAxis;
Jeff Brown5912f952013-07-01 19:10:31 -0700476 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000477 std::optional<int> axis = InputEventLookup::getAxisByLabel(token.c_str());
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800478 if (!axis) {
Jeff Brown5912f952013-07-01 19:10:31 -0700479 ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000480 mTokenizer->getLocation().c_str(), token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700481 return BAD_VALUE;
482 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800483 axisInfo.axis = *axis;
Jeff Brown5912f952013-07-01 19:10:31 -0700484 }
485
486 for (;;) {
487 mTokenizer->skipDelimiters(WHITESPACE);
488 if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') {
489 break;
490 }
491 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
492 if (keywordToken == "flat") {
493 mTokenizer->skipDelimiters(WHITESPACE);
494 String8 flatToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000495 std::optional<int> flatOverride = parseInt(flatToken.c_str());
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800496 if (!flatOverride) {
Jeff Brown5912f952013-07-01 19:10:31 -0700497 ALOGE("%s: Expected flat value, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000498 mTokenizer->getLocation().c_str(), flatToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700499 return BAD_VALUE;
500 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800501 axisInfo.flatOverride = *flatOverride;
Jeff Brown5912f952013-07-01 19:10:31 -0700502 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000503 ALOGE("%s: Expected keyword 'flat', got '%s'.", mTokenizer->getLocation().c_str(),
504 keywordToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700505 return BAD_VALUE;
506 }
507 }
508
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700509 ALOGD_IF(DEBUG_PARSER,
510 "Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
511 "splitValue=%d, flatOverride=%d.",
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800512 *scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue,
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700513 axisInfo.flatOverride);
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800514 mMap->mAxes.insert({*scanCode, axisInfo});
Jeff Brown5912f952013-07-01 19:10:31 -0700515 return NO_ERROR;
516}
517
Michael Wright74bdd2e2013-10-17 17:35:53 -0700518status_t KeyLayoutMap::Parser::parseLed() {
519 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
520 bool mapUsage = false;
521 if (codeToken == "usage") {
522 mapUsage = true;
523 mTokenizer->skipDelimiters(WHITESPACE);
524 codeToken = mTokenizer->nextToken(WHITESPACE);
525 }
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000526 std::optional<int> code = parseInt(codeToken.c_str());
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800527 if (!code) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000528 ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().c_str(),
529 mapUsage ? "usage" : "scan code", codeToken.c_str());
Michael Wright74bdd2e2013-10-17 17:35:53 -0700530 return BAD_VALUE;
531 }
532
Siarhei Vishniakouef1564c2022-05-18 09:45:54 -0700533 std::unordered_map<int32_t, Led>& map =
534 mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode;
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800535 if (map.find(*code) != map.end()) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000536 ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().c_str(),
537 mapUsage ? "usage" : "scan code", codeToken.c_str());
Michael Wright74bdd2e2013-10-17 17:35:53 -0700538 return BAD_VALUE;
539 }
540
541 mTokenizer->skipDelimiters(WHITESPACE);
542 String8 ledCodeToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000543 std::optional<int> ledCode = InputEventLookup::getLedByLabel(ledCodeToken.c_str());
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800544 if (!ledCode) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000545 ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().c_str(),
546 ledCodeToken.c_str());
Michael Wright74bdd2e2013-10-17 17:35:53 -0700547 return BAD_VALUE;
548 }
549
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700550 ALOGD_IF(DEBUG_PARSER, "Parsed led %s: code=%d, ledCode=%d.", mapUsage ? "usage" : "scan code",
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800551 *code, *ledCode);
Michael Wright74bdd2e2013-10-17 17:35:53 -0700552
553 Led led;
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800554 led.ledCode = *ledCode;
555 map.insert({*code, led});
Michael Wright74bdd2e2013-10-17 17:35:53 -0700556 return NO_ERROR;
557}
Chris Yef59a2f42020-10-16 12:55:26 -0700558
559static std::optional<InputDeviceSensorType> getSensorType(const char* token) {
Dominik Laskowski75788452021-02-09 18:51:25 -0800560 auto it = SENSOR_LIST.find(token);
Chris Yef59a2f42020-10-16 12:55:26 -0700561 if (it == SENSOR_LIST.end()) {
562 return std::nullopt;
563 }
564 return it->second;
565}
566
567static std::optional<int32_t> getSensorDataIndex(String8 token) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000568 std::string tokenStr(token.c_str());
Chris Yef59a2f42020-10-16 12:55:26 -0700569 if (tokenStr == "X") {
570 return 0;
571 } else if (tokenStr == "Y") {
572 return 1;
573 } else if (tokenStr == "Z") {
574 return 2;
575 }
576 return std::nullopt;
577}
578
579// Parse sensor type and data index mapping, as below format
580// sensor <raw abs> <sensor type> <sensor data index>
581// raw abs : the linux abs code of the axis
582// sensor type : string name of InputDeviceSensorType
583// sensor data index : the data index of sensor, out of [X, Y, Z]
584// Examples:
585// sensor 0x00 ACCELEROMETER X
586// sensor 0x01 ACCELEROMETER Y
587// sensor 0x02 ACCELEROMETER Z
588// sensor 0x03 GYROSCOPE X
589// sensor 0x04 GYROSCOPE Y
590// sensor 0x05 GYROSCOPE Z
591status_t KeyLayoutMap::Parser::parseSensor() {
592 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000593 std::optional<int> code = parseInt(codeToken.c_str());
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800594 if (!code) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000595 ALOGE("%s: Expected sensor %s number, got '%s'.", mTokenizer->getLocation().c_str(),
596 "abs code", codeToken.c_str());
Chris Yef59a2f42020-10-16 12:55:26 -0700597 return BAD_VALUE;
598 }
599
600 std::unordered_map<int32_t, Sensor>& map = mMap->mSensorsByAbsCode;
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800601 if (map.find(*code) != map.end()) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000602 ALOGE("%s: Duplicate entry for sensor %s '%s'.", mTokenizer->getLocation().c_str(),
603 "abs code", codeToken.c_str());
Chris Yef59a2f42020-10-16 12:55:26 -0700604 return BAD_VALUE;
605 }
606
607 mTokenizer->skipDelimiters(WHITESPACE);
608 String8 sensorTypeToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000609 std::optional<InputDeviceSensorType> typeOpt = getSensorType(sensorTypeToken.c_str());
Chris Yef59a2f42020-10-16 12:55:26 -0700610 if (!typeOpt) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000611 ALOGE("%s: Expected sensor code label, got '%s'.", mTokenizer->getLocation().c_str(),
612 sensorTypeToken.c_str());
Chris Yef59a2f42020-10-16 12:55:26 -0700613 return BAD_VALUE;
614 }
615 InputDeviceSensorType sensorType = typeOpt.value();
616 mTokenizer->skipDelimiters(WHITESPACE);
617 String8 sensorDataIndexToken = mTokenizer->nextToken(WHITESPACE);
618 std::optional<int32_t> indexOpt = getSensorDataIndex(sensorDataIndexToken);
619 if (!indexOpt) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000620 ALOGE("%s: Expected sensor data index label, got '%s'.", mTokenizer->getLocation().c_str(),
621 sensorDataIndexToken.c_str());
Chris Yef59a2f42020-10-16 12:55:26 -0700622 return BAD_VALUE;
623 }
624 int32_t sensorDataIndex = indexOpt.value();
625
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800626 ALOGD_IF(DEBUG_PARSER, "Parsed sensor: abs code=%d, sensorType=%s, sensorDataIndex=%d.", *code,
Siarhei Vishniakou5ed8eaa2022-05-18 12:30:16 -0700627 ftl::enum_string(sensorType).c_str(), sensorDataIndex);
Chris Yef59a2f42020-10-16 12:55:26 -0700628
629 Sensor sensor;
630 sensor.sensorType = sensorType;
631 sensor.sensorDataIndex = sensorDataIndex;
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800632 map.emplace(*code, sensor);
Chris Yef59a2f42020-10-16 12:55:26 -0700633 return NO_ERROR;
634}
Dominik Laskowski75788452021-02-09 18:51:25 -0800635
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700636// Parse the name of a required kernel config.
637// The layout won't be used if the specified kernel config is not present
638// Examples:
639// requires_kernel_config CONFIG_HID_PLAYSTATION
640status_t KeyLayoutMap::Parser::parseRequiredKernelConfig() {
641 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000642 std::string configName = codeToken.c_str();
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700643
644 const auto result = mMap->mRequiredKernelConfigs.emplace(configName);
645 if (!result.second) {
646 ALOGE("%s: Duplicate entry for required kernel config %s.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000647 mTokenizer->getLocation().c_str(), configName.c_str());
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700648 return BAD_VALUE;
649 }
650
651 ALOGD_IF(DEBUG_PARSER, "Parsed required kernel config: name=%s", configName.c_str());
652 return NO_ERROR;
653}
654
Dominik Laskowski75788452021-02-09 18:51:25 -0800655} // namespace android