blob: d571917ff995500d971babbe07f8c16ea5c83085 [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 "KeyCharacterMap"
18
19#include <stdlib.h>
20#include <string.h>
21
Brett Chabotfaa986c2020-11-04 17:39:36 -080022#ifdef __linux__
Jeff Brown5912f952013-07-01 19:10:31 -070023#include <binder/Parcel.h>
Brett Chabotfaa986c2020-11-04 17:39:36 -080024#endif
Jeff Brown5912f952013-07-01 19:10:31 -070025#include <android/keycodes.h>
chaviw09c8d2d2020-08-24 15:48:26 -070026#include <attestation/HmacKeyManager.h>
Michael Wright872db4f2014-04-22 15:03:51 -070027#include <input/InputEventLabels.h>
Jeff Brown5912f952013-07-01 19:10:31 -070028#include <input/KeyCharacterMap.h>
chaviw09c8d2d2020-08-24 15:48:26 -070029#include <input/Keyboard.h>
Jeff Brown5912f952013-07-01 19:10:31 -070030
chaviw98318de2021-05-19 16:45:23 -050031#include <gui/constants.h>
Jeff Brown5912f952013-07-01 19:10:31 -070032#include <utils/Errors.h>
chaviw98318de2021-05-19 16:45:23 -050033#include <utils/Log.h>
Jeff Brown5912f952013-07-01 19:10:31 -070034#include <utils/Timers.h>
chaviw98318de2021-05-19 16:45:23 -050035#include <utils/Tokenizer.h>
Jeff Brown5912f952013-07-01 19:10:31 -070036
37// Enables debug output for the parser.
38#define DEBUG_PARSER 0
39
40// Enables debug output for parser performance.
41#define DEBUG_PARSER_PERFORMANCE 0
42
43// Enables debug output for mapping.
44#define DEBUG_MAPPING 0
45
Jeff Brown5912f952013-07-01 19:10:31 -070046namespace android {
47
48static const char* WHITESPACE = " \t\r";
49static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:";
50
51struct Modifier {
52 const char* label;
53 int32_t metaState;
54};
55static const Modifier modifiers[] = {
56 { "shift", AMETA_SHIFT_ON },
57 { "lshift", AMETA_SHIFT_LEFT_ON },
58 { "rshift", AMETA_SHIFT_RIGHT_ON },
59 { "alt", AMETA_ALT_ON },
60 { "lalt", AMETA_ALT_LEFT_ON },
61 { "ralt", AMETA_ALT_RIGHT_ON },
62 { "ctrl", AMETA_CTRL_ON },
63 { "lctrl", AMETA_CTRL_LEFT_ON },
64 { "rctrl", AMETA_CTRL_RIGHT_ON },
65 { "meta", AMETA_META_ON },
66 { "lmeta", AMETA_META_LEFT_ON },
67 { "rmeta", AMETA_META_RIGHT_ON },
68 { "sym", AMETA_SYM_ON },
69 { "fn", AMETA_FUNCTION_ON },
70 { "capslock", AMETA_CAPS_LOCK_ON },
71 { "numlock", AMETA_NUM_LOCK_ON },
72 { "scrolllock", AMETA_SCROLL_LOCK_ON },
73};
74
75#if DEBUG_MAPPING
76static String8 toString(const char16_t* chars, size_t numChars) {
77 String8 result;
78 for (size_t i = 0; i < numChars; i++) {
79 result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]);
80 }
81 return result;
82}
83#endif
84
85
86// --- KeyCharacterMap ---
87
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -070088KeyCharacterMap::KeyCharacterMap(const std::string& filename) : mLoadFileName(filename) {}
Philip Junker90bc9492021-12-10 18:39:42 +010089
Chris Ye3a1e4462020-08-12 10:13:15 -070090base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename,
91 Format format) {
Jeff Brown5912f952013-07-01 19:10:31 -070092 Tokenizer* tokenizer;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +010093 status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
Jeff Brown5912f952013-07-01 19:10:31 -070094 if (status) {
Chris Ye3a1e4462020-08-12 10:13:15 -070095 return Errorf("Error {} opening key character map file {}.", status, filename.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -070096 }
Philip Junker90bc9492021-12-10 18:39:42 +010097 std::shared_ptr<KeyCharacterMap> map =
98 std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
99 if (!map.get()) {
100 ALOGE("Error allocating key character map.");
101 return Errorf("Error allocating key character map.");
Chris Ye3a1e4462020-08-12 10:13:15 -0700102 }
Philip Junker90bc9492021-12-10 18:39:42 +0100103 std::unique_ptr<Tokenizer> t(tokenizer);
104 status = map->load(t.get(), format);
105 if (status == OK) {
106 return map;
107 }
108 return Errorf("Load KeyCharacterMap failed {}.", status);
Jeff Brown5912f952013-07-01 19:10:31 -0700109}
110
Chris Ye3a1e4462020-08-12 10:13:15 -0700111base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::loadContents(
112 const std::string& filename, const char* contents, Format format) {
Jeff Brown5912f952013-07-01 19:10:31 -0700113 Tokenizer* tokenizer;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100114 status_t status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
Jeff Brown5912f952013-07-01 19:10:31 -0700115 if (status) {
116 ALOGE("Error %d opening key character map.", status);
Chris Ye3a1e4462020-08-12 10:13:15 -0700117 return Errorf("Error {} opening key character map.", status);
Jeff Brown5912f952013-07-01 19:10:31 -0700118 }
Philip Junker90bc9492021-12-10 18:39:42 +0100119 std::shared_ptr<KeyCharacterMap> map =
120 std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
Jeff Brown5912f952013-07-01 19:10:31 -0700121 if (!map.get()) {
122 ALOGE("Error allocating key character map.");
Chris Ye3a1e4462020-08-12 10:13:15 -0700123 return Errorf("Error allocating key character map.");
Jeff Brown5912f952013-07-01 19:10:31 -0700124 }
Philip Junker90bc9492021-12-10 18:39:42 +0100125 std::unique_ptr<Tokenizer> t(tokenizer);
126 status = map->load(t.get(), format);
127 if (status == OK) {
128 return map;
129 }
130 return Errorf("Load KeyCharacterMap failed {}.", status);
131}
132
133status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format) {
134 status_t status = OK;
Chris Ye3a1e4462020-08-12 10:13:15 -0700135#if DEBUG_PARSER_PERFORMANCE
136 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
137#endif
Philip Junker90bc9492021-12-10 18:39:42 +0100138 Parser parser(this, tokenizer, format);
Chris Ye3a1e4462020-08-12 10:13:15 -0700139 status = parser.parse();
140#if DEBUG_PARSER_PERFORMANCE
141 nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
142 ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000143 tokenizer->getFilename().c_str(), tokenizer->getLineNumber(), elapsedTime / 1000000.0);
Chris Ye3a1e4462020-08-12 10:13:15 -0700144#endif
Philip Junker90bc9492021-12-10 18:39:42 +0100145 if (status != OK) {
146 ALOGE("Loading KeyCharacterMap failed with status %s", statusToString(status).c_str());
Chris Ye3a1e4462020-08-12 10:13:15 -0700147 }
Philip Junker90bc9492021-12-10 18:39:42 +0100148 return status;
149}
Chris Ye3a1e4462020-08-12 10:13:15 -0700150
Philip Junker90bc9492021-12-10 18:39:42 +0100151void KeyCharacterMap::clear() {
152 mKeysByScanCode.clear();
153 mKeysByUsageCode.clear();
Philip Junker90bc9492021-12-10 18:39:42 +0100154 mKeys.clear();
155 mLayoutOverlayApplied = false;
156 mType = KeyboardType::UNKNOWN;
157}
158
159status_t KeyCharacterMap::reloadBaseFromFile() {
160 clear();
161 Tokenizer* tokenizer;
162 status_t status = Tokenizer::open(String8(mLoadFileName.c_str()), &tokenizer);
163 if (status) {
164 ALOGE("Error %s opening key character map file %s.", statusToString(status).c_str(),
165 mLoadFileName.c_str());
166 return status;
167 }
168 std::unique_ptr<Tokenizer> t(tokenizer);
169 return load(t.get(), KeyCharacterMap::Format::BASE);
Jeff Brown5912f952013-07-01 19:10:31 -0700170}
171
Chris Ye3a1e4462020-08-12 10:13:15 -0700172void KeyCharacterMap::combine(const KeyCharacterMap& overlay) {
Philip Junker90bc9492021-12-10 18:39:42 +0100173 if (mLayoutOverlayApplied) {
174 reloadBaseFromFile();
175 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700176 for (const auto& [keyCode, key] : overlay.mKeys) {
177 mKeys.insert_or_assign(keyCode, key);
Jeff Brown5912f952013-07-01 19:10:31 -0700178 }
179
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700180 for (const auto& [fromScanCode, toAndroidKeyCode] : overlay.mKeysByScanCode) {
181 mKeysByScanCode.insert_or_assign(fromScanCode, toAndroidKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700182 }
183
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700184 for (const auto& [fromHidUsageCode, toAndroidKeyCode] : overlay.mKeysByUsageCode) {
185 mKeysByUsageCode.insert_or_assign(fromHidUsageCode, toAndroidKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700186 }
Philip Junker90bc9492021-12-10 18:39:42 +0100187 mLayoutOverlayApplied = true;
Jeff Brown5912f952013-07-01 19:10:31 -0700188}
189
Vaibhav Devmurari23e8ae92022-12-29 12:07:56 +0000190void KeyCharacterMap::clearLayoutOverlay() {
191 if (mLayoutOverlayApplied) {
192 reloadBaseFromFile();
193 mLayoutOverlayApplied = false;
194 }
195}
196
Michael Wright102936e2020-11-04 03:44:27 +0000197KeyCharacterMap::KeyboardType KeyCharacterMap::getKeyboardType() const {
Jeff Brown5912f952013-07-01 19:10:31 -0700198 return mType;
199}
200
Chris Ye3a1e4462020-08-12 10:13:15 -0700201const std::string KeyCharacterMap::getLoadFileName() const {
202 return mLoadFileName;
203}
204
Jeff Brown5912f952013-07-01 19:10:31 -0700205char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const {
206 char16_t result = 0;
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700207 const Key* key = getKey(keyCode);
208 if (key != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700209 result = key->label;
210 }
211#if DEBUG_MAPPING
212 ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result);
213#endif
214 return result;
215}
216
217char16_t KeyCharacterMap::getNumber(int32_t keyCode) const {
218 char16_t result = 0;
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700219 const Key* key = getKey(keyCode);
220 if (key != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700221 result = key->number;
222 }
223#if DEBUG_MAPPING
224 ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result);
225#endif
226 return result;
227}
228
229char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
230 char16_t result = 0;
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700231 const Behavior* behavior = getKeyBehavior(keyCode, metaState);
232 if (behavior != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700233 result = behavior->character;
234 }
235#if DEBUG_MAPPING
236 ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result);
237#endif
238 return result;
239}
240
241bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState,
242 FallbackAction* outFallbackAction) const {
243 outFallbackAction->keyCode = 0;
244 outFallbackAction->metaState = 0;
245
246 bool result = false;
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700247 const Behavior* behavior = getKeyBehavior(keyCode, metaState);
248 if (behavior != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700249 if (behavior->fallbackKeyCode) {
250 outFallbackAction->keyCode = behavior->fallbackKeyCode;
251 outFallbackAction->metaState = metaState & ~behavior->metaState;
252 result = true;
253 }
254 }
255#if DEBUG_MAPPING
256 ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, "
257 "fallback keyCode=%d, fallback metaState=0x%08x.",
258 keyCode, metaState, result ? "true" : "false",
259 outFallbackAction->keyCode, outFallbackAction->metaState);
260#endif
261 return result;
262}
263
264char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars,
265 int32_t metaState) const {
266 char16_t result = 0;
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700267 const Key* key = getKey(keyCode);
268 if (key != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700269 // Try to find the most general behavior that maps to this character.
270 // For example, the base key behavior will usually be last in the list.
271 // However, if we find a perfect meta state match for one behavior then use that one.
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700272 for (const Behavior& behavior : key->behaviors) {
273 if (behavior.character) {
Jeff Brown5912f952013-07-01 19:10:31 -0700274 for (size_t i = 0; i < numChars; i++) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700275 if (behavior.character == chars[i]) {
276 result = behavior.character;
277 if ((behavior.metaState & metaState) == behavior.metaState) {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700278 // Found exact match!
279 return result;
Jeff Brown5912f952013-07-01 19:10:31 -0700280 }
281 break;
282 }
283 }
284 }
285 }
Jeff Brown5912f952013-07-01 19:10:31 -0700286 }
Jeff Brown5912f952013-07-01 19:10:31 -0700287 return result;
288}
289
290bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
291 Vector<KeyEvent>& outEvents) const {
292 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
293
294 for (size_t i = 0; i < numChars; i++) {
295 int32_t keyCode, metaState;
296 char16_t ch = chars[i];
297 if (!findKey(ch, &keyCode, &metaState)) {
298#if DEBUG_MAPPING
299 ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000300 deviceId, toString(chars, numChars).c_str(), ch);
Jeff Brown5912f952013-07-01 19:10:31 -0700301#endif
302 return false;
303 }
304
305 int32_t currentMetaState = 0;
306 addMetaKeys(outEvents, deviceId, metaState, true, now, &currentMetaState);
307 addKey(outEvents, deviceId, keyCode, currentMetaState, true, now);
308 addKey(outEvents, deviceId, keyCode, currentMetaState, false, now);
309 addMetaKeys(outEvents, deviceId, metaState, false, now, &currentMetaState);
310 }
311#if DEBUG_MAPPING
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000312 ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", deviceId,
313 toString(chars, numChars).c_str(), int32_t(outEvents.size()));
Jeff Brown5912f952013-07-01 19:10:31 -0700314 for (size_t i = 0; i < outEvents.size(); i++) {
315 ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.",
316 outEvents[i].getKeyCode(), outEvents[i].getMetaState(),
317 outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up");
318 }
319#endif
320 return true;
321}
322
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000323void KeyCharacterMap::addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode) {
324 if (fromKeyCode == toKeyCode) {
325 mKeyRemapping.erase(fromKeyCode);
326#if DEBUG_MAPPING
327 ALOGD("addKeyRemapping: Cleared remapping forKeyCode=%d ~ Result Successful.", fromKeyCode);
328#endif
329 return;
330 }
331 mKeyRemapping.insert_or_assign(fromKeyCode, toKeyCode);
332#if DEBUG_MAPPING
333 ALOGD("addKeyRemapping: fromKeyCode=%d, toKeyCode=%d ~ Result Successful.", fromKeyCode,
334 toKeyCode);
335#endif
336}
337
Jeff Brown5912f952013-07-01 19:10:31 -0700338status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
339 if (usageCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000340 const auto it = mKeysByUsageCode.find(usageCode);
341 if (it != mKeysByUsageCode.end()) {
342 *outKeyCode = it->second;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700343#if DEBUG_MAPPING
344 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
345 scanCode, usageCode, *outKeyCode);
346#endif
Jeff Brown5912f952013-07-01 19:10:31 -0700347 return OK;
348 }
349 }
350 if (scanCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000351 const auto it = mKeysByScanCode.find(scanCode);
352 if (it != mKeysByScanCode.end()) {
353 *outKeyCode = it->second;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700354#if DEBUG_MAPPING
355 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
356 scanCode, usageCode, *outKeyCode);
357#endif
Jeff Brown5912f952013-07-01 19:10:31 -0700358 return OK;
359 }
360 }
361
362#if DEBUG_MAPPING
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700363 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700364#endif
365 *outKeyCode = AKEYCODE_UNKNOWN;
366 return NAME_NOT_FOUND;
367}
368
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000369int32_t KeyCharacterMap::applyKeyRemapping(int32_t fromKeyCode) const {
370 int32_t toKeyCode = fromKeyCode;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700371
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000372 const auto it = mKeyRemapping.find(fromKeyCode);
373 if (it != mKeyRemapping.end()) {
374 toKeyCode = it->second;
375 }
376#if DEBUG_MAPPING
377 ALOGD("applyKeyRemapping: keyCode=%d ~ replacement keyCode=%d.", fromKeyCode, toKeyCode);
378#endif
379 return toKeyCode;
380}
381
382std::pair<int32_t, int32_t> KeyCharacterMap::applyKeyBehavior(int32_t fromKeyCode,
383 int32_t fromMetaState) const {
384 int32_t toKeyCode = fromKeyCode;
385 int32_t toMetaState = fromMetaState;
386
387 const Behavior* behavior = getKeyBehavior(fromKeyCode, fromMetaState);
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700388 if (behavior != nullptr) {
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700389 if (behavior->replacementKeyCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000390 toKeyCode = behavior->replacementKeyCode;
391 toMetaState = fromMetaState & ~behavior->metaState;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700392 // Reset dependent meta states.
393 if (behavior->metaState & AMETA_ALT_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000394 toMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700395 }
396 if (behavior->metaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000397 toMetaState &= ~AMETA_ALT_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700398 }
399 if (behavior->metaState & AMETA_CTRL_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000400 toMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700401 }
402 if (behavior->metaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000403 toMetaState &= ~AMETA_CTRL_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700404 }
405 if (behavior->metaState & AMETA_SHIFT_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000406 toMetaState &= ~(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700407 }
408 if (behavior->metaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000409 toMetaState &= ~AMETA_SHIFT_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700410 }
411 // ... and put universal bits back if needed
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000412 toMetaState = normalizeMetaState(toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700413 }
414 }
415
416#if DEBUG_MAPPING
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000417 ALOGD("applyKeyBehavior: keyCode=%d, metaState=0x%08x ~ "
418 "replacement keyCode=%d, replacement metaState=0x%08x.",
419 fromKeyCode, fromMetaState, toKeyCode, toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700420#endif
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000421 return std::make_pair(toKeyCode, toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700422}
423
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700424const KeyCharacterMap::Key* KeyCharacterMap::getKey(int32_t keyCode) const {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700425 auto it = mKeys.find(keyCode);
426 if (it != mKeys.end()) {
427 return &it->second;
Jeff Brown5912f952013-07-01 19:10:31 -0700428 }
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700429 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700430}
431
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700432const KeyCharacterMap::Behavior* KeyCharacterMap::getKeyBehavior(int32_t keyCode,
433 int32_t metaState) const {
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700434 const Key* key = getKey(keyCode);
435 if (key != nullptr) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700436 for (const Behavior& behavior : key->behaviors) {
437 if (matchesMetaState(metaState, behavior.metaState)) {
438 return &behavior;
Jeff Brown5912f952013-07-01 19:10:31 -0700439 }
Jeff Brown5912f952013-07-01 19:10:31 -0700440 }
441 }
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700442 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700443}
444
445bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
446 // Behavior must have at least the set of meta states specified.
447 // And if the key event has CTRL, ALT or META then the behavior must exactly
448 // match those, taking into account that a behavior can specify that it handles
449 // one, both or either of a left/right modifier pair.
450 if ((eventMetaState & behaviorMetaState) == behaviorMetaState) {
451 const int32_t EXACT_META_STATES =
452 AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON
453 | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON
454 | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON;
455 int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES;
456 if (behaviorMetaState & AMETA_CTRL_ON) {
457 unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
458 } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
459 unmatchedMetaState &= ~AMETA_CTRL_ON;
460 }
461 if (behaviorMetaState & AMETA_ALT_ON) {
462 unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
463 } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
464 unmatchedMetaState &= ~AMETA_ALT_ON;
465 }
466 if (behaviorMetaState & AMETA_META_ON) {
467 unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
468 } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
469 unmatchedMetaState &= ~AMETA_META_ON;
470 }
471 return !unmatchedMetaState;
472 }
473 return false;
474}
475
476bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
477 if (!ch) {
478 return false;
479 }
480
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700481 for (const auto& [keyCode, key] : mKeys) {
Jeff Brown5912f952013-07-01 19:10:31 -0700482 // Try to find the most general behavior that maps to this character.
483 // For example, the base key behavior will usually be last in the list.
Yi Kong5bed83b2018-07-17 12:53:47 -0700484 const Behavior* found = nullptr;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700485 for (const Behavior& behavior : key.behaviors) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700486 if (behavior.character == ch) {
487 found = &behavior;
Jeff Brown5912f952013-07-01 19:10:31 -0700488 }
489 }
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700490 if (found != nullptr) {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700491 *outKeyCode = keyCode;
Jeff Brown5912f952013-07-01 19:10:31 -0700492 *outMetaState = found->metaState;
493 return true;
494 }
495 }
496 return false;
497}
498
499void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents,
500 int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
501 outEvents.push();
502 KeyEvent& event = outEvents.editTop();
Garfield Tan4cc839f2020-01-24 11:26:14 -0800503 event.initialize(InputEvent::nextId(), deviceId, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
504 INVALID_HMAC, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 0, keyCode,
505 0, metaState, 0, time, time);
Jeff Brown5912f952013-07-01 19:10:31 -0700506}
507
508void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
509 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
510 int32_t* currentMetaState) {
511 // Add and remove meta keys symmetrically.
512 if (down) {
513 addLockedMetaKey(outEvents, deviceId, metaState, time,
514 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
515 addLockedMetaKey(outEvents, deviceId, metaState, time,
516 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
517 addLockedMetaKey(outEvents, deviceId, metaState, time,
518 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
519
520 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
521 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
522 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
523 AMETA_SHIFT_ON, currentMetaState);
524 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
525 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
526 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
527 AMETA_ALT_ON, currentMetaState);
528 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
529 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
530 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
531 AMETA_CTRL_ON, currentMetaState);
532 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
533 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
534 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
535 AMETA_META_ON, currentMetaState);
536
537 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
538 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
539 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
540 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
541 } else {
542 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
543 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
544 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
545 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
546
547 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
548 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
549 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
550 AMETA_META_ON, currentMetaState);
551 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
552 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
553 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
554 AMETA_CTRL_ON, currentMetaState);
555 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
556 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
557 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
558 AMETA_ALT_ON, currentMetaState);
559 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
560 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
561 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
562 AMETA_SHIFT_ON, currentMetaState);
563
564 addLockedMetaKey(outEvents, deviceId, metaState, time,
565 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
566 addLockedMetaKey(outEvents, deviceId, metaState, time,
567 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
568 addLockedMetaKey(outEvents, deviceId, metaState, time,
569 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
570 }
571}
572
573bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
574 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
575 int32_t keyCode, int32_t keyMetaState,
576 int32_t* currentMetaState) {
577 if ((metaState & keyMetaState) == keyMetaState) {
578 *currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
579 addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
580 return true;
581 }
582 return false;
583}
584
585void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
586 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
587 int32_t leftKeyCode, int32_t leftKeyMetaState,
588 int32_t rightKeyCode, int32_t rightKeyMetaState,
589 int32_t eitherKeyMetaState,
590 int32_t* currentMetaState) {
591 bool specific = false;
592 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
593 leftKeyCode, leftKeyMetaState, currentMetaState);
594 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
595 rightKeyCode, rightKeyMetaState, currentMetaState);
596
597 if (!specific) {
598 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
599 leftKeyCode, eitherKeyMetaState, currentMetaState);
600 }
601}
602
603void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
604 int32_t deviceId, int32_t metaState, nsecs_t time,
605 int32_t keyCode, int32_t keyMetaState,
606 int32_t* currentMetaState) {
607 if ((metaState & keyMetaState) == keyMetaState) {
608 *currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
609 addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
610 *currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
611 addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
612 }
613}
614
Brett Chabotfaa986c2020-11-04 17:39:36 -0800615#ifdef __linux__
Chris Ye3a1e4462020-08-12 10:13:15 -0700616std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
617 if (parcel == nullptr) {
618 ALOGE("%s: Null parcel", __func__);
619 return nullptr;
620 }
Philip Junker90bc9492021-12-10 18:39:42 +0100621 std::string loadFileName = parcel->readCString();
622 std::shared_ptr<KeyCharacterMap> map =
623 std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(loadFileName));
Michael Wright102936e2020-11-04 03:44:27 +0000624 map->mType = static_cast<KeyCharacterMap::KeyboardType>(parcel->readInt32());
Philip Junker90bc9492021-12-10 18:39:42 +0100625 map->mLayoutOverlayApplied = parcel->readBool();
Jeff Brown5912f952013-07-01 19:10:31 -0700626 size_t numKeys = parcel->readInt32();
627 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700628 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700629 }
Michael Wright4c971c02015-10-21 14:38:03 +0100630 if (numKeys > MAX_KEYS) {
Ian Pedowitzd57d9b92016-02-19 08:34:43 +0000631 ALOGE("Too many keys in KeyCharacterMap (%zu > %d)", numKeys, MAX_KEYS);
Yi Kong5bed83b2018-07-17 12:53:47 -0700632 return nullptr;
Michael Wright4c971c02015-10-21 14:38:03 +0100633 }
Jeff Brown5912f952013-07-01 19:10:31 -0700634
635 for (size_t i = 0; i < numKeys; i++) {
636 int32_t keyCode = parcel->readInt32();
637 char16_t label = parcel->readInt32();
638 char16_t number = parcel->readInt32();
639 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700640 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700641 }
642
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700643 Key key{.label = label, .number = number};
Jeff Brown5912f952013-07-01 19:10:31 -0700644 while (parcel->readInt32()) {
645 int32_t metaState = parcel->readInt32();
646 char16_t character = parcel->readInt32();
647 int32_t fallbackKeyCode = parcel->readInt32();
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700648 int32_t replacementKeyCode = parcel->readInt32();
Jeff Brown5912f952013-07-01 19:10:31 -0700649 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700650 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700651 }
652
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700653 key.behaviors.push_back({
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700654 .metaState = metaState,
655 .character = character,
656 .fallbackKeyCode = fallbackKeyCode,
657 .replacementKeyCode = replacementKeyCode,
658 });
Jeff Brown5912f952013-07-01 19:10:31 -0700659 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700660 map->mKeys.emplace(keyCode, std::move(key));
Jeff Brown5912f952013-07-01 19:10:31 -0700661
662 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700663 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700664 }
665 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000666 size_t numKeyRemapping = parcel->readInt32();
667 if (parcel->errorCheck()) {
668 return nullptr;
669 }
670 for (size_t i = 0; i < numKeyRemapping; i++) {
671 int32_t key = parcel->readInt32();
672 int32_t value = parcel->readInt32();
673 map->mKeyRemapping.insert_or_assign(key, value);
674 if (parcel->errorCheck()) {
675 return nullptr;
676 }
677 }
Philip Junker90bc9492021-12-10 18:39:42 +0100678 size_t numKeysByScanCode = parcel->readInt32();
679 if (parcel->errorCheck()) {
680 return nullptr;
681 }
682 for (size_t i = 0; i < numKeysByScanCode; i++) {
683 int32_t key = parcel->readInt32();
684 int32_t value = parcel->readInt32();
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000685 map->mKeysByScanCode.insert_or_assign(key, value);
Philip Junker90bc9492021-12-10 18:39:42 +0100686 if (parcel->errorCheck()) {
687 return nullptr;
688 }
689 }
690 size_t numKeysByUsageCode = parcel->readInt32();
691 if (parcel->errorCheck()) {
692 return nullptr;
693 }
694 for (size_t i = 0; i < numKeysByUsageCode; i++) {
695 int32_t key = parcel->readInt32();
696 int32_t value = parcel->readInt32();
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000697 map->mKeysByUsageCode.insert_or_assign(key, value);
Philip Junker90bc9492021-12-10 18:39:42 +0100698 if (parcel->errorCheck()) {
699 return nullptr;
700 }
701 }
Jeff Brown5912f952013-07-01 19:10:31 -0700702 return map;
703}
704
705void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
Chris Ye3a1e4462020-08-12 10:13:15 -0700706 if (parcel == nullptr) {
707 ALOGE("%s: Null parcel", __func__);
708 return;
709 }
Philip Junker90bc9492021-12-10 18:39:42 +0100710 parcel->writeCString(mLoadFileName.c_str());
Michael Wright102936e2020-11-04 03:44:27 +0000711 parcel->writeInt32(static_cast<int32_t>(mType));
Philip Junker90bc9492021-12-10 18:39:42 +0100712 parcel->writeBool(mLayoutOverlayApplied);
Jeff Brown5912f952013-07-01 19:10:31 -0700713
714 size_t numKeys = mKeys.size();
715 parcel->writeInt32(numKeys);
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700716 for (const auto& [keyCode, key] : mKeys) {
Jeff Brown5912f952013-07-01 19:10:31 -0700717 parcel->writeInt32(keyCode);
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700718 parcel->writeInt32(key.label);
719 parcel->writeInt32(key.number);
720 for (const Behavior& behavior : key.behaviors) {
Jeff Brown5912f952013-07-01 19:10:31 -0700721 parcel->writeInt32(1);
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700722 parcel->writeInt32(behavior.metaState);
723 parcel->writeInt32(behavior.character);
724 parcel->writeInt32(behavior.fallbackKeyCode);
725 parcel->writeInt32(behavior.replacementKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700726 }
727 parcel->writeInt32(0);
728 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000729 size_t numKeyRemapping = mKeyRemapping.size();
730 parcel->writeInt32(numKeyRemapping);
731 for (auto const& [fromAndroidKeyCode, toAndroidKeyCode] : mKeyRemapping) {
732 parcel->writeInt32(fromAndroidKeyCode);
733 parcel->writeInt32(toAndroidKeyCode);
734 }
Philip Junker90bc9492021-12-10 18:39:42 +0100735 size_t numKeysByScanCode = mKeysByScanCode.size();
736 parcel->writeInt32(numKeysByScanCode);
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000737 for (auto const& [fromScanCode, toAndroidKeyCode] : mKeysByScanCode) {
738 parcel->writeInt32(fromScanCode);
739 parcel->writeInt32(toAndroidKeyCode);
Philip Junker90bc9492021-12-10 18:39:42 +0100740 }
741 size_t numKeysByUsageCode = mKeysByUsageCode.size();
742 parcel->writeInt32(numKeysByUsageCode);
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000743 for (auto const& [fromUsageCode, toAndroidKeyCode] : mKeysByUsageCode) {
744 parcel->writeInt32(fromUsageCode);
745 parcel->writeInt32(toAndroidKeyCode);
Philip Junker90bc9492021-12-10 18:39:42 +0100746 }
Jeff Brown5912f952013-07-01 19:10:31 -0700747}
Brett Chabotfaa986c2020-11-04 17:39:36 -0800748#endif // __linux__
Jeff Brown5912f952013-07-01 19:10:31 -0700749
Jeff Brown5912f952013-07-01 19:10:31 -0700750// --- KeyCharacterMap::Parser ---
751
752KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
753 mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
754}
755
Jeff Brown5912f952013-07-01 19:10:31 -0700756status_t KeyCharacterMap::Parser::parse() {
757 while (!mTokenizer->isEof()) {
758#if DEBUG_PARSER
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000759 ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(),
760 mTokenizer->peekRemainderOfLine().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700761#endif
762
763 mTokenizer->skipDelimiters(WHITESPACE);
764
765 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
766 switch (mState) {
767 case STATE_TOP: {
768 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
769 if (keywordToken == "type") {
770 mTokenizer->skipDelimiters(WHITESPACE);
771 status_t status = parseType();
772 if (status) return status;
773 } else if (keywordToken == "map") {
774 mTokenizer->skipDelimiters(WHITESPACE);
775 status_t status = parseMap();
776 if (status) return status;
777 } else if (keywordToken == "key") {
778 mTokenizer->skipDelimiters(WHITESPACE);
779 status_t status = parseKey();
780 if (status) return status;
781 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000782 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().c_str(),
783 keywordToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700784 return BAD_VALUE;
785 }
786 break;
787 }
788
789 case STATE_KEY: {
790 status_t status = parseKeyProperty();
791 if (status) return status;
792 break;
793 }
794 }
795
796 mTokenizer->skipDelimiters(WHITESPACE);
797 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000798 ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
799 mTokenizer->getLocation().c_str(), mTokenizer->peekRemainderOfLine().c_str());
800 return BAD_VALUE;
Jeff Brown5912f952013-07-01 19:10:31 -0700801 }
802 }
803
804 mTokenizer->nextLine();
805 }
806
807 if (mState != STATE_TOP) {
808 ALOGE("%s: Unterminated key description at end of file.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000809 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700810 return BAD_VALUE;
811 }
812
Michael Wright102936e2020-11-04 03:44:27 +0000813 if (mMap->mType == KeyboardType::UNKNOWN) {
Jeff Brown5912f952013-07-01 19:10:31 -0700814 ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000815 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700816 return BAD_VALUE;
817 }
818
Michael Wright102936e2020-11-04 03:44:27 +0000819 if (mFormat == Format::BASE) {
820 if (mMap->mType == KeyboardType::OVERLAY) {
Jeff Brown5912f952013-07-01 19:10:31 -0700821 ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000822 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700823 return BAD_VALUE;
824 }
Michael Wright102936e2020-11-04 03:44:27 +0000825 } else if (mFormat == Format::OVERLAY) {
826 if (mMap->mType != KeyboardType::OVERLAY) {
Jeff Brown5912f952013-07-01 19:10:31 -0700827 ALOGE("%s: Overlay keyboard layout missing required keyboard "
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000828 "'type OVERLAY' declaration.",
829 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700830 return BAD_VALUE;
831 }
832 }
833
834 return NO_ERROR;
835}
836
837status_t KeyCharacterMap::Parser::parseType() {
Michael Wright102936e2020-11-04 03:44:27 +0000838 if (mMap->mType != KeyboardType::UNKNOWN) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000839 ALOGE("%s: Duplicate keyboard 'type' declaration.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700840 return BAD_VALUE;
841 }
842
843 KeyboardType type;
844 String8 typeToken = mTokenizer->nextToken(WHITESPACE);
845 if (typeToken == "NUMERIC") {
Michael Wright102936e2020-11-04 03:44:27 +0000846 type = KeyboardType::NUMERIC;
Jeff Brown5912f952013-07-01 19:10:31 -0700847 } else if (typeToken == "PREDICTIVE") {
Michael Wright102936e2020-11-04 03:44:27 +0000848 type = KeyboardType::PREDICTIVE;
Jeff Brown5912f952013-07-01 19:10:31 -0700849 } else if (typeToken == "ALPHA") {
Michael Wright102936e2020-11-04 03:44:27 +0000850 type = KeyboardType::ALPHA;
Jeff Brown5912f952013-07-01 19:10:31 -0700851 } else if (typeToken == "FULL") {
Michael Wright102936e2020-11-04 03:44:27 +0000852 type = KeyboardType::FULL;
Jeff Brown5912f952013-07-01 19:10:31 -0700853 } else if (typeToken == "SPECIAL_FUNCTION") {
Siarhei Vishniakou61da25a2018-02-15 21:04:49 -0600854 ALOGW("The SPECIAL_FUNCTION type is now declared in the device's IDC file, please set "
855 "the property 'keyboard.specialFunction' to '1' there instead.");
856 // TODO: return BAD_VALUE here in Q
Michael Wright102936e2020-11-04 03:44:27 +0000857 type = KeyboardType::SPECIAL_FUNCTION;
Jeff Brown5912f952013-07-01 19:10:31 -0700858 } else if (typeToken == "OVERLAY") {
Michael Wright102936e2020-11-04 03:44:27 +0000859 type = KeyboardType::OVERLAY;
Jeff Brown5912f952013-07-01 19:10:31 -0700860 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000861 ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().c_str(),
862 typeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700863 return BAD_VALUE;
864 }
865
866#if DEBUG_PARSER
867 ALOGD("Parsed type: type=%d.", type);
868#endif
869 mMap->mType = type;
870 return NO_ERROR;
871}
872
873status_t KeyCharacterMap::Parser::parseMap() {
874 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
875 if (keywordToken == "key") {
876 mTokenizer->skipDelimiters(WHITESPACE);
877 return parseMapKey();
878 }
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000879 ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().c_str(),
880 keywordToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700881 return BAD_VALUE;
882}
883
884status_t KeyCharacterMap::Parser::parseMapKey() {
885 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
886 bool mapUsage = false;
887 if (codeToken == "usage") {
888 mapUsage = true;
889 mTokenizer->skipDelimiters(WHITESPACE);
890 codeToken = mTokenizer->nextToken(WHITESPACE);
891 }
892
893 char* end;
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000894 int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0));
Jeff Brown5912f952013-07-01 19:10:31 -0700895 if (*end) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000896 ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().c_str(),
897 mapUsage ? "usage" : "scan code", codeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700898 return BAD_VALUE;
899 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000900 std::map<int32_t, int32_t>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
901 const auto it = map.find(code);
902 if (it != map.end()) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000903 ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().c_str(),
904 mapUsage ? "usage" : "scan code", codeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700905 return BAD_VALUE;
906 }
907
908 mTokenizer->skipDelimiters(WHITESPACE);
909 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000910 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700911 if (!keyCode) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000912 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(),
913 keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700914 return BAD_VALUE;
915 }
916
917#if DEBUG_PARSER
918 ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
919 mapUsage ? "usage" : "scan code", code, keyCode);
920#endif
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800921 map.insert_or_assign(code, *keyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700922 return NO_ERROR;
923}
924
925status_t KeyCharacterMap::Parser::parseKey() {
926 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000927 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700928 if (!keyCode) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000929 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(),
930 keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700931 return BAD_VALUE;
932 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700933 if (mMap->mKeys.find(*keyCode) != mMap->mKeys.end()) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000934 ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().c_str(),
935 keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700936 return BAD_VALUE;
937 }
938
939 mTokenizer->skipDelimiters(WHITESPACE);
940 String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
941 if (openBraceToken != "{") {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000942 ALOGE("%s: Expected '{' after key code label, got '%s'.", mTokenizer->getLocation().c_str(),
943 openBraceToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700944 return BAD_VALUE;
945 }
946
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800947 ALOGD_IF(DEBUG_PARSER, "Parsed beginning of key: keyCode=%d.", *keyCode);
948 mKeyCode = *keyCode;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700949 mMap->mKeys.emplace(*keyCode, Key{});
Jeff Brown5912f952013-07-01 19:10:31 -0700950 mState = STATE_KEY;
951 return NO_ERROR;
952}
953
954status_t KeyCharacterMap::Parser::parseKeyProperty() {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700955 Key& key = mMap->mKeys[mKeyCode];
Jeff Brown5912f952013-07-01 19:10:31 -0700956 String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
957 if (token == "}") {
958 mState = STATE_TOP;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700959 return finishKey(key);
Jeff Brown5912f952013-07-01 19:10:31 -0700960 }
961
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700962 std::vector<Property> properties;
Jeff Brown5912f952013-07-01 19:10:31 -0700963
964 // Parse all comma-delimited property names up to the first colon.
965 for (;;) {
966 if (token == "label") {
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700967 properties.emplace_back(PROPERTY_LABEL);
Jeff Brown5912f952013-07-01 19:10:31 -0700968 } else if (token == "number") {
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700969 properties.emplace_back(PROPERTY_NUMBER);
Jeff Brown5912f952013-07-01 19:10:31 -0700970 } else {
971 int32_t metaState;
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000972 status_t status = parseModifier(token.c_str(), &metaState);
Jeff Brown5912f952013-07-01 19:10:31 -0700973 if (status) {
974 ALOGE("%s: Expected a property name or modifier, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000975 mTokenizer->getLocation().c_str(), token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700976 return status;
977 }
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700978 properties.emplace_back(PROPERTY_META, metaState);
Jeff Brown5912f952013-07-01 19:10:31 -0700979 }
980
981 mTokenizer->skipDelimiters(WHITESPACE);
982 if (!mTokenizer->isEol()) {
983 char ch = mTokenizer->nextChar();
984 if (ch == ':') {
985 break;
986 } else if (ch == ',') {
987 mTokenizer->skipDelimiters(WHITESPACE);
988 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
989 continue;
990 }
991 }
992
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000993 ALOGE("%s: Expected ',' or ':' after property name.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700994 return BAD_VALUE;
995 }
996
997 // Parse behavior after the colon.
998 mTokenizer->skipDelimiters(WHITESPACE);
999
1000 Behavior behavior;
1001 bool haveCharacter = false;
1002 bool haveFallback = false;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001003 bool haveReplacement = false;
Jeff Brown5912f952013-07-01 19:10:31 -07001004
1005 do {
1006 char ch = mTokenizer->peekChar();
1007 if (ch == '\'') {
1008 char16_t character;
1009 status_t status = parseCharacterLiteral(&character);
1010 if (status || !character) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001011 ALOGE("%s: Invalid character literal for key.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001012 return BAD_VALUE;
1013 }
1014 if (haveCharacter) {
1015 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001016 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001017 return BAD_VALUE;
1018 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001019 if (haveReplacement) {
1020 ALOGE("%s: Cannot combine character literal with replace action.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001021 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001022 return BAD_VALUE;
1023 }
Jeff Brown5912f952013-07-01 19:10:31 -07001024 behavior.character = character;
1025 haveCharacter = true;
1026 } else {
1027 token = mTokenizer->nextToken(WHITESPACE);
1028 if (token == "none") {
1029 if (haveCharacter) {
1030 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001031 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001032 return BAD_VALUE;
1033 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001034 if (haveReplacement) {
1035 ALOGE("%s: Cannot combine 'none' with replace action.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001036 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001037 return BAD_VALUE;
1038 }
Jeff Brown5912f952013-07-01 19:10:31 -07001039 haveCharacter = true;
1040 } else if (token == "fallback") {
1041 mTokenizer->skipDelimiters(WHITESPACE);
1042 token = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001043 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001044 if (!keyCode) {
1045 ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001046 mTokenizer->getLocation().c_str(), token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001047 return BAD_VALUE;
1048 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001049 if (haveFallback || haveReplacement) {
1050 ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001051 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001052 return BAD_VALUE;
1053 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001054 behavior.fallbackKeyCode = *keyCode;
Jeff Brown5912f952013-07-01 19:10:31 -07001055 haveFallback = true;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001056 } else if (token == "replace") {
1057 mTokenizer->skipDelimiters(WHITESPACE);
1058 token = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001059 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001060 if (!keyCode) {
1061 ALOGE("%s: Invalid key code label for replace, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001062 mTokenizer->getLocation().c_str(), token.c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001063 return BAD_VALUE;
1064 }
1065 if (haveCharacter) {
1066 ALOGE("%s: Cannot combine character literal with replace action.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001067 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001068 return BAD_VALUE;
1069 }
1070 if (haveFallback || haveReplacement) {
1071 ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001072 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001073 return BAD_VALUE;
1074 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001075 behavior.replacementKeyCode = *keyCode;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001076 haveReplacement = true;
1077
Jeff Brown5912f952013-07-01 19:10:31 -07001078 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001079 ALOGE("%s: Expected a key behavior after ':'.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001080 return BAD_VALUE;
1081 }
1082 }
1083
1084 mTokenizer->skipDelimiters(WHITESPACE);
1085 } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#');
1086
1087 // Add the behavior.
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -07001088 for (const Property& property : properties) {
Jeff Brown5912f952013-07-01 19:10:31 -07001089 switch (property.property) {
1090 case PROPERTY_LABEL:
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001091 if (key.label) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001092 ALOGE("%s: Duplicate label for key.", mTokenizer->getLocation().c_str());
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001093 return BAD_VALUE;
1094 }
1095 key.label = behavior.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001096#if DEBUG_PARSER
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001097 ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key.label);
Jeff Brown5912f952013-07-01 19:10:31 -07001098#endif
1099 break;
1100 case PROPERTY_NUMBER:
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001101 if (key.number) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001102 ALOGE("%s: Duplicate number for key.", mTokenizer->getLocation().c_str());
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001103 return BAD_VALUE;
Jeff Brown5912f952013-07-01 19:10:31 -07001104 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001105 key.number = behavior.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001106#if DEBUG_PARSER
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001107 ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key.number);
Jeff Brown5912f952013-07-01 19:10:31 -07001108#endif
1109 break;
1110 case PROPERTY_META: {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001111 for (const Behavior& b : key.behaviors) {
1112 if (b.metaState == property.metaState) {
Jeff Brown5912f952013-07-01 19:10:31 -07001113 ALOGE("%s: Duplicate key behavior for modifier.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001114 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001115 return BAD_VALUE;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001116 }
Jeff Brown5912f952013-07-01 19:10:31 -07001117 }
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001118 Behavior newBehavior = behavior;
1119 newBehavior.metaState = property.metaState;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001120 key.behaviors.push_front(newBehavior);
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001121 ALOGD_IF(DEBUG_PARSER,
1122 "Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001123 mKeyCode, key.behaviors.front().metaState, key.behaviors.front().character,
1124 key.behaviors.front().fallbackKeyCode,
1125 key.behaviors.front().replacementKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -07001126 break;
1127 }
1128 }
1129 }
1130 return NO_ERROR;
1131}
1132
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001133status_t KeyCharacterMap::Parser::finishKey(Key& key) {
Jeff Brown5912f952013-07-01 19:10:31 -07001134 // Fill in default number property.
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001135 if (!key.number) {
Jeff Brown5912f952013-07-01 19:10:31 -07001136 char16_t digit = 0;
1137 char16_t symbol = 0;
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001138 for (const Behavior& b : key.behaviors) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001139 char16_t ch = b.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001140 if (ch) {
1141 if (ch >= '0' && ch <= '9') {
1142 digit = ch;
1143 } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
1144 || ch == '-' || ch == '+' || ch == ',' || ch == '.'
1145 || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
1146 symbol = ch;
1147 }
1148 }
1149 }
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001150 key.number = digit ? digit : symbol;
Jeff Brown5912f952013-07-01 19:10:31 -07001151 }
1152 return NO_ERROR;
1153}
1154
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001155status_t KeyCharacterMap::Parser::parseModifier(const std::string& token, int32_t* outMetaState) {
Jeff Brown5912f952013-07-01 19:10:31 -07001156 if (token == "base") {
1157 *outMetaState = 0;
1158 return NO_ERROR;
1159 }
1160
1161 int32_t combinedMeta = 0;
1162
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001163 const char* str = token.c_str();
Jeff Brown5912f952013-07-01 19:10:31 -07001164 const char* start = str;
1165 for (const char* cur = str; ; cur++) {
1166 char ch = *cur;
1167 if (ch == '+' || ch == '\0') {
1168 size_t len = cur - start;
1169 int32_t metaState = 0;
1170 for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
1171 if (strlen(modifiers[i].label) == len
1172 && strncmp(modifiers[i].label, start, len) == 0) {
1173 metaState = modifiers[i].metaState;
1174 break;
1175 }
1176 }
1177 if (!metaState) {
1178 return BAD_VALUE;
1179 }
1180 if (combinedMeta & metaState) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001181 ALOGE("%s: Duplicate modifier combination '%s'.", mTokenizer->getLocation().c_str(),
1182 token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001183 return BAD_VALUE;
1184 }
1185
1186 combinedMeta |= metaState;
1187 start = cur + 1;
1188
1189 if (ch == '\0') {
1190 break;
1191 }
1192 }
1193 }
1194 *outMetaState = combinedMeta;
1195 return NO_ERROR;
1196}
1197
1198status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
1199 char ch = mTokenizer->nextChar();
1200 if (ch != '\'') {
1201 goto Error;
1202 }
1203
1204 ch = mTokenizer->nextChar();
1205 if (ch == '\\') {
1206 // Escape sequence.
1207 ch = mTokenizer->nextChar();
1208 if (ch == 'n') {
1209 *outCharacter = '\n';
1210 } else if (ch == 't') {
1211 *outCharacter = '\t';
1212 } else if (ch == '\\') {
1213 *outCharacter = '\\';
1214 } else if (ch == '\'') {
1215 *outCharacter = '\'';
1216 } else if (ch == '"') {
1217 *outCharacter = '"';
1218 } else if (ch == 'u') {
1219 *outCharacter = 0;
1220 for (int i = 0; i < 4; i++) {
1221 ch = mTokenizer->nextChar();
1222 int digit;
1223 if (ch >= '0' && ch <= '9') {
1224 digit = ch - '0';
1225 } else if (ch >= 'A' && ch <= 'F') {
1226 digit = ch - 'A' + 10;
1227 } else if (ch >= 'a' && ch <= 'f') {
1228 digit = ch - 'a' + 10;
1229 } else {
1230 goto Error;
1231 }
1232 *outCharacter = (*outCharacter << 4) | digit;
1233 }
1234 } else {
1235 goto Error;
1236 }
1237 } else if (ch >= 32 && ch <= 126 && ch != '\'') {
1238 // ASCII literal character.
1239 *outCharacter = ch;
1240 } else {
1241 goto Error;
1242 }
1243
1244 ch = mTokenizer->nextChar();
1245 if (ch != '\'') {
1246 goto Error;
1247 }
1248
1249 // Ensure that we consumed the entire token.
1250 if (mTokenizer->nextToken(WHITESPACE).isEmpty()) {
1251 return NO_ERROR;
1252 }
1253
1254Error:
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001255 ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001256 return BAD_VALUE;
1257}
1258
1259} // namespace android