blob: f75bf410f258f9ee6db3a031a0a3e153db1354f7 [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
Jeff Brown5912f952013-07-01 19:10:31 -070022#include <android/keycodes.h>
chaviw09c8d2d2020-08-24 15:48:26 -070023#include <attestation/HmacKeyManager.h>
Siarhei Vishniakoub58c0c32024-05-10 17:24:06 -070024#include <binder/Parcel.h>
Michael Wright872db4f2014-04-22 15:03:51 -070025#include <input/InputEventLabels.h>
Jeff Brown5912f952013-07-01 19:10:31 -070026#include <input/KeyCharacterMap.h>
chaviw09c8d2d2020-08-24 15:48:26 -070027#include <input/Keyboard.h>
Jeff Brown5912f952013-07-01 19:10:31 -070028
Jeff Brown5912f952013-07-01 19:10:31 -070029#include <utils/Errors.h>
chaviw98318de2021-05-19 16:45:23 -050030#include <utils/Log.h>
Jeff Brown5912f952013-07-01 19:10:31 -070031#include <utils/Timers.h>
chaviw98318de2021-05-19 16:45:23 -050032#include <utils/Tokenizer.h>
Jeff Brown5912f952013-07-01 19:10:31 -070033
34// Enables debug output for the parser.
35#define DEBUG_PARSER 0
36
37// Enables debug output for parser performance.
38#define DEBUG_PARSER_PERFORMANCE 0
39
40// Enables debug output for mapping.
41#define DEBUG_MAPPING 0
42
Jeff Brown5912f952013-07-01 19:10:31 -070043namespace android {
44
45static const char* WHITESPACE = " \t\r";
46static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:";
47
48struct Modifier {
49 const char* label;
50 int32_t metaState;
51};
52static const Modifier modifiers[] = {
53 { "shift", AMETA_SHIFT_ON },
54 { "lshift", AMETA_SHIFT_LEFT_ON },
55 { "rshift", AMETA_SHIFT_RIGHT_ON },
56 { "alt", AMETA_ALT_ON },
57 { "lalt", AMETA_ALT_LEFT_ON },
58 { "ralt", AMETA_ALT_RIGHT_ON },
59 { "ctrl", AMETA_CTRL_ON },
60 { "lctrl", AMETA_CTRL_LEFT_ON },
61 { "rctrl", AMETA_CTRL_RIGHT_ON },
62 { "meta", AMETA_META_ON },
63 { "lmeta", AMETA_META_LEFT_ON },
64 { "rmeta", AMETA_META_RIGHT_ON },
65 { "sym", AMETA_SYM_ON },
66 { "fn", AMETA_FUNCTION_ON },
67 { "capslock", AMETA_CAPS_LOCK_ON },
68 { "numlock", AMETA_NUM_LOCK_ON },
69 { "scrolllock", AMETA_SCROLL_LOCK_ON },
70};
71
72#if DEBUG_MAPPING
73static String8 toString(const char16_t* chars, size_t numChars) {
74 String8 result;
75 for (size_t i = 0; i < numChars; i++) {
76 result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]);
77 }
78 return result;
79}
80#endif
81
82
83// --- KeyCharacterMap ---
84
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -070085KeyCharacterMap::KeyCharacterMap(const std::string& filename) : mLoadFileName(filename) {}
Philip Junker90bc9492021-12-10 18:39:42 +010086
Chris Ye3a1e4462020-08-12 10:13:15 -070087base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename,
88 Format format) {
Jeff Brown5912f952013-07-01 19:10:31 -070089 Tokenizer* tokenizer;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +010090 status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
Jeff Brown5912f952013-07-01 19:10:31 -070091 if (status) {
Chris Ye3a1e4462020-08-12 10:13:15 -070092 return Errorf("Error {} opening key character map file {}.", status, filename.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -070093 }
Philip Junker90bc9492021-12-10 18:39:42 +010094 std::shared_ptr<KeyCharacterMap> map =
95 std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
96 if (!map.get()) {
97 ALOGE("Error allocating key character map.");
98 return Errorf("Error allocating key character map.");
Chris Ye3a1e4462020-08-12 10:13:15 -070099 }
Philip Junker90bc9492021-12-10 18:39:42 +0100100 std::unique_ptr<Tokenizer> t(tokenizer);
101 status = map->load(t.get(), format);
102 if (status == OK) {
103 return map;
104 }
105 return Errorf("Load KeyCharacterMap failed {}.", status);
Jeff Brown5912f952013-07-01 19:10:31 -0700106}
107
Chris Ye3a1e4462020-08-12 10:13:15 -0700108base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::loadContents(
109 const std::string& filename, const char* contents, Format format) {
Jeff Brown5912f952013-07-01 19:10:31 -0700110 Tokenizer* tokenizer;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100111 status_t status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
Jeff Brown5912f952013-07-01 19:10:31 -0700112 if (status) {
113 ALOGE("Error %d opening key character map.", status);
Chris Ye3a1e4462020-08-12 10:13:15 -0700114 return Errorf("Error {} opening key character map.", status);
Jeff Brown5912f952013-07-01 19:10:31 -0700115 }
Philip Junker90bc9492021-12-10 18:39:42 +0100116 std::shared_ptr<KeyCharacterMap> map =
117 std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
Jeff Brown5912f952013-07-01 19:10:31 -0700118 if (!map.get()) {
119 ALOGE("Error allocating key character map.");
Chris Ye3a1e4462020-08-12 10:13:15 -0700120 return Errorf("Error allocating key character map.");
Jeff Brown5912f952013-07-01 19:10:31 -0700121 }
Philip Junker90bc9492021-12-10 18:39:42 +0100122 std::unique_ptr<Tokenizer> t(tokenizer);
123 status = map->load(t.get(), format);
124 if (status == OK) {
125 return map;
126 }
127 return Errorf("Load KeyCharacterMap failed {}.", status);
128}
129
130status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format) {
131 status_t status = OK;
Chris Ye3a1e4462020-08-12 10:13:15 -0700132#if DEBUG_PARSER_PERFORMANCE
133 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
134#endif
Philip Junker90bc9492021-12-10 18:39:42 +0100135 Parser parser(this, tokenizer, format);
Chris Ye3a1e4462020-08-12 10:13:15 -0700136 status = parser.parse();
137#if DEBUG_PARSER_PERFORMANCE
138 nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
139 ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000140 tokenizer->getFilename().c_str(), tokenizer->getLineNumber(), elapsedTime / 1000000.0);
Chris Ye3a1e4462020-08-12 10:13:15 -0700141#endif
Philip Junker90bc9492021-12-10 18:39:42 +0100142 if (status != OK) {
143 ALOGE("Loading KeyCharacterMap failed with status %s", statusToString(status).c_str());
Chris Ye3a1e4462020-08-12 10:13:15 -0700144 }
Philip Junker90bc9492021-12-10 18:39:42 +0100145 return status;
146}
Chris Ye3a1e4462020-08-12 10:13:15 -0700147
Philip Junker90bc9492021-12-10 18:39:42 +0100148void KeyCharacterMap::clear() {
149 mKeysByScanCode.clear();
150 mKeysByUsageCode.clear();
Philip Junker90bc9492021-12-10 18:39:42 +0100151 mKeys.clear();
152 mLayoutOverlayApplied = false;
153 mType = KeyboardType::UNKNOWN;
154}
155
156status_t KeyCharacterMap::reloadBaseFromFile() {
157 clear();
158 Tokenizer* tokenizer;
159 status_t status = Tokenizer::open(String8(mLoadFileName.c_str()), &tokenizer);
160 if (status) {
161 ALOGE("Error %s opening key character map file %s.", statusToString(status).c_str(),
162 mLoadFileName.c_str());
163 return status;
164 }
165 std::unique_ptr<Tokenizer> t(tokenizer);
166 return load(t.get(), KeyCharacterMap::Format::BASE);
Jeff Brown5912f952013-07-01 19:10:31 -0700167}
168
Chris Ye3a1e4462020-08-12 10:13:15 -0700169void KeyCharacterMap::combine(const KeyCharacterMap& overlay) {
Philip Junker90bc9492021-12-10 18:39:42 +0100170 if (mLayoutOverlayApplied) {
171 reloadBaseFromFile();
172 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700173 for (const auto& [keyCode, key] : overlay.mKeys) {
174 mKeys.insert_or_assign(keyCode, key);
Jeff Brown5912f952013-07-01 19:10:31 -0700175 }
176
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700177 for (const auto& [fromScanCode, toAndroidKeyCode] : overlay.mKeysByScanCode) {
178 mKeysByScanCode.insert_or_assign(fromScanCode, toAndroidKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700179 }
180
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700181 for (const auto& [fromHidUsageCode, toAndroidKeyCode] : overlay.mKeysByUsageCode) {
182 mKeysByUsageCode.insert_or_assign(fromHidUsageCode, toAndroidKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700183 }
Philip Junker90bc9492021-12-10 18:39:42 +0100184 mLayoutOverlayApplied = true;
Jeff Brown5912f952013-07-01 19:10:31 -0700185}
186
Vaibhav Devmurari23e8ae92022-12-29 12:07:56 +0000187void KeyCharacterMap::clearLayoutOverlay() {
188 if (mLayoutOverlayApplied) {
189 reloadBaseFromFile();
190 mLayoutOverlayApplied = false;
191 }
192}
193
Michael Wright102936e2020-11-04 03:44:27 +0000194KeyCharacterMap::KeyboardType KeyCharacterMap::getKeyboardType() const {
Jeff Brown5912f952013-07-01 19:10:31 -0700195 return mType;
196}
197
Chris Ye3a1e4462020-08-12 10:13:15 -0700198const std::string KeyCharacterMap::getLoadFileName() const {
199 return mLoadFileName;
200}
201
Jeff Brown5912f952013-07-01 19:10:31 -0700202char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const {
203 char16_t result = 0;
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700204 const Key* key = getKey(keyCode);
205 if (key != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700206 result = key->label;
207 }
208#if DEBUG_MAPPING
209 ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result);
210#endif
211 return result;
212}
213
214char16_t KeyCharacterMap::getNumber(int32_t keyCode) const {
215 char16_t result = 0;
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700216 const Key* key = getKey(keyCode);
217 if (key != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700218 result = key->number;
219 }
220#if DEBUG_MAPPING
221 ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result);
222#endif
223 return result;
224}
225
226char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
227 char16_t result = 0;
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700228 const Behavior* behavior = getKeyBehavior(keyCode, metaState);
229 if (behavior != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700230 result = behavior->character;
231 }
232#if DEBUG_MAPPING
233 ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result);
234#endif
235 return result;
236}
237
238bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState,
239 FallbackAction* outFallbackAction) const {
240 outFallbackAction->keyCode = 0;
241 outFallbackAction->metaState = 0;
242
243 bool result = false;
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700244 const Behavior* behavior = getKeyBehavior(keyCode, metaState);
245 if (behavior != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700246 if (behavior->fallbackKeyCode) {
247 outFallbackAction->keyCode = behavior->fallbackKeyCode;
248 outFallbackAction->metaState = metaState & ~behavior->metaState;
249 result = true;
250 }
251 }
252#if DEBUG_MAPPING
253 ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, "
254 "fallback keyCode=%d, fallback metaState=0x%08x.",
255 keyCode, metaState, result ? "true" : "false",
256 outFallbackAction->keyCode, outFallbackAction->metaState);
257#endif
258 return result;
259}
260
261char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars,
262 int32_t metaState) const {
263 char16_t result = 0;
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700264 const Key* key = getKey(keyCode);
265 if (key != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700266 // Try to find the most general behavior that maps to this character.
267 // For example, the base key behavior will usually be last in the list.
268 // However, if we find a perfect meta state match for one behavior then use that one.
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700269 for (const Behavior& behavior : key->behaviors) {
270 if (behavior.character) {
Jeff Brown5912f952013-07-01 19:10:31 -0700271 for (size_t i = 0; i < numChars; i++) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700272 if (behavior.character == chars[i]) {
273 result = behavior.character;
274 if ((behavior.metaState & metaState) == behavior.metaState) {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700275 // Found exact match!
276 return result;
Jeff Brown5912f952013-07-01 19:10:31 -0700277 }
278 break;
279 }
280 }
281 }
282 }
Jeff Brown5912f952013-07-01 19:10:31 -0700283 }
Jeff Brown5912f952013-07-01 19:10:31 -0700284 return result;
285}
286
287bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
288 Vector<KeyEvent>& outEvents) const {
289 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
290
291 for (size_t i = 0; i < numChars; i++) {
292 int32_t keyCode, metaState;
293 char16_t ch = chars[i];
294 if (!findKey(ch, &keyCode, &metaState)) {
295#if DEBUG_MAPPING
296 ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000297 deviceId, toString(chars, numChars).c_str(), ch);
Jeff Brown5912f952013-07-01 19:10:31 -0700298#endif
299 return false;
300 }
301
302 int32_t currentMetaState = 0;
303 addMetaKeys(outEvents, deviceId, metaState, true, now, &currentMetaState);
304 addKey(outEvents, deviceId, keyCode, currentMetaState, true, now);
305 addKey(outEvents, deviceId, keyCode, currentMetaState, false, now);
306 addMetaKeys(outEvents, deviceId, metaState, false, now, &currentMetaState);
307 }
308#if DEBUG_MAPPING
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000309 ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", deviceId,
310 toString(chars, numChars).c_str(), int32_t(outEvents.size()));
Jeff Brown5912f952013-07-01 19:10:31 -0700311 for (size_t i = 0; i < outEvents.size(); i++) {
312 ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.",
313 outEvents[i].getKeyCode(), outEvents[i].getMetaState(),
314 outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up");
315 }
316#endif
317 return true;
318}
319
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000320void KeyCharacterMap::addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode) {
321 if (fromKeyCode == toKeyCode) {
322 mKeyRemapping.erase(fromKeyCode);
323#if DEBUG_MAPPING
324 ALOGD("addKeyRemapping: Cleared remapping forKeyCode=%d ~ Result Successful.", fromKeyCode);
325#endif
326 return;
327 }
328 mKeyRemapping.insert_or_assign(fromKeyCode, toKeyCode);
329#if DEBUG_MAPPING
330 ALOGD("addKeyRemapping: fromKeyCode=%d, toKeyCode=%d ~ Result Successful.", fromKeyCode,
331 toKeyCode);
332#endif
333}
334
Jeff Brown5912f952013-07-01 19:10:31 -0700335status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
336 if (usageCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000337 const auto it = mKeysByUsageCode.find(usageCode);
338 if (it != mKeysByUsageCode.end()) {
339 *outKeyCode = it->second;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700340#if DEBUG_MAPPING
341 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
342 scanCode, usageCode, *outKeyCode);
343#endif
Jeff Brown5912f952013-07-01 19:10:31 -0700344 return OK;
345 }
346 }
347 if (scanCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000348 const auto it = mKeysByScanCode.find(scanCode);
349 if (it != mKeysByScanCode.end()) {
350 *outKeyCode = it->second;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700351#if DEBUG_MAPPING
352 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
353 scanCode, usageCode, *outKeyCode);
354#endif
Jeff Brown5912f952013-07-01 19:10:31 -0700355 return OK;
356 }
357 }
358
359#if DEBUG_MAPPING
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700360 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700361#endif
362 *outKeyCode = AKEYCODE_UNKNOWN;
363 return NAME_NOT_FOUND;
364}
365
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000366int32_t KeyCharacterMap::applyKeyRemapping(int32_t fromKeyCode) const {
367 int32_t toKeyCode = fromKeyCode;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700368
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000369 const auto it = mKeyRemapping.find(fromKeyCode);
370 if (it != mKeyRemapping.end()) {
371 toKeyCode = it->second;
372 }
373#if DEBUG_MAPPING
374 ALOGD("applyKeyRemapping: keyCode=%d ~ replacement keyCode=%d.", fromKeyCode, toKeyCode);
375#endif
376 return toKeyCode;
377}
378
379std::pair<int32_t, int32_t> KeyCharacterMap::applyKeyBehavior(int32_t fromKeyCode,
380 int32_t fromMetaState) const {
381 int32_t toKeyCode = fromKeyCode;
382 int32_t toMetaState = fromMetaState;
383
384 const Behavior* behavior = getKeyBehavior(fromKeyCode, fromMetaState);
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700385 if (behavior != nullptr) {
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700386 if (behavior->replacementKeyCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000387 toKeyCode = behavior->replacementKeyCode;
388 toMetaState = fromMetaState & ~behavior->metaState;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700389 // Reset dependent meta states.
390 if (behavior->metaState & AMETA_ALT_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000391 toMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700392 }
393 if (behavior->metaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000394 toMetaState &= ~AMETA_ALT_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700395 }
396 if (behavior->metaState & AMETA_CTRL_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000397 toMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700398 }
399 if (behavior->metaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000400 toMetaState &= ~AMETA_CTRL_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700401 }
402 if (behavior->metaState & AMETA_SHIFT_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000403 toMetaState &= ~(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700404 }
405 if (behavior->metaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000406 toMetaState &= ~AMETA_SHIFT_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700407 }
408 // ... and put universal bits back if needed
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000409 toMetaState = normalizeMetaState(toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700410 }
411 }
412
413#if DEBUG_MAPPING
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000414 ALOGD("applyKeyBehavior: keyCode=%d, metaState=0x%08x ~ "
415 "replacement keyCode=%d, replacement metaState=0x%08x.",
416 fromKeyCode, fromMetaState, toKeyCode, toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700417#endif
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000418 return std::make_pair(toKeyCode, toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700419}
420
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700421const KeyCharacterMap::Key* KeyCharacterMap::getKey(int32_t keyCode) const {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700422 auto it = mKeys.find(keyCode);
423 if (it != mKeys.end()) {
424 return &it->second;
Jeff Brown5912f952013-07-01 19:10:31 -0700425 }
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700426 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700427}
428
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700429const KeyCharacterMap::Behavior* KeyCharacterMap::getKeyBehavior(int32_t keyCode,
430 int32_t metaState) const {
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700431 const Key* key = getKey(keyCode);
432 if (key != nullptr) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700433 for (const Behavior& behavior : key->behaviors) {
434 if (matchesMetaState(metaState, behavior.metaState)) {
435 return &behavior;
Jeff Brown5912f952013-07-01 19:10:31 -0700436 }
Jeff Brown5912f952013-07-01 19:10:31 -0700437 }
438 }
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700439 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700440}
441
442bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
443 // Behavior must have at least the set of meta states specified.
444 // And if the key event has CTRL, ALT or META then the behavior must exactly
445 // match those, taking into account that a behavior can specify that it handles
446 // one, both or either of a left/right modifier pair.
447 if ((eventMetaState & behaviorMetaState) == behaviorMetaState) {
448 const int32_t EXACT_META_STATES =
449 AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON
450 | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON
451 | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON;
452 int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES;
453 if (behaviorMetaState & AMETA_CTRL_ON) {
454 unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
455 } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
456 unmatchedMetaState &= ~AMETA_CTRL_ON;
457 }
458 if (behaviorMetaState & AMETA_ALT_ON) {
459 unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
460 } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
461 unmatchedMetaState &= ~AMETA_ALT_ON;
462 }
463 if (behaviorMetaState & AMETA_META_ON) {
464 unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
465 } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
466 unmatchedMetaState &= ~AMETA_META_ON;
467 }
468 return !unmatchedMetaState;
469 }
470 return false;
471}
472
473bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
474 if (!ch) {
475 return false;
476 }
477
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700478 for (const auto& [keyCode, key] : mKeys) {
Jeff Brown5912f952013-07-01 19:10:31 -0700479 // Try to find the most general behavior that maps to this character.
480 // For example, the base key behavior will usually be last in the list.
Yi Kong5bed83b2018-07-17 12:53:47 -0700481 const Behavior* found = nullptr;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700482 for (const Behavior& behavior : key.behaviors) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700483 if (behavior.character == ch) {
484 found = &behavior;
Jeff Brown5912f952013-07-01 19:10:31 -0700485 }
486 }
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700487 if (found != nullptr) {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700488 *outKeyCode = keyCode;
Jeff Brown5912f952013-07-01 19:10:31 -0700489 *outMetaState = found->metaState;
490 return true;
491 }
492 }
493 return false;
494}
495
Linnan Li13bf76a2024-05-05 19:18:02 +0800496void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents, int32_t deviceId, int32_t keyCode,
497 int32_t metaState, bool down, nsecs_t time) {
Jeff Brown5912f952013-07-01 19:10:31 -0700498 outEvents.push();
499 KeyEvent& event = outEvents.editTop();
Linnan Li13bf76a2024-05-05 19:18:02 +0800500 event.initialize(InputEvent::nextId(), deviceId, AINPUT_SOURCE_KEYBOARD, ui::ADISPLAY_ID_NONE,
Garfield Tan4cc839f2020-01-24 11:26:14 -0800501 INVALID_HMAC, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 0, keyCode,
502 0, metaState, 0, time, time);
Jeff Brown5912f952013-07-01 19:10:31 -0700503}
504
505void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
506 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
507 int32_t* currentMetaState) {
508 // Add and remove meta keys symmetrically.
509 if (down) {
510 addLockedMetaKey(outEvents, deviceId, metaState, time,
511 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
512 addLockedMetaKey(outEvents, deviceId, metaState, time,
513 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
514 addLockedMetaKey(outEvents, deviceId, metaState, time,
515 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
516
517 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
518 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
519 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
520 AMETA_SHIFT_ON, currentMetaState);
521 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
522 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
523 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
524 AMETA_ALT_ON, currentMetaState);
525 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
526 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
527 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
528 AMETA_CTRL_ON, currentMetaState);
529 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
530 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
531 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
532 AMETA_META_ON, currentMetaState);
533
534 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
535 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
536 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
537 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
538 } else {
539 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
540 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
541 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
542 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
543
544 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
545 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
546 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
547 AMETA_META_ON, currentMetaState);
548 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
549 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
550 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
551 AMETA_CTRL_ON, currentMetaState);
552 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
553 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
554 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
555 AMETA_ALT_ON, currentMetaState);
556 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
557 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
558 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
559 AMETA_SHIFT_ON, currentMetaState);
560
561 addLockedMetaKey(outEvents, deviceId, metaState, time,
562 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
563 addLockedMetaKey(outEvents, deviceId, metaState, time,
564 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
565 addLockedMetaKey(outEvents, deviceId, metaState, time,
566 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
567 }
568}
569
570bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
571 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
572 int32_t keyCode, int32_t keyMetaState,
573 int32_t* currentMetaState) {
574 if ((metaState & keyMetaState) == keyMetaState) {
575 *currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
576 addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
577 return true;
578 }
579 return false;
580}
581
582void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
583 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
584 int32_t leftKeyCode, int32_t leftKeyMetaState,
585 int32_t rightKeyCode, int32_t rightKeyMetaState,
586 int32_t eitherKeyMetaState,
587 int32_t* currentMetaState) {
588 bool specific = false;
589 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
590 leftKeyCode, leftKeyMetaState, currentMetaState);
591 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
592 rightKeyCode, rightKeyMetaState, currentMetaState);
593
594 if (!specific) {
595 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
596 leftKeyCode, eitherKeyMetaState, currentMetaState);
597 }
598}
599
600void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
601 int32_t deviceId, int32_t metaState, nsecs_t time,
602 int32_t keyCode, int32_t keyMetaState,
603 int32_t* currentMetaState) {
604 if ((metaState & keyMetaState) == keyMetaState) {
605 *currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
606 addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
607 *currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
608 addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
609 }
610}
611
Siarhei Vishniakouc62948e2023-10-23 07:22:01 -0700612std::unique_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
Chris Ye3a1e4462020-08-12 10:13:15 -0700613 if (parcel == nullptr) {
614 ALOGE("%s: Null parcel", __func__);
615 return nullptr;
616 }
Philip Junker90bc9492021-12-10 18:39:42 +0100617 std::string loadFileName = parcel->readCString();
Siarhei Vishniakouc62948e2023-10-23 07:22:01 -0700618 std::unique_ptr<KeyCharacterMap> map =
619 std::make_unique<KeyCharacterMap>(KeyCharacterMap(loadFileName));
Michael Wright102936e2020-11-04 03:44:27 +0000620 map->mType = static_cast<KeyCharacterMap::KeyboardType>(parcel->readInt32());
Philip Junker90bc9492021-12-10 18:39:42 +0100621 map->mLayoutOverlayApplied = parcel->readBool();
Jeff Brown5912f952013-07-01 19:10:31 -0700622 size_t numKeys = parcel->readInt32();
623 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700624 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700625 }
Michael Wright4c971c02015-10-21 14:38:03 +0100626 if (numKeys > MAX_KEYS) {
Ian Pedowitzd57d9b92016-02-19 08:34:43 +0000627 ALOGE("Too many keys in KeyCharacterMap (%zu > %d)", numKeys, MAX_KEYS);
Yi Kong5bed83b2018-07-17 12:53:47 -0700628 return nullptr;
Michael Wright4c971c02015-10-21 14:38:03 +0100629 }
Jeff Brown5912f952013-07-01 19:10:31 -0700630
631 for (size_t i = 0; i < numKeys; i++) {
632 int32_t keyCode = parcel->readInt32();
633 char16_t label = parcel->readInt32();
634 char16_t number = parcel->readInt32();
635 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700636 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700637 }
638
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700639 Key key{.label = label, .number = number};
Jeff Brown5912f952013-07-01 19:10:31 -0700640 while (parcel->readInt32()) {
641 int32_t metaState = parcel->readInt32();
642 char16_t character = parcel->readInt32();
643 int32_t fallbackKeyCode = parcel->readInt32();
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700644 int32_t replacementKeyCode = parcel->readInt32();
Jeff Brown5912f952013-07-01 19:10:31 -0700645 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700646 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700647 }
648
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700649 key.behaviors.push_back({
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700650 .metaState = metaState,
651 .character = character,
652 .fallbackKeyCode = fallbackKeyCode,
653 .replacementKeyCode = replacementKeyCode,
654 });
Jeff Brown5912f952013-07-01 19:10:31 -0700655 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700656 map->mKeys.emplace(keyCode, std::move(key));
Jeff Brown5912f952013-07-01 19:10:31 -0700657
658 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700659 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700660 }
661 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000662 size_t numKeyRemapping = parcel->readInt32();
663 if (parcel->errorCheck()) {
664 return nullptr;
665 }
666 for (size_t i = 0; i < numKeyRemapping; i++) {
667 int32_t key = parcel->readInt32();
668 int32_t value = parcel->readInt32();
669 map->mKeyRemapping.insert_or_assign(key, value);
670 if (parcel->errorCheck()) {
671 return nullptr;
672 }
673 }
Philip Junker90bc9492021-12-10 18:39:42 +0100674 size_t numKeysByScanCode = parcel->readInt32();
675 if (parcel->errorCheck()) {
676 return nullptr;
677 }
678 for (size_t i = 0; i < numKeysByScanCode; i++) {
679 int32_t key = parcel->readInt32();
680 int32_t value = parcel->readInt32();
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000681 map->mKeysByScanCode.insert_or_assign(key, value);
Philip Junker90bc9492021-12-10 18:39:42 +0100682 if (parcel->errorCheck()) {
683 return nullptr;
684 }
685 }
686 size_t numKeysByUsageCode = parcel->readInt32();
687 if (parcel->errorCheck()) {
688 return nullptr;
689 }
690 for (size_t i = 0; i < numKeysByUsageCode; i++) {
691 int32_t key = parcel->readInt32();
692 int32_t value = parcel->readInt32();
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000693 map->mKeysByUsageCode.insert_or_assign(key, value);
Philip Junker90bc9492021-12-10 18:39:42 +0100694 if (parcel->errorCheck()) {
695 return nullptr;
696 }
697 }
Jeff Brown5912f952013-07-01 19:10:31 -0700698 return map;
699}
700
701void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
Chris Ye3a1e4462020-08-12 10:13:15 -0700702 if (parcel == nullptr) {
703 ALOGE("%s: Null parcel", __func__);
704 return;
705 }
Philip Junker90bc9492021-12-10 18:39:42 +0100706 parcel->writeCString(mLoadFileName.c_str());
Michael Wright102936e2020-11-04 03:44:27 +0000707 parcel->writeInt32(static_cast<int32_t>(mType));
Philip Junker90bc9492021-12-10 18:39:42 +0100708 parcel->writeBool(mLayoutOverlayApplied);
Jeff Brown5912f952013-07-01 19:10:31 -0700709
710 size_t numKeys = mKeys.size();
711 parcel->writeInt32(numKeys);
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700712 for (const auto& [keyCode, key] : mKeys) {
Jeff Brown5912f952013-07-01 19:10:31 -0700713 parcel->writeInt32(keyCode);
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700714 parcel->writeInt32(key.label);
715 parcel->writeInt32(key.number);
716 for (const Behavior& behavior : key.behaviors) {
Jeff Brown5912f952013-07-01 19:10:31 -0700717 parcel->writeInt32(1);
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700718 parcel->writeInt32(behavior.metaState);
719 parcel->writeInt32(behavior.character);
720 parcel->writeInt32(behavior.fallbackKeyCode);
721 parcel->writeInt32(behavior.replacementKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700722 }
723 parcel->writeInt32(0);
724 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000725 size_t numKeyRemapping = mKeyRemapping.size();
726 parcel->writeInt32(numKeyRemapping);
727 for (auto const& [fromAndroidKeyCode, toAndroidKeyCode] : mKeyRemapping) {
728 parcel->writeInt32(fromAndroidKeyCode);
729 parcel->writeInt32(toAndroidKeyCode);
730 }
Philip Junker90bc9492021-12-10 18:39:42 +0100731 size_t numKeysByScanCode = mKeysByScanCode.size();
732 parcel->writeInt32(numKeysByScanCode);
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000733 for (auto const& [fromScanCode, toAndroidKeyCode] : mKeysByScanCode) {
734 parcel->writeInt32(fromScanCode);
735 parcel->writeInt32(toAndroidKeyCode);
Philip Junker90bc9492021-12-10 18:39:42 +0100736 }
737 size_t numKeysByUsageCode = mKeysByUsageCode.size();
738 parcel->writeInt32(numKeysByUsageCode);
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000739 for (auto const& [fromUsageCode, toAndroidKeyCode] : mKeysByUsageCode) {
740 parcel->writeInt32(fromUsageCode);
741 parcel->writeInt32(toAndroidKeyCode);
Philip Junker90bc9492021-12-10 18:39:42 +0100742 }
Jeff Brown5912f952013-07-01 19:10:31 -0700743}
Jeff Brown5912f952013-07-01 19:10:31 -0700744
Jeff Brown5912f952013-07-01 19:10:31 -0700745// --- KeyCharacterMap::Parser ---
746
747KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
748 mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
749}
750
Jeff Brown5912f952013-07-01 19:10:31 -0700751status_t KeyCharacterMap::Parser::parse() {
752 while (!mTokenizer->isEof()) {
753#if DEBUG_PARSER
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000754 ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(),
755 mTokenizer->peekRemainderOfLine().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700756#endif
757
758 mTokenizer->skipDelimiters(WHITESPACE);
759
760 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
761 switch (mState) {
762 case STATE_TOP: {
763 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
764 if (keywordToken == "type") {
765 mTokenizer->skipDelimiters(WHITESPACE);
766 status_t status = parseType();
767 if (status) return status;
768 } else if (keywordToken == "map") {
769 mTokenizer->skipDelimiters(WHITESPACE);
770 status_t status = parseMap();
771 if (status) return status;
772 } else if (keywordToken == "key") {
773 mTokenizer->skipDelimiters(WHITESPACE);
774 status_t status = parseKey();
775 if (status) return status;
776 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000777 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().c_str(),
778 keywordToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700779 return BAD_VALUE;
780 }
781 break;
782 }
783
784 case STATE_KEY: {
785 status_t status = parseKeyProperty();
786 if (status) return status;
787 break;
788 }
789 }
790
791 mTokenizer->skipDelimiters(WHITESPACE);
792 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000793 ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
794 mTokenizer->getLocation().c_str(), mTokenizer->peekRemainderOfLine().c_str());
795 return BAD_VALUE;
Jeff Brown5912f952013-07-01 19:10:31 -0700796 }
797 }
798
799 mTokenizer->nextLine();
800 }
801
802 if (mState != STATE_TOP) {
803 ALOGE("%s: Unterminated key description at end of file.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000804 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700805 return BAD_VALUE;
806 }
807
Michael Wright102936e2020-11-04 03:44:27 +0000808 if (mMap->mType == KeyboardType::UNKNOWN) {
Jeff Brown5912f952013-07-01 19:10:31 -0700809 ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000810 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700811 return BAD_VALUE;
812 }
813
Michael Wright102936e2020-11-04 03:44:27 +0000814 if (mFormat == Format::BASE) {
815 if (mMap->mType == KeyboardType::OVERLAY) {
Jeff Brown5912f952013-07-01 19:10:31 -0700816 ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000817 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700818 return BAD_VALUE;
819 }
Michael Wright102936e2020-11-04 03:44:27 +0000820 } else if (mFormat == Format::OVERLAY) {
821 if (mMap->mType != KeyboardType::OVERLAY) {
Jeff Brown5912f952013-07-01 19:10:31 -0700822 ALOGE("%s: Overlay keyboard layout missing required keyboard "
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000823 "'type OVERLAY' declaration.",
824 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700825 return BAD_VALUE;
826 }
827 }
828
829 return NO_ERROR;
830}
831
832status_t KeyCharacterMap::Parser::parseType() {
Michael Wright102936e2020-11-04 03:44:27 +0000833 if (mMap->mType != KeyboardType::UNKNOWN) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000834 ALOGE("%s: Duplicate keyboard 'type' declaration.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700835 return BAD_VALUE;
836 }
837
838 KeyboardType type;
839 String8 typeToken = mTokenizer->nextToken(WHITESPACE);
840 if (typeToken == "NUMERIC") {
Michael Wright102936e2020-11-04 03:44:27 +0000841 type = KeyboardType::NUMERIC;
Jeff Brown5912f952013-07-01 19:10:31 -0700842 } else if (typeToken == "PREDICTIVE") {
Michael Wright102936e2020-11-04 03:44:27 +0000843 type = KeyboardType::PREDICTIVE;
Jeff Brown5912f952013-07-01 19:10:31 -0700844 } else if (typeToken == "ALPHA") {
Michael Wright102936e2020-11-04 03:44:27 +0000845 type = KeyboardType::ALPHA;
Jeff Brown5912f952013-07-01 19:10:31 -0700846 } else if (typeToken == "FULL") {
Michael Wright102936e2020-11-04 03:44:27 +0000847 type = KeyboardType::FULL;
Jeff Brown5912f952013-07-01 19:10:31 -0700848 } else if (typeToken == "SPECIAL_FUNCTION") {
Siarhei Vishniakou61da25a2018-02-15 21:04:49 -0600849 ALOGW("The SPECIAL_FUNCTION type is now declared in the device's IDC file, please set "
850 "the property 'keyboard.specialFunction' to '1' there instead.");
851 // TODO: return BAD_VALUE here in Q
Michael Wright102936e2020-11-04 03:44:27 +0000852 type = KeyboardType::SPECIAL_FUNCTION;
Jeff Brown5912f952013-07-01 19:10:31 -0700853 } else if (typeToken == "OVERLAY") {
Michael Wright102936e2020-11-04 03:44:27 +0000854 type = KeyboardType::OVERLAY;
Jeff Brown5912f952013-07-01 19:10:31 -0700855 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000856 ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().c_str(),
857 typeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700858 return BAD_VALUE;
859 }
860
861#if DEBUG_PARSER
862 ALOGD("Parsed type: type=%d.", type);
863#endif
864 mMap->mType = type;
865 return NO_ERROR;
866}
867
868status_t KeyCharacterMap::Parser::parseMap() {
869 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
870 if (keywordToken == "key") {
871 mTokenizer->skipDelimiters(WHITESPACE);
872 return parseMapKey();
873 }
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000874 ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().c_str(),
875 keywordToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700876 return BAD_VALUE;
877}
878
879status_t KeyCharacterMap::Parser::parseMapKey() {
880 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
881 bool mapUsage = false;
882 if (codeToken == "usage") {
883 mapUsage = true;
884 mTokenizer->skipDelimiters(WHITESPACE);
885 codeToken = mTokenizer->nextToken(WHITESPACE);
886 }
887
888 char* end;
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000889 int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0));
Jeff Brown5912f952013-07-01 19:10:31 -0700890 if (*end) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000891 ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().c_str(),
892 mapUsage ? "usage" : "scan code", codeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700893 return BAD_VALUE;
894 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000895 std::map<int32_t, int32_t>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
896 const auto it = map.find(code);
897 if (it != map.end()) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000898 ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().c_str(),
899 mapUsage ? "usage" : "scan code", codeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700900 return BAD_VALUE;
901 }
902
903 mTokenizer->skipDelimiters(WHITESPACE);
904 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000905 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700906 if (!keyCode) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000907 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(),
908 keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700909 return BAD_VALUE;
910 }
911
912#if DEBUG_PARSER
913 ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
914 mapUsage ? "usage" : "scan code", code, keyCode);
915#endif
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800916 map.insert_or_assign(code, *keyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700917 return NO_ERROR;
918}
919
920status_t KeyCharacterMap::Parser::parseKey() {
921 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000922 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700923 if (!keyCode) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000924 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(),
925 keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700926 return BAD_VALUE;
927 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700928 if (mMap->mKeys.find(*keyCode) != mMap->mKeys.end()) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000929 ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().c_str(),
930 keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700931 return BAD_VALUE;
932 }
933
934 mTokenizer->skipDelimiters(WHITESPACE);
935 String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
936 if (openBraceToken != "{") {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000937 ALOGE("%s: Expected '{' after key code label, got '%s'.", mTokenizer->getLocation().c_str(),
938 openBraceToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700939 return BAD_VALUE;
940 }
941
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800942 ALOGD_IF(DEBUG_PARSER, "Parsed beginning of key: keyCode=%d.", *keyCode);
943 mKeyCode = *keyCode;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700944 mMap->mKeys.emplace(*keyCode, Key{});
Jeff Brown5912f952013-07-01 19:10:31 -0700945 mState = STATE_KEY;
946 return NO_ERROR;
947}
948
949status_t KeyCharacterMap::Parser::parseKeyProperty() {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700950 Key& key = mMap->mKeys[mKeyCode];
Jeff Brown5912f952013-07-01 19:10:31 -0700951 String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
952 if (token == "}") {
953 mState = STATE_TOP;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700954 return finishKey(key);
Jeff Brown5912f952013-07-01 19:10:31 -0700955 }
956
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700957 std::vector<Property> properties;
Jeff Brown5912f952013-07-01 19:10:31 -0700958
959 // Parse all comma-delimited property names up to the first colon.
960 for (;;) {
961 if (token == "label") {
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700962 properties.emplace_back(PROPERTY_LABEL);
Jeff Brown5912f952013-07-01 19:10:31 -0700963 } else if (token == "number") {
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700964 properties.emplace_back(PROPERTY_NUMBER);
Jeff Brown5912f952013-07-01 19:10:31 -0700965 } else {
966 int32_t metaState;
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000967 status_t status = parseModifier(token.c_str(), &metaState);
Jeff Brown5912f952013-07-01 19:10:31 -0700968 if (status) {
969 ALOGE("%s: Expected a property name or modifier, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000970 mTokenizer->getLocation().c_str(), token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700971 return status;
972 }
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700973 properties.emplace_back(PROPERTY_META, metaState);
Jeff Brown5912f952013-07-01 19:10:31 -0700974 }
975
976 mTokenizer->skipDelimiters(WHITESPACE);
977 if (!mTokenizer->isEol()) {
978 char ch = mTokenizer->nextChar();
979 if (ch == ':') {
980 break;
981 } else if (ch == ',') {
982 mTokenizer->skipDelimiters(WHITESPACE);
983 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
984 continue;
985 }
986 }
987
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000988 ALOGE("%s: Expected ',' or ':' after property name.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700989 return BAD_VALUE;
990 }
991
992 // Parse behavior after the colon.
993 mTokenizer->skipDelimiters(WHITESPACE);
994
995 Behavior behavior;
996 bool haveCharacter = false;
997 bool haveFallback = false;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700998 bool haveReplacement = false;
Jeff Brown5912f952013-07-01 19:10:31 -0700999
1000 do {
1001 char ch = mTokenizer->peekChar();
1002 if (ch == '\'') {
1003 char16_t character;
1004 status_t status = parseCharacterLiteral(&character);
1005 if (status || !character) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001006 ALOGE("%s: Invalid character literal for key.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001007 return BAD_VALUE;
1008 }
1009 if (haveCharacter) {
1010 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001011 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001012 return BAD_VALUE;
1013 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001014 if (haveReplacement) {
1015 ALOGE("%s: Cannot combine character literal with replace action.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001016 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001017 return BAD_VALUE;
1018 }
Jeff Brown5912f952013-07-01 19:10:31 -07001019 behavior.character = character;
1020 haveCharacter = true;
1021 } else {
1022 token = mTokenizer->nextToken(WHITESPACE);
1023 if (token == "none") {
1024 if (haveCharacter) {
1025 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001026 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001027 return BAD_VALUE;
1028 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001029 if (haveReplacement) {
1030 ALOGE("%s: Cannot combine 'none' with replace action.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001031 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001032 return BAD_VALUE;
1033 }
Jeff Brown5912f952013-07-01 19:10:31 -07001034 haveCharacter = true;
1035 } else if (token == "fallback") {
1036 mTokenizer->skipDelimiters(WHITESPACE);
1037 token = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001038 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001039 if (!keyCode) {
1040 ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001041 mTokenizer->getLocation().c_str(), token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001042 return BAD_VALUE;
1043 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001044 if (haveFallback || haveReplacement) {
1045 ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001046 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001047 return BAD_VALUE;
1048 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001049 behavior.fallbackKeyCode = *keyCode;
Jeff Brown5912f952013-07-01 19:10:31 -07001050 haveFallback = true;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001051 } else if (token == "replace") {
1052 mTokenizer->skipDelimiters(WHITESPACE);
1053 token = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001054 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001055 if (!keyCode) {
1056 ALOGE("%s: Invalid key code label for replace, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001057 mTokenizer->getLocation().c_str(), token.c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001058 return BAD_VALUE;
1059 }
1060 if (haveCharacter) {
1061 ALOGE("%s: Cannot combine character literal with replace action.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001062 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001063 return BAD_VALUE;
1064 }
1065 if (haveFallback || haveReplacement) {
1066 ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001067 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001068 return BAD_VALUE;
1069 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001070 behavior.replacementKeyCode = *keyCode;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001071 haveReplacement = true;
1072
Jeff Brown5912f952013-07-01 19:10:31 -07001073 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001074 ALOGE("%s: Expected a key behavior after ':'.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001075 return BAD_VALUE;
1076 }
1077 }
1078
1079 mTokenizer->skipDelimiters(WHITESPACE);
1080 } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#');
1081
1082 // Add the behavior.
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -07001083 for (const Property& property : properties) {
Jeff Brown5912f952013-07-01 19:10:31 -07001084 switch (property.property) {
1085 case PROPERTY_LABEL:
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001086 if (key.label) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001087 ALOGE("%s: Duplicate label for key.", mTokenizer->getLocation().c_str());
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001088 return BAD_VALUE;
1089 }
1090 key.label = behavior.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001091#if DEBUG_PARSER
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001092 ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key.label);
Jeff Brown5912f952013-07-01 19:10:31 -07001093#endif
1094 break;
1095 case PROPERTY_NUMBER:
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001096 if (key.number) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001097 ALOGE("%s: Duplicate number for key.", mTokenizer->getLocation().c_str());
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001098 return BAD_VALUE;
Jeff Brown5912f952013-07-01 19:10:31 -07001099 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001100 key.number = behavior.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001101#if DEBUG_PARSER
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001102 ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key.number);
Jeff Brown5912f952013-07-01 19:10:31 -07001103#endif
1104 break;
1105 case PROPERTY_META: {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001106 for (const Behavior& b : key.behaviors) {
1107 if (b.metaState == property.metaState) {
Jeff Brown5912f952013-07-01 19:10:31 -07001108 ALOGE("%s: Duplicate key behavior for modifier.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001109 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001110 return BAD_VALUE;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001111 }
Jeff Brown5912f952013-07-01 19:10:31 -07001112 }
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001113 Behavior newBehavior = behavior;
1114 newBehavior.metaState = property.metaState;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001115 key.behaviors.push_front(newBehavior);
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001116 ALOGD_IF(DEBUG_PARSER,
1117 "Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001118 mKeyCode, key.behaviors.front().metaState, key.behaviors.front().character,
1119 key.behaviors.front().fallbackKeyCode,
1120 key.behaviors.front().replacementKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -07001121 break;
1122 }
1123 }
1124 }
1125 return NO_ERROR;
1126}
1127
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001128status_t KeyCharacterMap::Parser::finishKey(Key& key) {
Jeff Brown5912f952013-07-01 19:10:31 -07001129 // Fill in default number property.
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001130 if (!key.number) {
Jeff Brown5912f952013-07-01 19:10:31 -07001131 char16_t digit = 0;
1132 char16_t symbol = 0;
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001133 for (const Behavior& b : key.behaviors) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001134 char16_t ch = b.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001135 if (ch) {
1136 if (ch >= '0' && ch <= '9') {
1137 digit = ch;
1138 } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
1139 || ch == '-' || ch == '+' || ch == ',' || ch == '.'
1140 || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
1141 symbol = ch;
1142 }
1143 }
1144 }
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001145 key.number = digit ? digit : symbol;
Jeff Brown5912f952013-07-01 19:10:31 -07001146 }
1147 return NO_ERROR;
1148}
1149
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001150status_t KeyCharacterMap::Parser::parseModifier(const std::string& token, int32_t* outMetaState) {
Jeff Brown5912f952013-07-01 19:10:31 -07001151 if (token == "base") {
1152 *outMetaState = 0;
1153 return NO_ERROR;
1154 }
1155
1156 int32_t combinedMeta = 0;
1157
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001158 const char* str = token.c_str();
Jeff Brown5912f952013-07-01 19:10:31 -07001159 const char* start = str;
1160 for (const char* cur = str; ; cur++) {
1161 char ch = *cur;
1162 if (ch == '+' || ch == '\0') {
1163 size_t len = cur - start;
1164 int32_t metaState = 0;
1165 for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
1166 if (strlen(modifiers[i].label) == len
1167 && strncmp(modifiers[i].label, start, len) == 0) {
1168 metaState = modifiers[i].metaState;
1169 break;
1170 }
1171 }
1172 if (!metaState) {
1173 return BAD_VALUE;
1174 }
1175 if (combinedMeta & metaState) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001176 ALOGE("%s: Duplicate modifier combination '%s'.", mTokenizer->getLocation().c_str(),
1177 token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001178 return BAD_VALUE;
1179 }
1180
1181 combinedMeta |= metaState;
1182 start = cur + 1;
1183
1184 if (ch == '\0') {
1185 break;
1186 }
1187 }
1188 }
1189 *outMetaState = combinedMeta;
1190 return NO_ERROR;
1191}
1192
1193status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
1194 char ch = mTokenizer->nextChar();
1195 if (ch != '\'') {
1196 goto Error;
1197 }
1198
1199 ch = mTokenizer->nextChar();
1200 if (ch == '\\') {
1201 // Escape sequence.
1202 ch = mTokenizer->nextChar();
1203 if (ch == 'n') {
1204 *outCharacter = '\n';
1205 } else if (ch == 't') {
1206 *outCharacter = '\t';
1207 } else if (ch == '\\') {
1208 *outCharacter = '\\';
1209 } else if (ch == '\'') {
1210 *outCharacter = '\'';
1211 } else if (ch == '"') {
1212 *outCharacter = '"';
1213 } else if (ch == 'u') {
1214 *outCharacter = 0;
1215 for (int i = 0; i < 4; i++) {
1216 ch = mTokenizer->nextChar();
1217 int digit;
1218 if (ch >= '0' && ch <= '9') {
1219 digit = ch - '0';
1220 } else if (ch >= 'A' && ch <= 'F') {
1221 digit = ch - 'A' + 10;
1222 } else if (ch >= 'a' && ch <= 'f') {
1223 digit = ch - 'a' + 10;
1224 } else {
1225 goto Error;
1226 }
1227 *outCharacter = (*outCharacter << 4) | digit;
1228 }
1229 } else {
1230 goto Error;
1231 }
1232 } else if (ch >= 32 && ch <= 126 && ch != '\'') {
1233 // ASCII literal character.
1234 *outCharacter = ch;
1235 } else {
1236 goto Error;
1237 }
1238
1239 ch = mTokenizer->nextChar();
1240 if (ch != '\'') {
1241 goto Error;
1242 }
1243
1244 // Ensure that we consumed the entire token.
Tomasz Wasilczyke50b2de2023-08-14 18:03:09 +00001245 if (mTokenizer->nextToken(WHITESPACE).empty()) {
Jeff Brown5912f952013-07-01 19:10:31 -07001246 return NO_ERROR;
1247 }
1248
1249Error:
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001250 ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001251 return BAD_VALUE;
1252}
1253
1254} // namespace android