blob: 90d29dd1903bfee8ed43c0c77f6fd21330d25d0c [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
Linnan Lid78dd9b2024-10-15 15:50:01 +000087base::Result<std::unique_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename,
Chris Ye3a1e4462020-08-12 10:13:15 -070088 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 }
Linnan Lid78dd9b2024-10-15 15:50:01 +000094 std::unique_ptr<KeyCharacterMap> map =
95 std::unique_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
Philip Junker90bc9492021-12-10 18:39:42 +010096 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
Vaibhav Devmurari5a71e882024-09-30 15:54:41 +0000368std::vector<int32_t> KeyCharacterMap::findKeyCodesMappedToKeyCode(int32_t toKeyCode) const {
369 std::vector<int32_t> fromKeyCodes;
370
371 for (const auto& [from, to] : mKeyRemapping) {
372 if (toKeyCode == to) {
373 fromKeyCodes.push_back(from);
374 }
375 }
376 return fromKeyCodes;
377}
378
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000379std::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();
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700500 event.initialize(InputEvent::nextId(), deviceId, AINPUT_SOURCE_KEYBOARD,
501 ui::LogicalDisplayId::INVALID, INVALID_HMAC,
502 down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 0, keyCode, 0, metaState,
503 0, time, time);
Jeff Brown5912f952013-07-01 19:10:31 -0700504}
505
506void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
507 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
508 int32_t* currentMetaState) {
509 // Add and remove meta keys symmetrically.
510 if (down) {
511 addLockedMetaKey(outEvents, deviceId, metaState, time,
512 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
513 addLockedMetaKey(outEvents, deviceId, metaState, time,
514 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
515 addLockedMetaKey(outEvents, deviceId, metaState, time,
516 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
517
518 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
519 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
520 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
521 AMETA_SHIFT_ON, currentMetaState);
522 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
523 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
524 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
525 AMETA_ALT_ON, currentMetaState);
526 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
527 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
528 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
529 AMETA_CTRL_ON, currentMetaState);
530 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
531 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
532 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
533 AMETA_META_ON, currentMetaState);
534
535 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
536 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
537 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
538 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
539 } else {
540 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
541 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
542 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
543 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
544
545 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
546 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
547 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
548 AMETA_META_ON, currentMetaState);
549 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
550 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
551 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
552 AMETA_CTRL_ON, currentMetaState);
553 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
554 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
555 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
556 AMETA_ALT_ON, currentMetaState);
557 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
558 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
559 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
560 AMETA_SHIFT_ON, currentMetaState);
561
562 addLockedMetaKey(outEvents, deviceId, metaState, time,
563 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
564 addLockedMetaKey(outEvents, deviceId, metaState, time,
565 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
566 addLockedMetaKey(outEvents, deviceId, metaState, time,
567 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
568 }
569}
570
571bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
572 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
573 int32_t keyCode, int32_t keyMetaState,
574 int32_t* currentMetaState) {
575 if ((metaState & keyMetaState) == keyMetaState) {
576 *currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
577 addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
578 return true;
579 }
580 return false;
581}
582
583void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
584 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
585 int32_t leftKeyCode, int32_t leftKeyMetaState,
586 int32_t rightKeyCode, int32_t rightKeyMetaState,
587 int32_t eitherKeyMetaState,
588 int32_t* currentMetaState) {
589 bool specific = false;
590 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
591 leftKeyCode, leftKeyMetaState, currentMetaState);
592 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
593 rightKeyCode, rightKeyMetaState, currentMetaState);
594
595 if (!specific) {
596 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
597 leftKeyCode, eitherKeyMetaState, currentMetaState);
598 }
599}
600
601void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
602 int32_t deviceId, int32_t metaState, nsecs_t time,
603 int32_t keyCode, int32_t keyMetaState,
604 int32_t* currentMetaState) {
605 if ((metaState & keyMetaState) == keyMetaState) {
606 *currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
607 addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
608 *currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
609 addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
610 }
611}
612
Siarhei Vishniakouc62948e2023-10-23 07:22:01 -0700613std::unique_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
Chris Ye3a1e4462020-08-12 10:13:15 -0700614 if (parcel == nullptr) {
615 ALOGE("%s: Null parcel", __func__);
616 return nullptr;
617 }
Philip Junker90bc9492021-12-10 18:39:42 +0100618 std::string loadFileName = parcel->readCString();
Siarhei Vishniakouc62948e2023-10-23 07:22:01 -0700619 std::unique_ptr<KeyCharacterMap> map =
620 std::make_unique<KeyCharacterMap>(KeyCharacterMap(loadFileName));
Michael Wright102936e2020-11-04 03:44:27 +0000621 map->mType = static_cast<KeyCharacterMap::KeyboardType>(parcel->readInt32());
Philip Junker90bc9492021-12-10 18:39:42 +0100622 map->mLayoutOverlayApplied = parcel->readBool();
Jeff Brown5912f952013-07-01 19:10:31 -0700623 size_t numKeys = parcel->readInt32();
624 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700625 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700626 }
Michael Wright4c971c02015-10-21 14:38:03 +0100627 if (numKeys > MAX_KEYS) {
Ian Pedowitzd57d9b92016-02-19 08:34:43 +0000628 ALOGE("Too many keys in KeyCharacterMap (%zu > %d)", numKeys, MAX_KEYS);
Yi Kong5bed83b2018-07-17 12:53:47 -0700629 return nullptr;
Michael Wright4c971c02015-10-21 14:38:03 +0100630 }
Jeff Brown5912f952013-07-01 19:10:31 -0700631
632 for (size_t i = 0; i < numKeys; i++) {
633 int32_t keyCode = parcel->readInt32();
634 char16_t label = parcel->readInt32();
635 char16_t number = parcel->readInt32();
636 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700637 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700638 }
639
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700640 Key key{.label = label, .number = number};
Jeff Brown5912f952013-07-01 19:10:31 -0700641 while (parcel->readInt32()) {
642 int32_t metaState = parcel->readInt32();
643 char16_t character = parcel->readInt32();
644 int32_t fallbackKeyCode = parcel->readInt32();
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700645 int32_t replacementKeyCode = parcel->readInt32();
Jeff Brown5912f952013-07-01 19:10:31 -0700646 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700647 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700648 }
649
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700650 key.behaviors.push_back({
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700651 .metaState = metaState,
652 .character = character,
653 .fallbackKeyCode = fallbackKeyCode,
654 .replacementKeyCode = replacementKeyCode,
655 });
Jeff Brown5912f952013-07-01 19:10:31 -0700656 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700657 map->mKeys.emplace(keyCode, std::move(key));
Jeff Brown5912f952013-07-01 19:10:31 -0700658
659 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700660 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700661 }
662 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000663 size_t numKeyRemapping = parcel->readInt32();
664 if (parcel->errorCheck()) {
665 return nullptr;
666 }
667 for (size_t i = 0; i < numKeyRemapping; i++) {
668 int32_t key = parcel->readInt32();
669 int32_t value = parcel->readInt32();
670 map->mKeyRemapping.insert_or_assign(key, value);
671 if (parcel->errorCheck()) {
672 return nullptr;
673 }
674 }
Philip Junker90bc9492021-12-10 18:39:42 +0100675 size_t numKeysByScanCode = parcel->readInt32();
676 if (parcel->errorCheck()) {
677 return nullptr;
678 }
679 for (size_t i = 0; i < numKeysByScanCode; i++) {
680 int32_t key = parcel->readInt32();
681 int32_t value = parcel->readInt32();
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000682 map->mKeysByScanCode.insert_or_assign(key, value);
Philip Junker90bc9492021-12-10 18:39:42 +0100683 if (parcel->errorCheck()) {
684 return nullptr;
685 }
686 }
687 size_t numKeysByUsageCode = parcel->readInt32();
688 if (parcel->errorCheck()) {
689 return nullptr;
690 }
691 for (size_t i = 0; i < numKeysByUsageCode; i++) {
692 int32_t key = parcel->readInt32();
693 int32_t value = parcel->readInt32();
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000694 map->mKeysByUsageCode.insert_or_assign(key, value);
Philip Junker90bc9492021-12-10 18:39:42 +0100695 if (parcel->errorCheck()) {
696 return nullptr;
697 }
698 }
Jeff Brown5912f952013-07-01 19:10:31 -0700699 return map;
700}
701
702void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
Chris Ye3a1e4462020-08-12 10:13:15 -0700703 if (parcel == nullptr) {
704 ALOGE("%s: Null parcel", __func__);
705 return;
706 }
Philip Junker90bc9492021-12-10 18:39:42 +0100707 parcel->writeCString(mLoadFileName.c_str());
Michael Wright102936e2020-11-04 03:44:27 +0000708 parcel->writeInt32(static_cast<int32_t>(mType));
Philip Junker90bc9492021-12-10 18:39:42 +0100709 parcel->writeBool(mLayoutOverlayApplied);
Jeff Brown5912f952013-07-01 19:10:31 -0700710
711 size_t numKeys = mKeys.size();
712 parcel->writeInt32(numKeys);
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700713 for (const auto& [keyCode, key] : mKeys) {
Jeff Brown5912f952013-07-01 19:10:31 -0700714 parcel->writeInt32(keyCode);
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700715 parcel->writeInt32(key.label);
716 parcel->writeInt32(key.number);
717 for (const Behavior& behavior : key.behaviors) {
Jeff Brown5912f952013-07-01 19:10:31 -0700718 parcel->writeInt32(1);
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700719 parcel->writeInt32(behavior.metaState);
720 parcel->writeInt32(behavior.character);
721 parcel->writeInt32(behavior.fallbackKeyCode);
722 parcel->writeInt32(behavior.replacementKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700723 }
724 parcel->writeInt32(0);
725 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000726 size_t numKeyRemapping = mKeyRemapping.size();
727 parcel->writeInt32(numKeyRemapping);
728 for (auto const& [fromAndroidKeyCode, toAndroidKeyCode] : mKeyRemapping) {
729 parcel->writeInt32(fromAndroidKeyCode);
730 parcel->writeInt32(toAndroidKeyCode);
731 }
Philip Junker90bc9492021-12-10 18:39:42 +0100732 size_t numKeysByScanCode = mKeysByScanCode.size();
733 parcel->writeInt32(numKeysByScanCode);
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000734 for (auto const& [fromScanCode, toAndroidKeyCode] : mKeysByScanCode) {
735 parcel->writeInt32(fromScanCode);
736 parcel->writeInt32(toAndroidKeyCode);
Philip Junker90bc9492021-12-10 18:39:42 +0100737 }
738 size_t numKeysByUsageCode = mKeysByUsageCode.size();
739 parcel->writeInt32(numKeysByUsageCode);
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000740 for (auto const& [fromUsageCode, toAndroidKeyCode] : mKeysByUsageCode) {
741 parcel->writeInt32(fromUsageCode);
742 parcel->writeInt32(toAndroidKeyCode);
Philip Junker90bc9492021-12-10 18:39:42 +0100743 }
Jeff Brown5912f952013-07-01 19:10:31 -0700744}
Jeff Brown5912f952013-07-01 19:10:31 -0700745
Jeff Brown5912f952013-07-01 19:10:31 -0700746// --- KeyCharacterMap::Parser ---
747
748KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
749 mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
750}
751
Jeff Brown5912f952013-07-01 19:10:31 -0700752status_t KeyCharacterMap::Parser::parse() {
753 while (!mTokenizer->isEof()) {
754#if DEBUG_PARSER
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000755 ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(),
756 mTokenizer->peekRemainderOfLine().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700757#endif
758
759 mTokenizer->skipDelimiters(WHITESPACE);
760
761 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
762 switch (mState) {
763 case STATE_TOP: {
764 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
765 if (keywordToken == "type") {
766 mTokenizer->skipDelimiters(WHITESPACE);
767 status_t status = parseType();
768 if (status) return status;
769 } else if (keywordToken == "map") {
770 mTokenizer->skipDelimiters(WHITESPACE);
771 status_t status = parseMap();
772 if (status) return status;
773 } else if (keywordToken == "key") {
774 mTokenizer->skipDelimiters(WHITESPACE);
775 status_t status = parseKey();
776 if (status) return status;
777 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000778 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().c_str(),
779 keywordToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700780 return BAD_VALUE;
781 }
782 break;
783 }
784
785 case STATE_KEY: {
786 status_t status = parseKeyProperty();
787 if (status) return status;
788 break;
789 }
790 }
791
792 mTokenizer->skipDelimiters(WHITESPACE);
793 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000794 ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
795 mTokenizer->getLocation().c_str(), mTokenizer->peekRemainderOfLine().c_str());
796 return BAD_VALUE;
Jeff Brown5912f952013-07-01 19:10:31 -0700797 }
798 }
799
800 mTokenizer->nextLine();
801 }
802
803 if (mState != STATE_TOP) {
804 ALOGE("%s: Unterminated key description at end of file.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000805 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700806 return BAD_VALUE;
807 }
808
Michael Wright102936e2020-11-04 03:44:27 +0000809 if (mMap->mType == KeyboardType::UNKNOWN) {
Jeff Brown5912f952013-07-01 19:10:31 -0700810 ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000811 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700812 return BAD_VALUE;
813 }
814
Michael Wright102936e2020-11-04 03:44:27 +0000815 if (mFormat == Format::BASE) {
816 if (mMap->mType == KeyboardType::OVERLAY) {
Jeff Brown5912f952013-07-01 19:10:31 -0700817 ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000818 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700819 return BAD_VALUE;
820 }
Michael Wright102936e2020-11-04 03:44:27 +0000821 } else if (mFormat == Format::OVERLAY) {
822 if (mMap->mType != KeyboardType::OVERLAY) {
Jeff Brown5912f952013-07-01 19:10:31 -0700823 ALOGE("%s: Overlay keyboard layout missing required keyboard "
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000824 "'type OVERLAY' declaration.",
825 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700826 return BAD_VALUE;
827 }
828 }
829
830 return NO_ERROR;
831}
832
833status_t KeyCharacterMap::Parser::parseType() {
Michael Wright102936e2020-11-04 03:44:27 +0000834 if (mMap->mType != KeyboardType::UNKNOWN) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000835 ALOGE("%s: Duplicate keyboard 'type' declaration.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700836 return BAD_VALUE;
837 }
838
839 KeyboardType type;
840 String8 typeToken = mTokenizer->nextToken(WHITESPACE);
841 if (typeToken == "NUMERIC") {
Michael Wright102936e2020-11-04 03:44:27 +0000842 type = KeyboardType::NUMERIC;
Jeff Brown5912f952013-07-01 19:10:31 -0700843 } else if (typeToken == "PREDICTIVE") {
Michael Wright102936e2020-11-04 03:44:27 +0000844 type = KeyboardType::PREDICTIVE;
Jeff Brown5912f952013-07-01 19:10:31 -0700845 } else if (typeToken == "ALPHA") {
Michael Wright102936e2020-11-04 03:44:27 +0000846 type = KeyboardType::ALPHA;
Jeff Brown5912f952013-07-01 19:10:31 -0700847 } else if (typeToken == "FULL") {
Michael Wright102936e2020-11-04 03:44:27 +0000848 type = KeyboardType::FULL;
Jeff Brown5912f952013-07-01 19:10:31 -0700849 } else if (typeToken == "SPECIAL_FUNCTION") {
Siarhei Vishniakou61da25a2018-02-15 21:04:49 -0600850 ALOGW("The SPECIAL_FUNCTION type is now declared in the device's IDC file, please set "
851 "the property 'keyboard.specialFunction' to '1' there instead.");
852 // TODO: return BAD_VALUE here in Q
Michael Wright102936e2020-11-04 03:44:27 +0000853 type = KeyboardType::SPECIAL_FUNCTION;
Jeff Brown5912f952013-07-01 19:10:31 -0700854 } else if (typeToken == "OVERLAY") {
Michael Wright102936e2020-11-04 03:44:27 +0000855 type = KeyboardType::OVERLAY;
Jeff Brown5912f952013-07-01 19:10:31 -0700856 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000857 ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().c_str(),
858 typeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700859 return BAD_VALUE;
860 }
861
862#if DEBUG_PARSER
863 ALOGD("Parsed type: type=%d.", type);
864#endif
865 mMap->mType = type;
866 return NO_ERROR;
867}
868
869status_t KeyCharacterMap::Parser::parseMap() {
870 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
871 if (keywordToken == "key") {
872 mTokenizer->skipDelimiters(WHITESPACE);
873 return parseMapKey();
874 }
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000875 ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().c_str(),
876 keywordToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700877 return BAD_VALUE;
878}
879
880status_t KeyCharacterMap::Parser::parseMapKey() {
881 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
882 bool mapUsage = false;
883 if (codeToken == "usage") {
884 mapUsage = true;
885 mTokenizer->skipDelimiters(WHITESPACE);
886 codeToken = mTokenizer->nextToken(WHITESPACE);
887 }
888
889 char* end;
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000890 int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0));
Jeff Brown5912f952013-07-01 19:10:31 -0700891 if (*end) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000892 ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().c_str(),
893 mapUsage ? "usage" : "scan code", codeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700894 return BAD_VALUE;
895 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000896 std::map<int32_t, int32_t>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
897 const auto it = map.find(code);
898 if (it != map.end()) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000899 ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().c_str(),
900 mapUsage ? "usage" : "scan code", codeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700901 return BAD_VALUE;
902 }
903
904 mTokenizer->skipDelimiters(WHITESPACE);
905 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000906 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700907 if (!keyCode) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000908 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(),
909 keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700910 return BAD_VALUE;
911 }
912
913#if DEBUG_PARSER
914 ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
915 mapUsage ? "usage" : "scan code", code, keyCode);
916#endif
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800917 map.insert_or_assign(code, *keyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700918 return NO_ERROR;
919}
920
921status_t KeyCharacterMap::Parser::parseKey() {
922 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000923 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700924 if (!keyCode) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000925 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(),
926 keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700927 return BAD_VALUE;
928 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700929 if (mMap->mKeys.find(*keyCode) != mMap->mKeys.end()) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000930 ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().c_str(),
931 keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700932 return BAD_VALUE;
933 }
934
935 mTokenizer->skipDelimiters(WHITESPACE);
936 String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
937 if (openBraceToken != "{") {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000938 ALOGE("%s: Expected '{' after key code label, got '%s'.", mTokenizer->getLocation().c_str(),
939 openBraceToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700940 return BAD_VALUE;
941 }
942
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800943 ALOGD_IF(DEBUG_PARSER, "Parsed beginning of key: keyCode=%d.", *keyCode);
944 mKeyCode = *keyCode;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700945 mMap->mKeys.emplace(*keyCode, Key{});
Jeff Brown5912f952013-07-01 19:10:31 -0700946 mState = STATE_KEY;
947 return NO_ERROR;
948}
949
950status_t KeyCharacterMap::Parser::parseKeyProperty() {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700951 Key& key = mMap->mKeys[mKeyCode];
Jeff Brown5912f952013-07-01 19:10:31 -0700952 String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
953 if (token == "}") {
954 mState = STATE_TOP;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700955 return finishKey(key);
Jeff Brown5912f952013-07-01 19:10:31 -0700956 }
957
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700958 std::vector<Property> properties;
Jeff Brown5912f952013-07-01 19:10:31 -0700959
960 // Parse all comma-delimited property names up to the first colon.
961 for (;;) {
962 if (token == "label") {
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700963 properties.emplace_back(PROPERTY_LABEL);
Jeff Brown5912f952013-07-01 19:10:31 -0700964 } else if (token == "number") {
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700965 properties.emplace_back(PROPERTY_NUMBER);
Jeff Brown5912f952013-07-01 19:10:31 -0700966 } else {
967 int32_t metaState;
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000968 status_t status = parseModifier(token.c_str(), &metaState);
Jeff Brown5912f952013-07-01 19:10:31 -0700969 if (status) {
970 ALOGE("%s: Expected a property name or modifier, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000971 mTokenizer->getLocation().c_str(), token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700972 return status;
973 }
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700974 properties.emplace_back(PROPERTY_META, metaState);
Jeff Brown5912f952013-07-01 19:10:31 -0700975 }
976
977 mTokenizer->skipDelimiters(WHITESPACE);
978 if (!mTokenizer->isEol()) {
979 char ch = mTokenizer->nextChar();
980 if (ch == ':') {
981 break;
982 } else if (ch == ',') {
983 mTokenizer->skipDelimiters(WHITESPACE);
984 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
985 continue;
986 }
987 }
988
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000989 ALOGE("%s: Expected ',' or ':' after property name.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700990 return BAD_VALUE;
991 }
992
993 // Parse behavior after the colon.
994 mTokenizer->skipDelimiters(WHITESPACE);
995
996 Behavior behavior;
997 bool haveCharacter = false;
998 bool haveFallback = false;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700999 bool haveReplacement = false;
Jeff Brown5912f952013-07-01 19:10:31 -07001000
1001 do {
1002 char ch = mTokenizer->peekChar();
1003 if (ch == '\'') {
1004 char16_t character;
1005 status_t status = parseCharacterLiteral(&character);
1006 if (status || !character) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001007 ALOGE("%s: Invalid character literal for key.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001008 return BAD_VALUE;
1009 }
1010 if (haveCharacter) {
1011 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001012 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001013 return BAD_VALUE;
1014 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001015 if (haveReplacement) {
1016 ALOGE("%s: Cannot combine character literal with replace action.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001017 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001018 return BAD_VALUE;
1019 }
Jeff Brown5912f952013-07-01 19:10:31 -07001020 behavior.character = character;
1021 haveCharacter = true;
1022 } else {
1023 token = mTokenizer->nextToken(WHITESPACE);
1024 if (token == "none") {
1025 if (haveCharacter) {
1026 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001027 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001028 return BAD_VALUE;
1029 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001030 if (haveReplacement) {
1031 ALOGE("%s: Cannot combine 'none' with replace action.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001032 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001033 return BAD_VALUE;
1034 }
Jeff Brown5912f952013-07-01 19:10:31 -07001035 haveCharacter = true;
1036 } else if (token == "fallback") {
1037 mTokenizer->skipDelimiters(WHITESPACE);
1038 token = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001039 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001040 if (!keyCode) {
1041 ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001042 mTokenizer->getLocation().c_str(), token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001043 return BAD_VALUE;
1044 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001045 if (haveFallback || haveReplacement) {
1046 ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001047 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001048 return BAD_VALUE;
1049 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001050 behavior.fallbackKeyCode = *keyCode;
Jeff Brown5912f952013-07-01 19:10:31 -07001051 haveFallback = true;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001052 } else if (token == "replace") {
1053 mTokenizer->skipDelimiters(WHITESPACE);
1054 token = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001055 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001056 if (!keyCode) {
1057 ALOGE("%s: Invalid key code label for replace, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001058 mTokenizer->getLocation().c_str(), token.c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001059 return BAD_VALUE;
1060 }
1061 if (haveCharacter) {
1062 ALOGE("%s: Cannot combine character literal with replace action.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001063 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001064 return BAD_VALUE;
1065 }
1066 if (haveFallback || haveReplacement) {
1067 ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001068 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001069 return BAD_VALUE;
1070 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001071 behavior.replacementKeyCode = *keyCode;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001072 haveReplacement = true;
1073
Jeff Brown5912f952013-07-01 19:10:31 -07001074 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001075 ALOGE("%s: Expected a key behavior after ':'.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001076 return BAD_VALUE;
1077 }
1078 }
1079
1080 mTokenizer->skipDelimiters(WHITESPACE);
1081 } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#');
1082
1083 // Add the behavior.
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -07001084 for (const Property& property : properties) {
Jeff Brown5912f952013-07-01 19:10:31 -07001085 switch (property.property) {
1086 case PROPERTY_LABEL:
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001087 if (key.label) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001088 ALOGE("%s: Duplicate label for key.", mTokenizer->getLocation().c_str());
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001089 return BAD_VALUE;
1090 }
1091 key.label = behavior.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001092#if DEBUG_PARSER
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001093 ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key.label);
Jeff Brown5912f952013-07-01 19:10:31 -07001094#endif
1095 break;
1096 case PROPERTY_NUMBER:
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001097 if (key.number) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001098 ALOGE("%s: Duplicate number for key.", mTokenizer->getLocation().c_str());
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001099 return BAD_VALUE;
Jeff Brown5912f952013-07-01 19:10:31 -07001100 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001101 key.number = behavior.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001102#if DEBUG_PARSER
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001103 ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key.number);
Jeff Brown5912f952013-07-01 19:10:31 -07001104#endif
1105 break;
1106 case PROPERTY_META: {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001107 for (const Behavior& b : key.behaviors) {
1108 if (b.metaState == property.metaState) {
Jeff Brown5912f952013-07-01 19:10:31 -07001109 ALOGE("%s: Duplicate key behavior for modifier.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001110 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001111 return BAD_VALUE;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001112 }
Jeff Brown5912f952013-07-01 19:10:31 -07001113 }
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001114 Behavior newBehavior = behavior;
1115 newBehavior.metaState = property.metaState;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001116 key.behaviors.push_front(newBehavior);
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001117 ALOGD_IF(DEBUG_PARSER,
1118 "Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001119 mKeyCode, key.behaviors.front().metaState, key.behaviors.front().character,
1120 key.behaviors.front().fallbackKeyCode,
1121 key.behaviors.front().replacementKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -07001122 break;
1123 }
1124 }
1125 }
1126 return NO_ERROR;
1127}
1128
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001129status_t KeyCharacterMap::Parser::finishKey(Key& key) {
Jeff Brown5912f952013-07-01 19:10:31 -07001130 // Fill in default number property.
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001131 if (!key.number) {
Jeff Brown5912f952013-07-01 19:10:31 -07001132 char16_t digit = 0;
1133 char16_t symbol = 0;
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001134 for (const Behavior& b : key.behaviors) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001135 char16_t ch = b.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001136 if (ch) {
1137 if (ch >= '0' && ch <= '9') {
1138 digit = ch;
1139 } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
1140 || ch == '-' || ch == '+' || ch == ',' || ch == '.'
1141 || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
1142 symbol = ch;
1143 }
1144 }
1145 }
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001146 key.number = digit ? digit : symbol;
Jeff Brown5912f952013-07-01 19:10:31 -07001147 }
1148 return NO_ERROR;
1149}
1150
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001151status_t KeyCharacterMap::Parser::parseModifier(const std::string& token, int32_t* outMetaState) {
Jeff Brown5912f952013-07-01 19:10:31 -07001152 if (token == "base") {
1153 *outMetaState = 0;
1154 return NO_ERROR;
1155 }
1156
1157 int32_t combinedMeta = 0;
1158
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001159 const char* str = token.c_str();
Jeff Brown5912f952013-07-01 19:10:31 -07001160 const char* start = str;
1161 for (const char* cur = str; ; cur++) {
1162 char ch = *cur;
1163 if (ch == '+' || ch == '\0') {
1164 size_t len = cur - start;
1165 int32_t metaState = 0;
1166 for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
1167 if (strlen(modifiers[i].label) == len
1168 && strncmp(modifiers[i].label, start, len) == 0) {
1169 metaState = modifiers[i].metaState;
1170 break;
1171 }
1172 }
1173 if (!metaState) {
1174 return BAD_VALUE;
1175 }
1176 if (combinedMeta & metaState) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001177 ALOGE("%s: Duplicate modifier combination '%s'.", mTokenizer->getLocation().c_str(),
1178 token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001179 return BAD_VALUE;
1180 }
1181
1182 combinedMeta |= metaState;
1183 start = cur + 1;
1184
1185 if (ch == '\0') {
1186 break;
1187 }
1188 }
1189 }
1190 *outMetaState = combinedMeta;
1191 return NO_ERROR;
1192}
1193
1194status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
1195 char ch = mTokenizer->nextChar();
1196 if (ch != '\'') {
1197 goto Error;
1198 }
1199
1200 ch = mTokenizer->nextChar();
1201 if (ch == '\\') {
1202 // Escape sequence.
1203 ch = mTokenizer->nextChar();
1204 if (ch == 'n') {
1205 *outCharacter = '\n';
1206 } else if (ch == 't') {
1207 *outCharacter = '\t';
1208 } else if (ch == '\\') {
1209 *outCharacter = '\\';
1210 } else if (ch == '\'') {
1211 *outCharacter = '\'';
1212 } else if (ch == '"') {
1213 *outCharacter = '"';
1214 } else if (ch == 'u') {
1215 *outCharacter = 0;
1216 for (int i = 0; i < 4; i++) {
1217 ch = mTokenizer->nextChar();
1218 int digit;
1219 if (ch >= '0' && ch <= '9') {
1220 digit = ch - '0';
1221 } else if (ch >= 'A' && ch <= 'F') {
1222 digit = ch - 'A' + 10;
1223 } else if (ch >= 'a' && ch <= 'f') {
1224 digit = ch - 'a' + 10;
1225 } else {
1226 goto Error;
1227 }
1228 *outCharacter = (*outCharacter << 4) | digit;
1229 }
1230 } else {
1231 goto Error;
1232 }
1233 } else if (ch >= 32 && ch <= 126 && ch != '\'') {
1234 // ASCII literal character.
1235 *outCharacter = ch;
1236 } else {
1237 goto Error;
1238 }
1239
1240 ch = mTokenizer->nextChar();
1241 if (ch != '\'') {
1242 goto Error;
1243 }
1244
1245 // Ensure that we consumed the entire token.
Tomasz Wasilczyke50b2de2023-08-14 18:03:09 +00001246 if (mTokenizer->nextToken(WHITESPACE).empty()) {
Jeff Brown5912f952013-07-01 19:10:31 -07001247 return NO_ERROR;
1248 }
1249
1250Error:
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001251 ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001252 return BAD_VALUE;
1253}
1254
1255} // namespace android