blob: b0563abaf7d21588cd9119a64fdb49e40fd51db2 [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
Linnan Lie5657f22024-09-13 21:54:37 +0800320void KeyCharacterMap::setKeyRemapping(const std::map<int32_t, int32_t>& keyRemapping) {
321 mKeyRemapping = keyRemapping;
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000322}
323
Jeff Brown5912f952013-07-01 19:10:31 -0700324status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
325 if (usageCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000326 const auto it = mKeysByUsageCode.find(usageCode);
327 if (it != mKeysByUsageCode.end()) {
328 *outKeyCode = it->second;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700329#if DEBUG_MAPPING
330 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
331 scanCode, usageCode, *outKeyCode);
332#endif
Jeff Brown5912f952013-07-01 19:10:31 -0700333 return OK;
334 }
335 }
336 if (scanCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000337 const auto it = mKeysByScanCode.find(scanCode);
338 if (it != mKeysByScanCode.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
348#if DEBUG_MAPPING
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700349 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700350#endif
351 *outKeyCode = AKEYCODE_UNKNOWN;
352 return NAME_NOT_FOUND;
353}
354
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000355int32_t KeyCharacterMap::applyKeyRemapping(int32_t fromKeyCode) const {
356 int32_t toKeyCode = fromKeyCode;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700357
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000358 const auto it = mKeyRemapping.find(fromKeyCode);
359 if (it != mKeyRemapping.end()) {
360 toKeyCode = it->second;
361 }
362#if DEBUG_MAPPING
363 ALOGD("applyKeyRemapping: keyCode=%d ~ replacement keyCode=%d.", fromKeyCode, toKeyCode);
364#endif
365 return toKeyCode;
366}
367
368std::pair<int32_t, int32_t> KeyCharacterMap::applyKeyBehavior(int32_t fromKeyCode,
369 int32_t fromMetaState) const {
370 int32_t toKeyCode = fromKeyCode;
371 int32_t toMetaState = fromMetaState;
372
373 const Behavior* behavior = getKeyBehavior(fromKeyCode, fromMetaState);
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700374 if (behavior != nullptr) {
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700375 if (behavior->replacementKeyCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000376 toKeyCode = behavior->replacementKeyCode;
377 toMetaState = fromMetaState & ~behavior->metaState;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700378 // Reset dependent meta states.
379 if (behavior->metaState & AMETA_ALT_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000380 toMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700381 }
382 if (behavior->metaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000383 toMetaState &= ~AMETA_ALT_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700384 }
385 if (behavior->metaState & AMETA_CTRL_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000386 toMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700387 }
388 if (behavior->metaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000389 toMetaState &= ~AMETA_CTRL_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700390 }
391 if (behavior->metaState & AMETA_SHIFT_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000392 toMetaState &= ~(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700393 }
394 if (behavior->metaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000395 toMetaState &= ~AMETA_SHIFT_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700396 }
397 // ... and put universal bits back if needed
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000398 toMetaState = normalizeMetaState(toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700399 }
400 }
401
402#if DEBUG_MAPPING
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000403 ALOGD("applyKeyBehavior: keyCode=%d, metaState=0x%08x ~ "
404 "replacement keyCode=%d, replacement metaState=0x%08x.",
405 fromKeyCode, fromMetaState, toKeyCode, toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700406#endif
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000407 return std::make_pair(toKeyCode, toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700408}
409
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700410const KeyCharacterMap::Key* KeyCharacterMap::getKey(int32_t keyCode) const {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700411 auto it = mKeys.find(keyCode);
412 if (it != mKeys.end()) {
413 return &it->second;
Jeff Brown5912f952013-07-01 19:10:31 -0700414 }
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700415 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700416}
417
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700418const KeyCharacterMap::Behavior* KeyCharacterMap::getKeyBehavior(int32_t keyCode,
419 int32_t metaState) const {
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700420 const Key* key = getKey(keyCode);
421 if (key != nullptr) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700422 for (const Behavior& behavior : key->behaviors) {
423 if (matchesMetaState(metaState, behavior.metaState)) {
424 return &behavior;
Jeff Brown5912f952013-07-01 19:10:31 -0700425 }
Jeff Brown5912f952013-07-01 19:10:31 -0700426 }
427 }
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700428 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700429}
430
431bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
432 // Behavior must have at least the set of meta states specified.
433 // And if the key event has CTRL, ALT or META then the behavior must exactly
434 // match those, taking into account that a behavior can specify that it handles
435 // one, both or either of a left/right modifier pair.
436 if ((eventMetaState & behaviorMetaState) == behaviorMetaState) {
437 const int32_t EXACT_META_STATES =
438 AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON
439 | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON
440 | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON;
441 int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES;
442 if (behaviorMetaState & AMETA_CTRL_ON) {
443 unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
444 } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
445 unmatchedMetaState &= ~AMETA_CTRL_ON;
446 }
447 if (behaviorMetaState & AMETA_ALT_ON) {
448 unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
449 } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
450 unmatchedMetaState &= ~AMETA_ALT_ON;
451 }
452 if (behaviorMetaState & AMETA_META_ON) {
453 unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
454 } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
455 unmatchedMetaState &= ~AMETA_META_ON;
456 }
457 return !unmatchedMetaState;
458 }
459 return false;
460}
461
462bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
463 if (!ch) {
464 return false;
465 }
466
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700467 for (const auto& [keyCode, key] : mKeys) {
Jeff Brown5912f952013-07-01 19:10:31 -0700468 // Try to find the most general behavior that maps to this character.
469 // For example, the base key behavior will usually be last in the list.
Yi Kong5bed83b2018-07-17 12:53:47 -0700470 const Behavior* found = nullptr;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700471 for (const Behavior& behavior : key.behaviors) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700472 if (behavior.character == ch) {
473 found = &behavior;
Jeff Brown5912f952013-07-01 19:10:31 -0700474 }
475 }
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700476 if (found != nullptr) {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700477 *outKeyCode = keyCode;
Jeff Brown5912f952013-07-01 19:10:31 -0700478 *outMetaState = found->metaState;
479 return true;
480 }
481 }
482 return false;
483}
484
Linnan Li13bf76a2024-05-05 19:18:02 +0800485void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents, int32_t deviceId, int32_t keyCode,
486 int32_t metaState, bool down, nsecs_t time) {
Jeff Brown5912f952013-07-01 19:10:31 -0700487 outEvents.push();
488 KeyEvent& event = outEvents.editTop();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700489 event.initialize(InputEvent::nextId(), deviceId, AINPUT_SOURCE_KEYBOARD,
490 ui::LogicalDisplayId::INVALID, INVALID_HMAC,
491 down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 0, keyCode, 0, metaState,
492 0, time, time);
Jeff Brown5912f952013-07-01 19:10:31 -0700493}
494
495void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
496 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
497 int32_t* currentMetaState) {
498 // Add and remove meta keys symmetrically.
499 if (down) {
500 addLockedMetaKey(outEvents, deviceId, metaState, time,
501 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
502 addLockedMetaKey(outEvents, deviceId, metaState, time,
503 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
504 addLockedMetaKey(outEvents, deviceId, metaState, time,
505 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
506
507 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
508 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
509 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
510 AMETA_SHIFT_ON, currentMetaState);
511 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
512 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
513 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
514 AMETA_ALT_ON, currentMetaState);
515 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
516 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
517 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
518 AMETA_CTRL_ON, currentMetaState);
519 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
520 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
521 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
522 AMETA_META_ON, currentMetaState);
523
524 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
525 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
526 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
527 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
528 } else {
529 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
530 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
531 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
532 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
533
534 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
535 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
536 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
537 AMETA_META_ON, currentMetaState);
538 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
539 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
540 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
541 AMETA_CTRL_ON, currentMetaState);
542 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
543 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
544 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
545 AMETA_ALT_ON, currentMetaState);
546 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
547 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
548 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
549 AMETA_SHIFT_ON, currentMetaState);
550
551 addLockedMetaKey(outEvents, deviceId, metaState, time,
552 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
553 addLockedMetaKey(outEvents, deviceId, metaState, time,
554 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
555 addLockedMetaKey(outEvents, deviceId, metaState, time,
556 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
557 }
558}
559
560bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
561 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
562 int32_t keyCode, int32_t keyMetaState,
563 int32_t* currentMetaState) {
564 if ((metaState & keyMetaState) == keyMetaState) {
565 *currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
566 addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
567 return true;
568 }
569 return false;
570}
571
572void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
573 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
574 int32_t leftKeyCode, int32_t leftKeyMetaState,
575 int32_t rightKeyCode, int32_t rightKeyMetaState,
576 int32_t eitherKeyMetaState,
577 int32_t* currentMetaState) {
578 bool specific = false;
579 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
580 leftKeyCode, leftKeyMetaState, currentMetaState);
581 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
582 rightKeyCode, rightKeyMetaState, currentMetaState);
583
584 if (!specific) {
585 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
586 leftKeyCode, eitherKeyMetaState, currentMetaState);
587 }
588}
589
590void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
591 int32_t deviceId, int32_t metaState, nsecs_t time,
592 int32_t keyCode, int32_t keyMetaState,
593 int32_t* currentMetaState) {
594 if ((metaState & keyMetaState) == keyMetaState) {
595 *currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
596 addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
597 *currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
598 addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
599 }
600}
601
Siarhei Vishniakouc62948e2023-10-23 07:22:01 -0700602std::unique_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
Chris Ye3a1e4462020-08-12 10:13:15 -0700603 if (parcel == nullptr) {
604 ALOGE("%s: Null parcel", __func__);
605 return nullptr;
606 }
Philip Junker90bc9492021-12-10 18:39:42 +0100607 std::string loadFileName = parcel->readCString();
Siarhei Vishniakouc62948e2023-10-23 07:22:01 -0700608 std::unique_ptr<KeyCharacterMap> map =
609 std::make_unique<KeyCharacterMap>(KeyCharacterMap(loadFileName));
Michael Wright102936e2020-11-04 03:44:27 +0000610 map->mType = static_cast<KeyCharacterMap::KeyboardType>(parcel->readInt32());
Philip Junker90bc9492021-12-10 18:39:42 +0100611 map->mLayoutOverlayApplied = parcel->readBool();
Jeff Brown5912f952013-07-01 19:10:31 -0700612 size_t numKeys = parcel->readInt32();
613 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700614 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700615 }
Michael Wright4c971c02015-10-21 14:38:03 +0100616 if (numKeys > MAX_KEYS) {
Ian Pedowitzd57d9b92016-02-19 08:34:43 +0000617 ALOGE("Too many keys in KeyCharacterMap (%zu > %d)", numKeys, MAX_KEYS);
Yi Kong5bed83b2018-07-17 12:53:47 -0700618 return nullptr;
Michael Wright4c971c02015-10-21 14:38:03 +0100619 }
Jeff Brown5912f952013-07-01 19:10:31 -0700620
621 for (size_t i = 0; i < numKeys; i++) {
622 int32_t keyCode = parcel->readInt32();
623 char16_t label = parcel->readInt32();
624 char16_t number = parcel->readInt32();
625 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700626 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700627 }
628
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700629 Key key{.label = label, .number = number};
Jeff Brown5912f952013-07-01 19:10:31 -0700630 while (parcel->readInt32()) {
631 int32_t metaState = parcel->readInt32();
632 char16_t character = parcel->readInt32();
633 int32_t fallbackKeyCode = parcel->readInt32();
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700634 int32_t replacementKeyCode = parcel->readInt32();
Jeff Brown5912f952013-07-01 19:10:31 -0700635 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.behaviors.push_back({
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700640 .metaState = metaState,
641 .character = character,
642 .fallbackKeyCode = fallbackKeyCode,
643 .replacementKeyCode = replacementKeyCode,
644 });
Jeff Brown5912f952013-07-01 19:10:31 -0700645 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700646 map->mKeys.emplace(keyCode, std::move(key));
Jeff Brown5912f952013-07-01 19:10:31 -0700647
648 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700649 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700650 }
651 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000652 size_t numKeyRemapping = parcel->readInt32();
653 if (parcel->errorCheck()) {
654 return nullptr;
655 }
656 for (size_t i = 0; i < numKeyRemapping; i++) {
657 int32_t key = parcel->readInt32();
658 int32_t value = parcel->readInt32();
659 map->mKeyRemapping.insert_or_assign(key, value);
660 if (parcel->errorCheck()) {
661 return nullptr;
662 }
663 }
Philip Junker90bc9492021-12-10 18:39:42 +0100664 size_t numKeysByScanCode = parcel->readInt32();
665 if (parcel->errorCheck()) {
666 return nullptr;
667 }
668 for (size_t i = 0; i < numKeysByScanCode; i++) {
669 int32_t key = parcel->readInt32();
670 int32_t value = parcel->readInt32();
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000671 map->mKeysByScanCode.insert_or_assign(key, value);
Philip Junker90bc9492021-12-10 18:39:42 +0100672 if (parcel->errorCheck()) {
673 return nullptr;
674 }
675 }
676 size_t numKeysByUsageCode = parcel->readInt32();
677 if (parcel->errorCheck()) {
678 return nullptr;
679 }
680 for (size_t i = 0; i < numKeysByUsageCode; i++) {
681 int32_t key = parcel->readInt32();
682 int32_t value = parcel->readInt32();
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000683 map->mKeysByUsageCode.insert_or_assign(key, value);
Philip Junker90bc9492021-12-10 18:39:42 +0100684 if (parcel->errorCheck()) {
685 return nullptr;
686 }
687 }
Jeff Brown5912f952013-07-01 19:10:31 -0700688 return map;
689}
690
691void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
Chris Ye3a1e4462020-08-12 10:13:15 -0700692 if (parcel == nullptr) {
693 ALOGE("%s: Null parcel", __func__);
694 return;
695 }
Philip Junker90bc9492021-12-10 18:39:42 +0100696 parcel->writeCString(mLoadFileName.c_str());
Michael Wright102936e2020-11-04 03:44:27 +0000697 parcel->writeInt32(static_cast<int32_t>(mType));
Philip Junker90bc9492021-12-10 18:39:42 +0100698 parcel->writeBool(mLayoutOverlayApplied);
Jeff Brown5912f952013-07-01 19:10:31 -0700699
700 size_t numKeys = mKeys.size();
701 parcel->writeInt32(numKeys);
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700702 for (const auto& [keyCode, key] : mKeys) {
Jeff Brown5912f952013-07-01 19:10:31 -0700703 parcel->writeInt32(keyCode);
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700704 parcel->writeInt32(key.label);
705 parcel->writeInt32(key.number);
706 for (const Behavior& behavior : key.behaviors) {
Jeff Brown5912f952013-07-01 19:10:31 -0700707 parcel->writeInt32(1);
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700708 parcel->writeInt32(behavior.metaState);
709 parcel->writeInt32(behavior.character);
710 parcel->writeInt32(behavior.fallbackKeyCode);
711 parcel->writeInt32(behavior.replacementKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700712 }
713 parcel->writeInt32(0);
714 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000715 size_t numKeyRemapping = mKeyRemapping.size();
716 parcel->writeInt32(numKeyRemapping);
717 for (auto const& [fromAndroidKeyCode, toAndroidKeyCode] : mKeyRemapping) {
718 parcel->writeInt32(fromAndroidKeyCode);
719 parcel->writeInt32(toAndroidKeyCode);
720 }
Philip Junker90bc9492021-12-10 18:39:42 +0100721 size_t numKeysByScanCode = mKeysByScanCode.size();
722 parcel->writeInt32(numKeysByScanCode);
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000723 for (auto const& [fromScanCode, toAndroidKeyCode] : mKeysByScanCode) {
724 parcel->writeInt32(fromScanCode);
725 parcel->writeInt32(toAndroidKeyCode);
Philip Junker90bc9492021-12-10 18:39:42 +0100726 }
727 size_t numKeysByUsageCode = mKeysByUsageCode.size();
728 parcel->writeInt32(numKeysByUsageCode);
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000729 for (auto const& [fromUsageCode, toAndroidKeyCode] : mKeysByUsageCode) {
730 parcel->writeInt32(fromUsageCode);
731 parcel->writeInt32(toAndroidKeyCode);
Philip Junker90bc9492021-12-10 18:39:42 +0100732 }
Jeff Brown5912f952013-07-01 19:10:31 -0700733}
Jeff Brown5912f952013-07-01 19:10:31 -0700734
Jeff Brown5912f952013-07-01 19:10:31 -0700735// --- KeyCharacterMap::Parser ---
736
737KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
738 mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
739}
740
Jeff Brown5912f952013-07-01 19:10:31 -0700741status_t KeyCharacterMap::Parser::parse() {
742 while (!mTokenizer->isEof()) {
743#if DEBUG_PARSER
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000744 ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(),
745 mTokenizer->peekRemainderOfLine().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700746#endif
747
748 mTokenizer->skipDelimiters(WHITESPACE);
749
750 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
751 switch (mState) {
752 case STATE_TOP: {
753 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
754 if (keywordToken == "type") {
755 mTokenizer->skipDelimiters(WHITESPACE);
756 status_t status = parseType();
757 if (status) return status;
758 } else if (keywordToken == "map") {
759 mTokenizer->skipDelimiters(WHITESPACE);
760 status_t status = parseMap();
761 if (status) return status;
762 } else if (keywordToken == "key") {
763 mTokenizer->skipDelimiters(WHITESPACE);
764 status_t status = parseKey();
765 if (status) return status;
766 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000767 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().c_str(),
768 keywordToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700769 return BAD_VALUE;
770 }
771 break;
772 }
773
774 case STATE_KEY: {
775 status_t status = parseKeyProperty();
776 if (status) return status;
777 break;
778 }
779 }
780
781 mTokenizer->skipDelimiters(WHITESPACE);
782 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000783 ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
784 mTokenizer->getLocation().c_str(), mTokenizer->peekRemainderOfLine().c_str());
785 return BAD_VALUE;
Jeff Brown5912f952013-07-01 19:10:31 -0700786 }
787 }
788
789 mTokenizer->nextLine();
790 }
791
792 if (mState != STATE_TOP) {
793 ALOGE("%s: Unterminated key description at end of file.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000794 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700795 return BAD_VALUE;
796 }
797
Michael Wright102936e2020-11-04 03:44:27 +0000798 if (mMap->mType == KeyboardType::UNKNOWN) {
Jeff Brown5912f952013-07-01 19:10:31 -0700799 ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000800 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700801 return BAD_VALUE;
802 }
803
Michael Wright102936e2020-11-04 03:44:27 +0000804 if (mFormat == Format::BASE) {
805 if (mMap->mType == KeyboardType::OVERLAY) {
Jeff Brown5912f952013-07-01 19:10:31 -0700806 ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000807 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700808 return BAD_VALUE;
809 }
Michael Wright102936e2020-11-04 03:44:27 +0000810 } else if (mFormat == Format::OVERLAY) {
811 if (mMap->mType != KeyboardType::OVERLAY) {
Jeff Brown5912f952013-07-01 19:10:31 -0700812 ALOGE("%s: Overlay keyboard layout missing required keyboard "
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000813 "'type OVERLAY' declaration.",
814 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700815 return BAD_VALUE;
816 }
817 }
818
819 return NO_ERROR;
820}
821
822status_t KeyCharacterMap::Parser::parseType() {
Michael Wright102936e2020-11-04 03:44:27 +0000823 if (mMap->mType != KeyboardType::UNKNOWN) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000824 ALOGE("%s: Duplicate keyboard 'type' declaration.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700825 return BAD_VALUE;
826 }
827
828 KeyboardType type;
829 String8 typeToken = mTokenizer->nextToken(WHITESPACE);
830 if (typeToken == "NUMERIC") {
Michael Wright102936e2020-11-04 03:44:27 +0000831 type = KeyboardType::NUMERIC;
Jeff Brown5912f952013-07-01 19:10:31 -0700832 } else if (typeToken == "PREDICTIVE") {
Michael Wright102936e2020-11-04 03:44:27 +0000833 type = KeyboardType::PREDICTIVE;
Jeff Brown5912f952013-07-01 19:10:31 -0700834 } else if (typeToken == "ALPHA") {
Michael Wright102936e2020-11-04 03:44:27 +0000835 type = KeyboardType::ALPHA;
Jeff Brown5912f952013-07-01 19:10:31 -0700836 } else if (typeToken == "FULL") {
Michael Wright102936e2020-11-04 03:44:27 +0000837 type = KeyboardType::FULL;
Jeff Brown5912f952013-07-01 19:10:31 -0700838 } else if (typeToken == "SPECIAL_FUNCTION") {
Siarhei Vishniakou61da25a2018-02-15 21:04:49 -0600839 ALOGW("The SPECIAL_FUNCTION type is now declared in the device's IDC file, please set "
840 "the property 'keyboard.specialFunction' to '1' there instead.");
841 // TODO: return BAD_VALUE here in Q
Michael Wright102936e2020-11-04 03:44:27 +0000842 type = KeyboardType::SPECIAL_FUNCTION;
Jeff Brown5912f952013-07-01 19:10:31 -0700843 } else if (typeToken == "OVERLAY") {
Michael Wright102936e2020-11-04 03:44:27 +0000844 type = KeyboardType::OVERLAY;
Jeff Brown5912f952013-07-01 19:10:31 -0700845 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000846 ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().c_str(),
847 typeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700848 return BAD_VALUE;
849 }
850
851#if DEBUG_PARSER
852 ALOGD("Parsed type: type=%d.", type);
853#endif
854 mMap->mType = type;
855 return NO_ERROR;
856}
857
858status_t KeyCharacterMap::Parser::parseMap() {
859 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
860 if (keywordToken == "key") {
861 mTokenizer->skipDelimiters(WHITESPACE);
862 return parseMapKey();
863 }
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000864 ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().c_str(),
865 keywordToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700866 return BAD_VALUE;
867}
868
869status_t KeyCharacterMap::Parser::parseMapKey() {
870 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
871 bool mapUsage = false;
872 if (codeToken == "usage") {
873 mapUsage = true;
874 mTokenizer->skipDelimiters(WHITESPACE);
875 codeToken = mTokenizer->nextToken(WHITESPACE);
876 }
877
878 char* end;
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000879 int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0));
Jeff Brown5912f952013-07-01 19:10:31 -0700880 if (*end) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000881 ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().c_str(),
882 mapUsage ? "usage" : "scan code", codeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700883 return BAD_VALUE;
884 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000885 std::map<int32_t, int32_t>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
886 const auto it = map.find(code);
887 if (it != map.end()) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000888 ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().c_str(),
889 mapUsage ? "usage" : "scan code", codeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700890 return BAD_VALUE;
891 }
892
893 mTokenizer->skipDelimiters(WHITESPACE);
894 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000895 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700896 if (!keyCode) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000897 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(),
898 keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700899 return BAD_VALUE;
900 }
901
902#if DEBUG_PARSER
903 ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
904 mapUsage ? "usage" : "scan code", code, keyCode);
905#endif
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800906 map.insert_or_assign(code, *keyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700907 return NO_ERROR;
908}
909
910status_t KeyCharacterMap::Parser::parseKey() {
911 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000912 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700913 if (!keyCode) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000914 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(),
915 keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700916 return BAD_VALUE;
917 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700918 if (mMap->mKeys.find(*keyCode) != mMap->mKeys.end()) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000919 ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().c_str(),
920 keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700921 return BAD_VALUE;
922 }
923
924 mTokenizer->skipDelimiters(WHITESPACE);
925 String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
926 if (openBraceToken != "{") {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000927 ALOGE("%s: Expected '{' after key code label, got '%s'.", mTokenizer->getLocation().c_str(),
928 openBraceToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700929 return BAD_VALUE;
930 }
931
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800932 ALOGD_IF(DEBUG_PARSER, "Parsed beginning of key: keyCode=%d.", *keyCode);
933 mKeyCode = *keyCode;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700934 mMap->mKeys.emplace(*keyCode, Key{});
Jeff Brown5912f952013-07-01 19:10:31 -0700935 mState = STATE_KEY;
936 return NO_ERROR;
937}
938
939status_t KeyCharacterMap::Parser::parseKeyProperty() {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700940 Key& key = mMap->mKeys[mKeyCode];
Jeff Brown5912f952013-07-01 19:10:31 -0700941 String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
942 if (token == "}") {
943 mState = STATE_TOP;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700944 return finishKey(key);
Jeff Brown5912f952013-07-01 19:10:31 -0700945 }
946
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700947 std::vector<Property> properties;
Jeff Brown5912f952013-07-01 19:10:31 -0700948
949 // Parse all comma-delimited property names up to the first colon.
950 for (;;) {
951 if (token == "label") {
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700952 properties.emplace_back(PROPERTY_LABEL);
Jeff Brown5912f952013-07-01 19:10:31 -0700953 } else if (token == "number") {
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700954 properties.emplace_back(PROPERTY_NUMBER);
Jeff Brown5912f952013-07-01 19:10:31 -0700955 } else {
956 int32_t metaState;
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000957 status_t status = parseModifier(token.c_str(), &metaState);
Jeff Brown5912f952013-07-01 19:10:31 -0700958 if (status) {
959 ALOGE("%s: Expected a property name or modifier, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000960 mTokenizer->getLocation().c_str(), token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700961 return status;
962 }
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700963 properties.emplace_back(PROPERTY_META, metaState);
Jeff Brown5912f952013-07-01 19:10:31 -0700964 }
965
966 mTokenizer->skipDelimiters(WHITESPACE);
967 if (!mTokenizer->isEol()) {
968 char ch = mTokenizer->nextChar();
969 if (ch == ':') {
970 break;
971 } else if (ch == ',') {
972 mTokenizer->skipDelimiters(WHITESPACE);
973 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
974 continue;
975 }
976 }
977
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000978 ALOGE("%s: Expected ',' or ':' after property name.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700979 return BAD_VALUE;
980 }
981
982 // Parse behavior after the colon.
983 mTokenizer->skipDelimiters(WHITESPACE);
984
985 Behavior behavior;
986 bool haveCharacter = false;
987 bool haveFallback = false;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700988 bool haveReplacement = false;
Jeff Brown5912f952013-07-01 19:10:31 -0700989
990 do {
991 char ch = mTokenizer->peekChar();
992 if (ch == '\'') {
993 char16_t character;
994 status_t status = parseCharacterLiteral(&character);
995 if (status || !character) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000996 ALOGE("%s: Invalid character literal for key.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700997 return BAD_VALUE;
998 }
999 if (haveCharacter) {
1000 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001001 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001002 return BAD_VALUE;
1003 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001004 if (haveReplacement) {
1005 ALOGE("%s: Cannot combine character literal with replace action.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001006 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001007 return BAD_VALUE;
1008 }
Jeff Brown5912f952013-07-01 19:10:31 -07001009 behavior.character = character;
1010 haveCharacter = true;
1011 } else {
1012 token = mTokenizer->nextToken(WHITESPACE);
1013 if (token == "none") {
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 'none' 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 haveCharacter = true;
1025 } else if (token == "fallback") {
1026 mTokenizer->skipDelimiters(WHITESPACE);
1027 token = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001028 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001029 if (!keyCode) {
1030 ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001031 mTokenizer->getLocation().c_str(), token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001032 return BAD_VALUE;
1033 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001034 if (haveFallback || haveReplacement) {
1035 ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001036 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001037 return BAD_VALUE;
1038 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001039 behavior.fallbackKeyCode = *keyCode;
Jeff Brown5912f952013-07-01 19:10:31 -07001040 haveFallback = true;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001041 } else if (token == "replace") {
1042 mTokenizer->skipDelimiters(WHITESPACE);
1043 token = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001044 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001045 if (!keyCode) {
1046 ALOGE("%s: Invalid key code label for replace, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001047 mTokenizer->getLocation().c_str(), token.c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001048 return BAD_VALUE;
1049 }
1050 if (haveCharacter) {
1051 ALOGE("%s: Cannot combine character literal with replace action.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001052 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001053 return BAD_VALUE;
1054 }
1055 if (haveFallback || haveReplacement) {
1056 ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001057 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001058 return BAD_VALUE;
1059 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001060 behavior.replacementKeyCode = *keyCode;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001061 haveReplacement = true;
1062
Jeff Brown5912f952013-07-01 19:10:31 -07001063 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001064 ALOGE("%s: Expected a key behavior after ':'.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001065 return BAD_VALUE;
1066 }
1067 }
1068
1069 mTokenizer->skipDelimiters(WHITESPACE);
1070 } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#');
1071
1072 // Add the behavior.
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -07001073 for (const Property& property : properties) {
Jeff Brown5912f952013-07-01 19:10:31 -07001074 switch (property.property) {
1075 case PROPERTY_LABEL:
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001076 if (key.label) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001077 ALOGE("%s: Duplicate label for key.", mTokenizer->getLocation().c_str());
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001078 return BAD_VALUE;
1079 }
1080 key.label = behavior.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001081#if DEBUG_PARSER
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001082 ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key.label);
Jeff Brown5912f952013-07-01 19:10:31 -07001083#endif
1084 break;
1085 case PROPERTY_NUMBER:
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001086 if (key.number) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001087 ALOGE("%s: Duplicate number for key.", mTokenizer->getLocation().c_str());
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001088 return BAD_VALUE;
Jeff Brown5912f952013-07-01 19:10:31 -07001089 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001090 key.number = behavior.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001091#if DEBUG_PARSER
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001092 ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key.number);
Jeff Brown5912f952013-07-01 19:10:31 -07001093#endif
1094 break;
1095 case PROPERTY_META: {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001096 for (const Behavior& b : key.behaviors) {
1097 if (b.metaState == property.metaState) {
Jeff Brown5912f952013-07-01 19:10:31 -07001098 ALOGE("%s: Duplicate key behavior for modifier.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001099 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001100 return BAD_VALUE;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001101 }
Jeff Brown5912f952013-07-01 19:10:31 -07001102 }
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001103 Behavior newBehavior = behavior;
1104 newBehavior.metaState = property.metaState;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001105 key.behaviors.push_front(newBehavior);
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001106 ALOGD_IF(DEBUG_PARSER,
1107 "Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001108 mKeyCode, key.behaviors.front().metaState, key.behaviors.front().character,
1109 key.behaviors.front().fallbackKeyCode,
1110 key.behaviors.front().replacementKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -07001111 break;
1112 }
1113 }
1114 }
1115 return NO_ERROR;
1116}
1117
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001118status_t KeyCharacterMap::Parser::finishKey(Key& key) {
Jeff Brown5912f952013-07-01 19:10:31 -07001119 // Fill in default number property.
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001120 if (!key.number) {
Jeff Brown5912f952013-07-01 19:10:31 -07001121 char16_t digit = 0;
1122 char16_t symbol = 0;
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001123 for (const Behavior& b : key.behaviors) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001124 char16_t ch = b.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001125 if (ch) {
1126 if (ch >= '0' && ch <= '9') {
1127 digit = ch;
1128 } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
1129 || ch == '-' || ch == '+' || ch == ',' || ch == '.'
1130 || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
1131 symbol = ch;
1132 }
1133 }
1134 }
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001135 key.number = digit ? digit : symbol;
Jeff Brown5912f952013-07-01 19:10:31 -07001136 }
1137 return NO_ERROR;
1138}
1139
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001140status_t KeyCharacterMap::Parser::parseModifier(const std::string& token, int32_t* outMetaState) {
Jeff Brown5912f952013-07-01 19:10:31 -07001141 if (token == "base") {
1142 *outMetaState = 0;
1143 return NO_ERROR;
1144 }
1145
1146 int32_t combinedMeta = 0;
1147
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001148 const char* str = token.c_str();
Jeff Brown5912f952013-07-01 19:10:31 -07001149 const char* start = str;
1150 for (const char* cur = str; ; cur++) {
1151 char ch = *cur;
1152 if (ch == '+' || ch == '\0') {
1153 size_t len = cur - start;
1154 int32_t metaState = 0;
1155 for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
1156 if (strlen(modifiers[i].label) == len
1157 && strncmp(modifiers[i].label, start, len) == 0) {
1158 metaState = modifiers[i].metaState;
1159 break;
1160 }
1161 }
1162 if (!metaState) {
1163 return BAD_VALUE;
1164 }
1165 if (combinedMeta & metaState) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001166 ALOGE("%s: Duplicate modifier combination '%s'.", mTokenizer->getLocation().c_str(),
1167 token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001168 return BAD_VALUE;
1169 }
1170
1171 combinedMeta |= metaState;
1172 start = cur + 1;
1173
1174 if (ch == '\0') {
1175 break;
1176 }
1177 }
1178 }
1179 *outMetaState = combinedMeta;
1180 return NO_ERROR;
1181}
1182
1183status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
1184 char ch = mTokenizer->nextChar();
1185 if (ch != '\'') {
1186 goto Error;
1187 }
1188
1189 ch = mTokenizer->nextChar();
1190 if (ch == '\\') {
1191 // Escape sequence.
1192 ch = mTokenizer->nextChar();
1193 if (ch == 'n') {
1194 *outCharacter = '\n';
1195 } else if (ch == 't') {
1196 *outCharacter = '\t';
1197 } else if (ch == '\\') {
1198 *outCharacter = '\\';
1199 } else if (ch == '\'') {
1200 *outCharacter = '\'';
1201 } else if (ch == '"') {
1202 *outCharacter = '"';
1203 } else if (ch == 'u') {
1204 *outCharacter = 0;
1205 for (int i = 0; i < 4; i++) {
1206 ch = mTokenizer->nextChar();
1207 int digit;
1208 if (ch >= '0' && ch <= '9') {
1209 digit = ch - '0';
1210 } else if (ch >= 'A' && ch <= 'F') {
1211 digit = ch - 'A' + 10;
1212 } else if (ch >= 'a' && ch <= 'f') {
1213 digit = ch - 'a' + 10;
1214 } else {
1215 goto Error;
1216 }
1217 *outCharacter = (*outCharacter << 4) | digit;
1218 }
1219 } else {
1220 goto Error;
1221 }
1222 } else if (ch >= 32 && ch <= 126 && ch != '\'') {
1223 // ASCII literal character.
1224 *outCharacter = ch;
1225 } else {
1226 goto Error;
1227 }
1228
1229 ch = mTokenizer->nextChar();
1230 if (ch != '\'') {
1231 goto Error;
1232 }
1233
1234 // Ensure that we consumed the entire token.
Tomasz Wasilczyke50b2de2023-08-14 18:03:09 +00001235 if (mTokenizer->nextToken(WHITESPACE).empty()) {
Jeff Brown5912f952013-07-01 19:10:31 -07001236 return NO_ERROR;
1237 }
1238
1239Error:
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001240 ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001241 return BAD_VALUE;
1242}
1243
1244} // namespace android