blob: 41909bfb2d996dc6dd2203d214a6b3a12bf37a71 [file] [log] [blame]
Jeff Brown5912f952013-07-01 19:10:31 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "KeyCharacterMap"
18
19#include <stdlib.h>
20#include <string.h>
21
Brett Chabotfaa986c2020-11-04 17:39:36 -080022#ifdef __linux__
Jeff Brown5912f952013-07-01 19:10:31 -070023#include <binder/Parcel.h>
Brett Chabotfaa986c2020-11-04 17:39:36 -080024#endif
Jeff Brown5912f952013-07-01 19:10:31 -070025#include <android/keycodes.h>
chaviw09c8d2d2020-08-24 15:48:26 -070026#include <attestation/HmacKeyManager.h>
Michael Wright872db4f2014-04-22 15:03:51 -070027#include <input/InputEventLabels.h>
Jeff Brown5912f952013-07-01 19:10:31 -070028#include <input/KeyCharacterMap.h>
chaviw09c8d2d2020-08-24 15:48:26 -070029#include <input/Keyboard.h>
Jeff Brown5912f952013-07-01 19:10:31 -070030
Jeff Brown5912f952013-07-01 19:10:31 -070031#include <utils/Errors.h>
chaviw98318de2021-05-19 16:45:23 -050032#include <utils/Log.h>
Jeff Brown5912f952013-07-01 19:10:31 -070033#include <utils/Timers.h>
chaviw98318de2021-05-19 16:45:23 -050034#include <utils/Tokenizer.h>
Jeff Brown5912f952013-07-01 19:10:31 -070035
36// Enables debug output for the parser.
37#define DEBUG_PARSER 0
38
39// Enables debug output for parser performance.
40#define DEBUG_PARSER_PERFORMANCE 0
41
42// Enables debug output for mapping.
43#define DEBUG_MAPPING 0
44
Jeff Brown5912f952013-07-01 19:10:31 -070045namespace android {
46
47static const char* WHITESPACE = " \t\r";
48static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:";
49
50struct Modifier {
51 const char* label;
52 int32_t metaState;
53};
54static const Modifier modifiers[] = {
55 { "shift", AMETA_SHIFT_ON },
56 { "lshift", AMETA_SHIFT_LEFT_ON },
57 { "rshift", AMETA_SHIFT_RIGHT_ON },
58 { "alt", AMETA_ALT_ON },
59 { "lalt", AMETA_ALT_LEFT_ON },
60 { "ralt", AMETA_ALT_RIGHT_ON },
61 { "ctrl", AMETA_CTRL_ON },
62 { "lctrl", AMETA_CTRL_LEFT_ON },
63 { "rctrl", AMETA_CTRL_RIGHT_ON },
64 { "meta", AMETA_META_ON },
65 { "lmeta", AMETA_META_LEFT_ON },
66 { "rmeta", AMETA_META_RIGHT_ON },
67 { "sym", AMETA_SYM_ON },
68 { "fn", AMETA_FUNCTION_ON },
69 { "capslock", AMETA_CAPS_LOCK_ON },
70 { "numlock", AMETA_NUM_LOCK_ON },
71 { "scrolllock", AMETA_SCROLL_LOCK_ON },
72};
73
74#if DEBUG_MAPPING
75static String8 toString(const char16_t* chars, size_t numChars) {
76 String8 result;
77 for (size_t i = 0; i < numChars; i++) {
78 result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]);
79 }
80 return result;
81}
82#endif
83
84
85// --- KeyCharacterMap ---
86
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -070087KeyCharacterMap::KeyCharacterMap(const std::string& filename) : mLoadFileName(filename) {}
Philip Junker90bc9492021-12-10 18:39:42 +010088
Chris Ye3a1e4462020-08-12 10:13:15 -070089base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename,
90 Format format) {
Jeff Brown5912f952013-07-01 19:10:31 -070091 Tokenizer* tokenizer;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +010092 status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
Jeff Brown5912f952013-07-01 19:10:31 -070093 if (status) {
Chris Ye3a1e4462020-08-12 10:13:15 -070094 return Errorf("Error {} opening key character map file {}.", status, filename.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -070095 }
Philip Junker90bc9492021-12-10 18:39:42 +010096 std::shared_ptr<KeyCharacterMap> map =
97 std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
98 if (!map.get()) {
99 ALOGE("Error allocating key character map.");
100 return Errorf("Error allocating key character map.");
Chris Ye3a1e4462020-08-12 10:13:15 -0700101 }
Philip Junker90bc9492021-12-10 18:39:42 +0100102 std::unique_ptr<Tokenizer> t(tokenizer);
103 status = map->load(t.get(), format);
104 if (status == OK) {
105 return map;
106 }
107 return Errorf("Load KeyCharacterMap failed {}.", status);
Jeff Brown5912f952013-07-01 19:10:31 -0700108}
109
Chris Ye3a1e4462020-08-12 10:13:15 -0700110base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::loadContents(
111 const std::string& filename, const char* contents, Format format) {
Jeff Brown5912f952013-07-01 19:10:31 -0700112 Tokenizer* tokenizer;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100113 status_t status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
Jeff Brown5912f952013-07-01 19:10:31 -0700114 if (status) {
115 ALOGE("Error %d opening key character map.", status);
Chris Ye3a1e4462020-08-12 10:13:15 -0700116 return Errorf("Error {} opening key character map.", status);
Jeff Brown5912f952013-07-01 19:10:31 -0700117 }
Philip Junker90bc9492021-12-10 18:39:42 +0100118 std::shared_ptr<KeyCharacterMap> map =
119 std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
Jeff Brown5912f952013-07-01 19:10:31 -0700120 if (!map.get()) {
121 ALOGE("Error allocating key character map.");
Chris Ye3a1e4462020-08-12 10:13:15 -0700122 return Errorf("Error allocating key character map.");
Jeff Brown5912f952013-07-01 19:10:31 -0700123 }
Philip Junker90bc9492021-12-10 18:39:42 +0100124 std::unique_ptr<Tokenizer> t(tokenizer);
125 status = map->load(t.get(), format);
126 if (status == OK) {
127 return map;
128 }
129 return Errorf("Load KeyCharacterMap failed {}.", status);
130}
131
132status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format) {
133 status_t status = OK;
Chris Ye3a1e4462020-08-12 10:13:15 -0700134#if DEBUG_PARSER_PERFORMANCE
135 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
136#endif
Philip Junker90bc9492021-12-10 18:39:42 +0100137 Parser parser(this, tokenizer, format);
Chris Ye3a1e4462020-08-12 10:13:15 -0700138 status = parser.parse();
139#if DEBUG_PARSER_PERFORMANCE
140 nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
141 ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000142 tokenizer->getFilename().c_str(), tokenizer->getLineNumber(), elapsedTime / 1000000.0);
Chris Ye3a1e4462020-08-12 10:13:15 -0700143#endif
Philip Junker90bc9492021-12-10 18:39:42 +0100144 if (status != OK) {
145 ALOGE("Loading KeyCharacterMap failed with status %s", statusToString(status).c_str());
Chris Ye3a1e4462020-08-12 10:13:15 -0700146 }
Philip Junker90bc9492021-12-10 18:39:42 +0100147 return status;
148}
Chris Ye3a1e4462020-08-12 10:13:15 -0700149
Philip Junker90bc9492021-12-10 18:39:42 +0100150void KeyCharacterMap::clear() {
151 mKeysByScanCode.clear();
152 mKeysByUsageCode.clear();
Philip Junker90bc9492021-12-10 18:39:42 +0100153 mKeys.clear();
154 mLayoutOverlayApplied = false;
155 mType = KeyboardType::UNKNOWN;
156}
157
158status_t KeyCharacterMap::reloadBaseFromFile() {
159 clear();
160 Tokenizer* tokenizer;
161 status_t status = Tokenizer::open(String8(mLoadFileName.c_str()), &tokenizer);
162 if (status) {
163 ALOGE("Error %s opening key character map file %s.", statusToString(status).c_str(),
164 mLoadFileName.c_str());
165 return status;
166 }
167 std::unique_ptr<Tokenizer> t(tokenizer);
168 return load(t.get(), KeyCharacterMap::Format::BASE);
Jeff Brown5912f952013-07-01 19:10:31 -0700169}
170
Chris Ye3a1e4462020-08-12 10:13:15 -0700171void KeyCharacterMap::combine(const KeyCharacterMap& overlay) {
Philip Junker90bc9492021-12-10 18:39:42 +0100172 if (mLayoutOverlayApplied) {
173 reloadBaseFromFile();
174 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700175 for (const auto& [keyCode, key] : overlay.mKeys) {
176 mKeys.insert_or_assign(keyCode, key);
Jeff Brown5912f952013-07-01 19:10:31 -0700177 }
178
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700179 for (const auto& [fromScanCode, toAndroidKeyCode] : overlay.mKeysByScanCode) {
180 mKeysByScanCode.insert_or_assign(fromScanCode, toAndroidKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700181 }
182
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700183 for (const auto& [fromHidUsageCode, toAndroidKeyCode] : overlay.mKeysByUsageCode) {
184 mKeysByUsageCode.insert_or_assign(fromHidUsageCode, toAndroidKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700185 }
Philip Junker90bc9492021-12-10 18:39:42 +0100186 mLayoutOverlayApplied = true;
Jeff Brown5912f952013-07-01 19:10:31 -0700187}
188
Vaibhav Devmurari23e8ae92022-12-29 12:07:56 +0000189void KeyCharacterMap::clearLayoutOverlay() {
190 if (mLayoutOverlayApplied) {
191 reloadBaseFromFile();
192 mLayoutOverlayApplied = false;
193 }
194}
195
Michael Wright102936e2020-11-04 03:44:27 +0000196KeyCharacterMap::KeyboardType KeyCharacterMap::getKeyboardType() const {
Jeff Brown5912f952013-07-01 19:10:31 -0700197 return mType;
198}
199
Chris Ye3a1e4462020-08-12 10:13:15 -0700200const std::string KeyCharacterMap::getLoadFileName() const {
201 return mLoadFileName;
202}
203
Jeff Brown5912f952013-07-01 19:10:31 -0700204char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const {
205 char16_t result = 0;
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700206 const Key* key = getKey(keyCode);
207 if (key != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700208 result = key->label;
209 }
210#if DEBUG_MAPPING
211 ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result);
212#endif
213 return result;
214}
215
216char16_t KeyCharacterMap::getNumber(int32_t keyCode) const {
217 char16_t result = 0;
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700218 const Key* key = getKey(keyCode);
219 if (key != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700220 result = key->number;
221 }
222#if DEBUG_MAPPING
223 ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result);
224#endif
225 return result;
226}
227
228char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
229 char16_t result = 0;
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700230 const Behavior* behavior = getKeyBehavior(keyCode, metaState);
231 if (behavior != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700232 result = behavior->character;
233 }
234#if DEBUG_MAPPING
235 ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result);
236#endif
237 return result;
238}
239
240bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState,
241 FallbackAction* outFallbackAction) const {
242 outFallbackAction->keyCode = 0;
243 outFallbackAction->metaState = 0;
244
245 bool result = false;
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700246 const Behavior* behavior = getKeyBehavior(keyCode, metaState);
247 if (behavior != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700248 if (behavior->fallbackKeyCode) {
249 outFallbackAction->keyCode = behavior->fallbackKeyCode;
250 outFallbackAction->metaState = metaState & ~behavior->metaState;
251 result = true;
252 }
253 }
254#if DEBUG_MAPPING
255 ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, "
256 "fallback keyCode=%d, fallback metaState=0x%08x.",
257 keyCode, metaState, result ? "true" : "false",
258 outFallbackAction->keyCode, outFallbackAction->metaState);
259#endif
260 return result;
261}
262
263char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars,
264 int32_t metaState) const {
265 char16_t result = 0;
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700266 const Key* key = getKey(keyCode);
267 if (key != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700268 // Try to find the most general behavior that maps to this character.
269 // For example, the base key behavior will usually be last in the list.
270 // However, if we find a perfect meta state match for one behavior then use that one.
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700271 for (const Behavior& behavior : key->behaviors) {
272 if (behavior.character) {
Jeff Brown5912f952013-07-01 19:10:31 -0700273 for (size_t i = 0; i < numChars; i++) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700274 if (behavior.character == chars[i]) {
275 result = behavior.character;
276 if ((behavior.metaState & metaState) == behavior.metaState) {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700277 // Found exact match!
278 return result;
Jeff Brown5912f952013-07-01 19:10:31 -0700279 }
280 break;
281 }
282 }
283 }
284 }
Jeff Brown5912f952013-07-01 19:10:31 -0700285 }
Jeff Brown5912f952013-07-01 19:10:31 -0700286 return result;
287}
288
289bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
290 Vector<KeyEvent>& outEvents) const {
291 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
292
293 for (size_t i = 0; i < numChars; i++) {
294 int32_t keyCode, metaState;
295 char16_t ch = chars[i];
296 if (!findKey(ch, &keyCode, &metaState)) {
297#if DEBUG_MAPPING
298 ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000299 deviceId, toString(chars, numChars).c_str(), ch);
Jeff Brown5912f952013-07-01 19:10:31 -0700300#endif
301 return false;
302 }
303
304 int32_t currentMetaState = 0;
305 addMetaKeys(outEvents, deviceId, metaState, true, now, &currentMetaState);
306 addKey(outEvents, deviceId, keyCode, currentMetaState, true, now);
307 addKey(outEvents, deviceId, keyCode, currentMetaState, false, now);
308 addMetaKeys(outEvents, deviceId, metaState, false, now, &currentMetaState);
309 }
310#if DEBUG_MAPPING
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000311 ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", deviceId,
312 toString(chars, numChars).c_str(), int32_t(outEvents.size()));
Jeff Brown5912f952013-07-01 19:10:31 -0700313 for (size_t i = 0; i < outEvents.size(); i++) {
314 ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.",
315 outEvents[i].getKeyCode(), outEvents[i].getMetaState(),
316 outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up");
317 }
318#endif
319 return true;
320}
321
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000322void KeyCharacterMap::addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode) {
323 if (fromKeyCode == toKeyCode) {
324 mKeyRemapping.erase(fromKeyCode);
325#if DEBUG_MAPPING
326 ALOGD("addKeyRemapping: Cleared remapping forKeyCode=%d ~ Result Successful.", fromKeyCode);
327#endif
328 return;
329 }
330 mKeyRemapping.insert_or_assign(fromKeyCode, toKeyCode);
331#if DEBUG_MAPPING
332 ALOGD("addKeyRemapping: fromKeyCode=%d, toKeyCode=%d ~ Result Successful.", fromKeyCode,
333 toKeyCode);
334#endif
335}
336
Jeff Brown5912f952013-07-01 19:10:31 -0700337status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
338 if (usageCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000339 const auto it = mKeysByUsageCode.find(usageCode);
340 if (it != mKeysByUsageCode.end()) {
341 *outKeyCode = it->second;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700342#if DEBUG_MAPPING
343 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
344 scanCode, usageCode, *outKeyCode);
345#endif
Jeff Brown5912f952013-07-01 19:10:31 -0700346 return OK;
347 }
348 }
349 if (scanCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000350 const auto it = mKeysByScanCode.find(scanCode);
351 if (it != mKeysByScanCode.end()) {
352 *outKeyCode = it->second;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700353#if DEBUG_MAPPING
354 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
355 scanCode, usageCode, *outKeyCode);
356#endif
Jeff Brown5912f952013-07-01 19:10:31 -0700357 return OK;
358 }
359 }
360
361#if DEBUG_MAPPING
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700362 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700363#endif
364 *outKeyCode = AKEYCODE_UNKNOWN;
365 return NAME_NOT_FOUND;
366}
367
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000368int32_t KeyCharacterMap::applyKeyRemapping(int32_t fromKeyCode) const {
369 int32_t toKeyCode = fromKeyCode;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700370
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000371 const auto it = mKeyRemapping.find(fromKeyCode);
372 if (it != mKeyRemapping.end()) {
373 toKeyCode = it->second;
374 }
375#if DEBUG_MAPPING
376 ALOGD("applyKeyRemapping: keyCode=%d ~ replacement keyCode=%d.", fromKeyCode, toKeyCode);
377#endif
378 return toKeyCode;
379}
380
381std::pair<int32_t, int32_t> KeyCharacterMap::applyKeyBehavior(int32_t fromKeyCode,
382 int32_t fromMetaState) const {
383 int32_t toKeyCode = fromKeyCode;
384 int32_t toMetaState = fromMetaState;
385
386 const Behavior* behavior = getKeyBehavior(fromKeyCode, fromMetaState);
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700387 if (behavior != nullptr) {
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700388 if (behavior->replacementKeyCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000389 toKeyCode = behavior->replacementKeyCode;
390 toMetaState = fromMetaState & ~behavior->metaState;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700391 // Reset dependent meta states.
392 if (behavior->metaState & AMETA_ALT_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000393 toMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700394 }
395 if (behavior->metaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000396 toMetaState &= ~AMETA_ALT_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700397 }
398 if (behavior->metaState & AMETA_CTRL_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000399 toMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700400 }
401 if (behavior->metaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000402 toMetaState &= ~AMETA_CTRL_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700403 }
404 if (behavior->metaState & AMETA_SHIFT_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000405 toMetaState &= ~(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700406 }
407 if (behavior->metaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000408 toMetaState &= ~AMETA_SHIFT_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700409 }
410 // ... and put universal bits back if needed
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000411 toMetaState = normalizeMetaState(toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700412 }
413 }
414
415#if DEBUG_MAPPING
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000416 ALOGD("applyKeyBehavior: keyCode=%d, metaState=0x%08x ~ "
417 "replacement keyCode=%d, replacement metaState=0x%08x.",
418 fromKeyCode, fromMetaState, toKeyCode, toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700419#endif
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000420 return std::make_pair(toKeyCode, toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700421}
422
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700423const KeyCharacterMap::Key* KeyCharacterMap::getKey(int32_t keyCode) const {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700424 auto it = mKeys.find(keyCode);
425 if (it != mKeys.end()) {
426 return &it->second;
Jeff Brown5912f952013-07-01 19:10:31 -0700427 }
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700428 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700429}
430
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700431const KeyCharacterMap::Behavior* KeyCharacterMap::getKeyBehavior(int32_t keyCode,
432 int32_t metaState) const {
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700433 const Key* key = getKey(keyCode);
434 if (key != nullptr) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700435 for (const Behavior& behavior : key->behaviors) {
436 if (matchesMetaState(metaState, behavior.metaState)) {
437 return &behavior;
Jeff Brown5912f952013-07-01 19:10:31 -0700438 }
Jeff Brown5912f952013-07-01 19:10:31 -0700439 }
440 }
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700441 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700442}
443
444bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
445 // Behavior must have at least the set of meta states specified.
446 // And if the key event has CTRL, ALT or META then the behavior must exactly
447 // match those, taking into account that a behavior can specify that it handles
448 // one, both or either of a left/right modifier pair.
449 if ((eventMetaState & behaviorMetaState) == behaviorMetaState) {
450 const int32_t EXACT_META_STATES =
451 AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON
452 | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON
453 | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON;
454 int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES;
455 if (behaviorMetaState & AMETA_CTRL_ON) {
456 unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
457 } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
458 unmatchedMetaState &= ~AMETA_CTRL_ON;
459 }
460 if (behaviorMetaState & AMETA_ALT_ON) {
461 unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
462 } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
463 unmatchedMetaState &= ~AMETA_ALT_ON;
464 }
465 if (behaviorMetaState & AMETA_META_ON) {
466 unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
467 } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
468 unmatchedMetaState &= ~AMETA_META_ON;
469 }
470 return !unmatchedMetaState;
471 }
472 return false;
473}
474
475bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
476 if (!ch) {
477 return false;
478 }
479
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700480 for (const auto& [keyCode, key] : mKeys) {
Jeff Brown5912f952013-07-01 19:10:31 -0700481 // Try to find the most general behavior that maps to this character.
482 // For example, the base key behavior will usually be last in the list.
Yi Kong5bed83b2018-07-17 12:53:47 -0700483 const Behavior* found = nullptr;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700484 for (const Behavior& behavior : key.behaviors) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700485 if (behavior.character == ch) {
486 found = &behavior;
Jeff Brown5912f952013-07-01 19:10:31 -0700487 }
488 }
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700489 if (found != nullptr) {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700490 *outKeyCode = keyCode;
Jeff Brown5912f952013-07-01 19:10:31 -0700491 *outMetaState = found->metaState;
492 return true;
493 }
494 }
495 return false;
496}
497
Linnan Li13bf76a2024-05-05 19:18:02 +0800498void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents, int32_t deviceId, int32_t keyCode,
499 int32_t metaState, bool down, nsecs_t time) {
Jeff Brown5912f952013-07-01 19:10:31 -0700500 outEvents.push();
501 KeyEvent& event = outEvents.editTop();
Linnan Li13bf76a2024-05-05 19:18:02 +0800502 event.initialize(InputEvent::nextId(), deviceId, AINPUT_SOURCE_KEYBOARD, ui::ADISPLAY_ID_NONE,
Garfield Tan4cc839f2020-01-24 11:26:14 -0800503 INVALID_HMAC, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 0, keyCode,
504 0, metaState, 0, time, time);
Jeff Brown5912f952013-07-01 19:10:31 -0700505}
506
507void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
508 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
509 int32_t* currentMetaState) {
510 // Add and remove meta keys symmetrically.
511 if (down) {
512 addLockedMetaKey(outEvents, deviceId, metaState, time,
513 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
514 addLockedMetaKey(outEvents, deviceId, metaState, time,
515 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
516 addLockedMetaKey(outEvents, deviceId, metaState, time,
517 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
518
519 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
520 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
521 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
522 AMETA_SHIFT_ON, currentMetaState);
523 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
524 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
525 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
526 AMETA_ALT_ON, currentMetaState);
527 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
528 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
529 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
530 AMETA_CTRL_ON, currentMetaState);
531 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
532 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
533 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
534 AMETA_META_ON, currentMetaState);
535
536 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
537 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
538 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
539 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
540 } else {
541 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
542 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
543 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
544 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
545
546 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
547 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
548 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
549 AMETA_META_ON, currentMetaState);
550 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
551 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
552 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
553 AMETA_CTRL_ON, currentMetaState);
554 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
555 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
556 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
557 AMETA_ALT_ON, currentMetaState);
558 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
559 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
560 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
561 AMETA_SHIFT_ON, currentMetaState);
562
563 addLockedMetaKey(outEvents, deviceId, metaState, time,
564 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
565 addLockedMetaKey(outEvents, deviceId, metaState, time,
566 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
567 addLockedMetaKey(outEvents, deviceId, metaState, time,
568 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
569 }
570}
571
572bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
573 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
574 int32_t keyCode, int32_t keyMetaState,
575 int32_t* currentMetaState) {
576 if ((metaState & keyMetaState) == keyMetaState) {
577 *currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
578 addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
579 return true;
580 }
581 return false;
582}
583
584void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
585 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
586 int32_t leftKeyCode, int32_t leftKeyMetaState,
587 int32_t rightKeyCode, int32_t rightKeyMetaState,
588 int32_t eitherKeyMetaState,
589 int32_t* currentMetaState) {
590 bool specific = false;
591 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
592 leftKeyCode, leftKeyMetaState, currentMetaState);
593 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
594 rightKeyCode, rightKeyMetaState, currentMetaState);
595
596 if (!specific) {
597 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
598 leftKeyCode, eitherKeyMetaState, currentMetaState);
599 }
600}
601
602void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
603 int32_t deviceId, int32_t metaState, nsecs_t time,
604 int32_t keyCode, int32_t keyMetaState,
605 int32_t* currentMetaState) {
606 if ((metaState & keyMetaState) == keyMetaState) {
607 *currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
608 addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
609 *currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
610 addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
611 }
612}
613
Brett Chabotfaa986c2020-11-04 17:39:36 -0800614#ifdef __linux__
Siarhei Vishniakouc62948e2023-10-23 07:22:01 -0700615std::unique_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
Chris Ye3a1e4462020-08-12 10:13:15 -0700616 if (parcel == nullptr) {
617 ALOGE("%s: Null parcel", __func__);
618 return nullptr;
619 }
Philip Junker90bc9492021-12-10 18:39:42 +0100620 std::string loadFileName = parcel->readCString();
Siarhei Vishniakouc62948e2023-10-23 07:22:01 -0700621 std::unique_ptr<KeyCharacterMap> map =
622 std::make_unique<KeyCharacterMap>(KeyCharacterMap(loadFileName));
Michael Wright102936e2020-11-04 03:44:27 +0000623 map->mType = static_cast<KeyCharacterMap::KeyboardType>(parcel->readInt32());
Philip Junker90bc9492021-12-10 18:39:42 +0100624 map->mLayoutOverlayApplied = parcel->readBool();
Jeff Brown5912f952013-07-01 19:10:31 -0700625 size_t numKeys = parcel->readInt32();
626 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700627 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700628 }
Michael Wright4c971c02015-10-21 14:38:03 +0100629 if (numKeys > MAX_KEYS) {
Ian Pedowitzd57d9b92016-02-19 08:34:43 +0000630 ALOGE("Too many keys in KeyCharacterMap (%zu > %d)", numKeys, MAX_KEYS);
Yi Kong5bed83b2018-07-17 12:53:47 -0700631 return nullptr;
Michael Wright4c971c02015-10-21 14:38:03 +0100632 }
Jeff Brown5912f952013-07-01 19:10:31 -0700633
634 for (size_t i = 0; i < numKeys; i++) {
635 int32_t keyCode = parcel->readInt32();
636 char16_t label = parcel->readInt32();
637 char16_t number = parcel->readInt32();
638 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700639 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700640 }
641
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700642 Key key{.label = label, .number = number};
Jeff Brown5912f952013-07-01 19:10:31 -0700643 while (parcel->readInt32()) {
644 int32_t metaState = parcel->readInt32();
645 char16_t character = parcel->readInt32();
646 int32_t fallbackKeyCode = parcel->readInt32();
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700647 int32_t replacementKeyCode = parcel->readInt32();
Jeff Brown5912f952013-07-01 19:10:31 -0700648 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700649 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700650 }
651
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700652 key.behaviors.push_back({
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700653 .metaState = metaState,
654 .character = character,
655 .fallbackKeyCode = fallbackKeyCode,
656 .replacementKeyCode = replacementKeyCode,
657 });
Jeff Brown5912f952013-07-01 19:10:31 -0700658 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700659 map->mKeys.emplace(keyCode, std::move(key));
Jeff Brown5912f952013-07-01 19:10:31 -0700660
661 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700662 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700663 }
664 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000665 size_t numKeyRemapping = parcel->readInt32();
666 if (parcel->errorCheck()) {
667 return nullptr;
668 }
669 for (size_t i = 0; i < numKeyRemapping; i++) {
670 int32_t key = parcel->readInt32();
671 int32_t value = parcel->readInt32();
672 map->mKeyRemapping.insert_or_assign(key, value);
673 if (parcel->errorCheck()) {
674 return nullptr;
675 }
676 }
Philip Junker90bc9492021-12-10 18:39:42 +0100677 size_t numKeysByScanCode = parcel->readInt32();
678 if (parcel->errorCheck()) {
679 return nullptr;
680 }
681 for (size_t i = 0; i < numKeysByScanCode; i++) {
682 int32_t key = parcel->readInt32();
683 int32_t value = parcel->readInt32();
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000684 map->mKeysByScanCode.insert_or_assign(key, value);
Philip Junker90bc9492021-12-10 18:39:42 +0100685 if (parcel->errorCheck()) {
686 return nullptr;
687 }
688 }
689 size_t numKeysByUsageCode = parcel->readInt32();
690 if (parcel->errorCheck()) {
691 return nullptr;
692 }
693 for (size_t i = 0; i < numKeysByUsageCode; i++) {
694 int32_t key = parcel->readInt32();
695 int32_t value = parcel->readInt32();
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000696 map->mKeysByUsageCode.insert_or_assign(key, value);
Philip Junker90bc9492021-12-10 18:39:42 +0100697 if (parcel->errorCheck()) {
698 return nullptr;
699 }
700 }
Jeff Brown5912f952013-07-01 19:10:31 -0700701 return map;
702}
703
704void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
Chris Ye3a1e4462020-08-12 10:13:15 -0700705 if (parcel == nullptr) {
706 ALOGE("%s: Null parcel", __func__);
707 return;
708 }
Philip Junker90bc9492021-12-10 18:39:42 +0100709 parcel->writeCString(mLoadFileName.c_str());
Michael Wright102936e2020-11-04 03:44:27 +0000710 parcel->writeInt32(static_cast<int32_t>(mType));
Philip Junker90bc9492021-12-10 18:39:42 +0100711 parcel->writeBool(mLayoutOverlayApplied);
Jeff Brown5912f952013-07-01 19:10:31 -0700712
713 size_t numKeys = mKeys.size();
714 parcel->writeInt32(numKeys);
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700715 for (const auto& [keyCode, key] : mKeys) {
Jeff Brown5912f952013-07-01 19:10:31 -0700716 parcel->writeInt32(keyCode);
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700717 parcel->writeInt32(key.label);
718 parcel->writeInt32(key.number);
719 for (const Behavior& behavior : key.behaviors) {
Jeff Brown5912f952013-07-01 19:10:31 -0700720 parcel->writeInt32(1);
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700721 parcel->writeInt32(behavior.metaState);
722 parcel->writeInt32(behavior.character);
723 parcel->writeInt32(behavior.fallbackKeyCode);
724 parcel->writeInt32(behavior.replacementKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700725 }
726 parcel->writeInt32(0);
727 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000728 size_t numKeyRemapping = mKeyRemapping.size();
729 parcel->writeInt32(numKeyRemapping);
730 for (auto const& [fromAndroidKeyCode, toAndroidKeyCode] : mKeyRemapping) {
731 parcel->writeInt32(fromAndroidKeyCode);
732 parcel->writeInt32(toAndroidKeyCode);
733 }
Philip Junker90bc9492021-12-10 18:39:42 +0100734 size_t numKeysByScanCode = mKeysByScanCode.size();
735 parcel->writeInt32(numKeysByScanCode);
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000736 for (auto const& [fromScanCode, toAndroidKeyCode] : mKeysByScanCode) {
737 parcel->writeInt32(fromScanCode);
738 parcel->writeInt32(toAndroidKeyCode);
Philip Junker90bc9492021-12-10 18:39:42 +0100739 }
740 size_t numKeysByUsageCode = mKeysByUsageCode.size();
741 parcel->writeInt32(numKeysByUsageCode);
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000742 for (auto const& [fromUsageCode, toAndroidKeyCode] : mKeysByUsageCode) {
743 parcel->writeInt32(fromUsageCode);
744 parcel->writeInt32(toAndroidKeyCode);
Philip Junker90bc9492021-12-10 18:39:42 +0100745 }
Jeff Brown5912f952013-07-01 19:10:31 -0700746}
Brett Chabotfaa986c2020-11-04 17:39:36 -0800747#endif // __linux__
Jeff Brown5912f952013-07-01 19:10:31 -0700748
Jeff Brown5912f952013-07-01 19:10:31 -0700749// --- KeyCharacterMap::Parser ---
750
751KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
752 mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
753}
754
Jeff Brown5912f952013-07-01 19:10:31 -0700755status_t KeyCharacterMap::Parser::parse() {
756 while (!mTokenizer->isEof()) {
757#if DEBUG_PARSER
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000758 ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(),
759 mTokenizer->peekRemainderOfLine().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700760#endif
761
762 mTokenizer->skipDelimiters(WHITESPACE);
763
764 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
765 switch (mState) {
766 case STATE_TOP: {
767 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
768 if (keywordToken == "type") {
769 mTokenizer->skipDelimiters(WHITESPACE);
770 status_t status = parseType();
771 if (status) return status;
772 } else if (keywordToken == "map") {
773 mTokenizer->skipDelimiters(WHITESPACE);
774 status_t status = parseMap();
775 if (status) return status;
776 } else if (keywordToken == "key") {
777 mTokenizer->skipDelimiters(WHITESPACE);
778 status_t status = parseKey();
779 if (status) return status;
780 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000781 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().c_str(),
782 keywordToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700783 return BAD_VALUE;
784 }
785 break;
786 }
787
788 case STATE_KEY: {
789 status_t status = parseKeyProperty();
790 if (status) return status;
791 break;
792 }
793 }
794
795 mTokenizer->skipDelimiters(WHITESPACE);
796 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000797 ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
798 mTokenizer->getLocation().c_str(), mTokenizer->peekRemainderOfLine().c_str());
799 return BAD_VALUE;
Jeff Brown5912f952013-07-01 19:10:31 -0700800 }
801 }
802
803 mTokenizer->nextLine();
804 }
805
806 if (mState != STATE_TOP) {
807 ALOGE("%s: Unterminated key description at end of file.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000808 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700809 return BAD_VALUE;
810 }
811
Michael Wright102936e2020-11-04 03:44:27 +0000812 if (mMap->mType == KeyboardType::UNKNOWN) {
Jeff Brown5912f952013-07-01 19:10:31 -0700813 ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000814 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700815 return BAD_VALUE;
816 }
817
Michael Wright102936e2020-11-04 03:44:27 +0000818 if (mFormat == Format::BASE) {
819 if (mMap->mType == KeyboardType::OVERLAY) {
Jeff Brown5912f952013-07-01 19:10:31 -0700820 ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000821 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700822 return BAD_VALUE;
823 }
Michael Wright102936e2020-11-04 03:44:27 +0000824 } else if (mFormat == Format::OVERLAY) {
825 if (mMap->mType != KeyboardType::OVERLAY) {
Jeff Brown5912f952013-07-01 19:10:31 -0700826 ALOGE("%s: Overlay keyboard layout missing required keyboard "
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000827 "'type OVERLAY' declaration.",
828 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700829 return BAD_VALUE;
830 }
831 }
832
833 return NO_ERROR;
834}
835
836status_t KeyCharacterMap::Parser::parseType() {
Michael Wright102936e2020-11-04 03:44:27 +0000837 if (mMap->mType != KeyboardType::UNKNOWN) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000838 ALOGE("%s: Duplicate keyboard 'type' declaration.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700839 return BAD_VALUE;
840 }
841
842 KeyboardType type;
843 String8 typeToken = mTokenizer->nextToken(WHITESPACE);
844 if (typeToken == "NUMERIC") {
Michael Wright102936e2020-11-04 03:44:27 +0000845 type = KeyboardType::NUMERIC;
Jeff Brown5912f952013-07-01 19:10:31 -0700846 } else if (typeToken == "PREDICTIVE") {
Michael Wright102936e2020-11-04 03:44:27 +0000847 type = KeyboardType::PREDICTIVE;
Jeff Brown5912f952013-07-01 19:10:31 -0700848 } else if (typeToken == "ALPHA") {
Michael Wright102936e2020-11-04 03:44:27 +0000849 type = KeyboardType::ALPHA;
Jeff Brown5912f952013-07-01 19:10:31 -0700850 } else if (typeToken == "FULL") {
Michael Wright102936e2020-11-04 03:44:27 +0000851 type = KeyboardType::FULL;
Jeff Brown5912f952013-07-01 19:10:31 -0700852 } else if (typeToken == "SPECIAL_FUNCTION") {
Siarhei Vishniakou61da25a2018-02-15 21:04:49 -0600853 ALOGW("The SPECIAL_FUNCTION type is now declared in the device's IDC file, please set "
854 "the property 'keyboard.specialFunction' to '1' there instead.");
855 // TODO: return BAD_VALUE here in Q
Michael Wright102936e2020-11-04 03:44:27 +0000856 type = KeyboardType::SPECIAL_FUNCTION;
Jeff Brown5912f952013-07-01 19:10:31 -0700857 } else if (typeToken == "OVERLAY") {
Michael Wright102936e2020-11-04 03:44:27 +0000858 type = KeyboardType::OVERLAY;
Jeff Brown5912f952013-07-01 19:10:31 -0700859 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000860 ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().c_str(),
861 typeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700862 return BAD_VALUE;
863 }
864
865#if DEBUG_PARSER
866 ALOGD("Parsed type: type=%d.", type);
867#endif
868 mMap->mType = type;
869 return NO_ERROR;
870}
871
872status_t KeyCharacterMap::Parser::parseMap() {
873 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
874 if (keywordToken == "key") {
875 mTokenizer->skipDelimiters(WHITESPACE);
876 return parseMapKey();
877 }
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000878 ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().c_str(),
879 keywordToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700880 return BAD_VALUE;
881}
882
883status_t KeyCharacterMap::Parser::parseMapKey() {
884 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
885 bool mapUsage = false;
886 if (codeToken == "usage") {
887 mapUsage = true;
888 mTokenizer->skipDelimiters(WHITESPACE);
889 codeToken = mTokenizer->nextToken(WHITESPACE);
890 }
891
892 char* end;
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000893 int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0));
Jeff Brown5912f952013-07-01 19:10:31 -0700894 if (*end) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000895 ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().c_str(),
896 mapUsage ? "usage" : "scan code", codeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700897 return BAD_VALUE;
898 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000899 std::map<int32_t, int32_t>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
900 const auto it = map.find(code);
901 if (it != map.end()) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000902 ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().c_str(),
903 mapUsage ? "usage" : "scan code", codeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700904 return BAD_VALUE;
905 }
906
907 mTokenizer->skipDelimiters(WHITESPACE);
908 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000909 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700910 if (!keyCode) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000911 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(),
912 keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700913 return BAD_VALUE;
914 }
915
916#if DEBUG_PARSER
917 ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
918 mapUsage ? "usage" : "scan code", code, keyCode);
919#endif
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800920 map.insert_or_assign(code, *keyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700921 return NO_ERROR;
922}
923
924status_t KeyCharacterMap::Parser::parseKey() {
925 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000926 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700927 if (!keyCode) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000928 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(),
929 keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700930 return BAD_VALUE;
931 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700932 if (mMap->mKeys.find(*keyCode) != mMap->mKeys.end()) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000933 ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().c_str(),
934 keyCodeToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700935 return BAD_VALUE;
936 }
937
938 mTokenizer->skipDelimiters(WHITESPACE);
939 String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
940 if (openBraceToken != "{") {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000941 ALOGE("%s: Expected '{' after key code label, got '%s'.", mTokenizer->getLocation().c_str(),
942 openBraceToken.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700943 return BAD_VALUE;
944 }
945
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800946 ALOGD_IF(DEBUG_PARSER, "Parsed beginning of key: keyCode=%d.", *keyCode);
947 mKeyCode = *keyCode;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700948 mMap->mKeys.emplace(*keyCode, Key{});
Jeff Brown5912f952013-07-01 19:10:31 -0700949 mState = STATE_KEY;
950 return NO_ERROR;
951}
952
953status_t KeyCharacterMap::Parser::parseKeyProperty() {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700954 Key& key = mMap->mKeys[mKeyCode];
Jeff Brown5912f952013-07-01 19:10:31 -0700955 String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
956 if (token == "}") {
957 mState = STATE_TOP;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700958 return finishKey(key);
Jeff Brown5912f952013-07-01 19:10:31 -0700959 }
960
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700961 std::vector<Property> properties;
Jeff Brown5912f952013-07-01 19:10:31 -0700962
963 // Parse all comma-delimited property names up to the first colon.
964 for (;;) {
965 if (token == "label") {
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700966 properties.emplace_back(PROPERTY_LABEL);
Jeff Brown5912f952013-07-01 19:10:31 -0700967 } else if (token == "number") {
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700968 properties.emplace_back(PROPERTY_NUMBER);
Jeff Brown5912f952013-07-01 19:10:31 -0700969 } else {
970 int32_t metaState;
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000971 status_t status = parseModifier(token.c_str(), &metaState);
Jeff Brown5912f952013-07-01 19:10:31 -0700972 if (status) {
973 ALOGE("%s: Expected a property name or modifier, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000974 mTokenizer->getLocation().c_str(), token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700975 return status;
976 }
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700977 properties.emplace_back(PROPERTY_META, metaState);
Jeff Brown5912f952013-07-01 19:10:31 -0700978 }
979
980 mTokenizer->skipDelimiters(WHITESPACE);
981 if (!mTokenizer->isEol()) {
982 char ch = mTokenizer->nextChar();
983 if (ch == ':') {
984 break;
985 } else if (ch == ',') {
986 mTokenizer->skipDelimiters(WHITESPACE);
987 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
988 continue;
989 }
990 }
991
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +0000992 ALOGE("%s: Expected ',' or ':' after property name.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700993 return BAD_VALUE;
994 }
995
996 // Parse behavior after the colon.
997 mTokenizer->skipDelimiters(WHITESPACE);
998
999 Behavior behavior;
1000 bool haveCharacter = false;
1001 bool haveFallback = false;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001002 bool haveReplacement = false;
Jeff Brown5912f952013-07-01 19:10:31 -07001003
1004 do {
1005 char ch = mTokenizer->peekChar();
1006 if (ch == '\'') {
1007 char16_t character;
1008 status_t status = parseCharacterLiteral(&character);
1009 if (status || !character) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001010 ALOGE("%s: Invalid character literal for key.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001011 return BAD_VALUE;
1012 }
1013 if (haveCharacter) {
1014 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001015 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001016 return BAD_VALUE;
1017 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001018 if (haveReplacement) {
1019 ALOGE("%s: Cannot combine character literal with replace action.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001020 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001021 return BAD_VALUE;
1022 }
Jeff Brown5912f952013-07-01 19:10:31 -07001023 behavior.character = character;
1024 haveCharacter = true;
1025 } else {
1026 token = mTokenizer->nextToken(WHITESPACE);
1027 if (token == "none") {
1028 if (haveCharacter) {
1029 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001030 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001031 return BAD_VALUE;
1032 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001033 if (haveReplacement) {
1034 ALOGE("%s: Cannot combine 'none' with replace action.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001035 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001036 return BAD_VALUE;
1037 }
Jeff Brown5912f952013-07-01 19:10:31 -07001038 haveCharacter = true;
1039 } else if (token == "fallback") {
1040 mTokenizer->skipDelimiters(WHITESPACE);
1041 token = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001042 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001043 if (!keyCode) {
1044 ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001045 mTokenizer->getLocation().c_str(), token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001046 return BAD_VALUE;
1047 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001048 if (haveFallback || haveReplacement) {
1049 ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001050 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001051 return BAD_VALUE;
1052 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001053 behavior.fallbackKeyCode = *keyCode;
Jeff Brown5912f952013-07-01 19:10:31 -07001054 haveFallback = true;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001055 } else if (token == "replace") {
1056 mTokenizer->skipDelimiters(WHITESPACE);
1057 token = mTokenizer->nextToken(WHITESPACE);
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001058 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001059 if (!keyCode) {
1060 ALOGE("%s: Invalid key code label for replace, got '%s'.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001061 mTokenizer->getLocation().c_str(), token.c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001062 return BAD_VALUE;
1063 }
1064 if (haveCharacter) {
1065 ALOGE("%s: Cannot combine character literal with replace action.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001066 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001067 return BAD_VALUE;
1068 }
1069 if (haveFallback || haveReplacement) {
1070 ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001071 mTokenizer->getLocation().c_str());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001072 return BAD_VALUE;
1073 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001074 behavior.replacementKeyCode = *keyCode;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001075 haveReplacement = true;
1076
Jeff Brown5912f952013-07-01 19:10:31 -07001077 } else {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001078 ALOGE("%s: Expected a key behavior after ':'.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001079 return BAD_VALUE;
1080 }
1081 }
1082
1083 mTokenizer->skipDelimiters(WHITESPACE);
1084 } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#');
1085
1086 // Add the behavior.
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -07001087 for (const Property& property : properties) {
Jeff Brown5912f952013-07-01 19:10:31 -07001088 switch (property.property) {
1089 case PROPERTY_LABEL:
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001090 if (key.label) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001091 ALOGE("%s: Duplicate label for key.", mTokenizer->getLocation().c_str());
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001092 return BAD_VALUE;
1093 }
1094 key.label = behavior.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001095#if DEBUG_PARSER
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001096 ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key.label);
Jeff Brown5912f952013-07-01 19:10:31 -07001097#endif
1098 break;
1099 case PROPERTY_NUMBER:
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001100 if (key.number) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001101 ALOGE("%s: Duplicate number for key.", mTokenizer->getLocation().c_str());
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001102 return BAD_VALUE;
Jeff Brown5912f952013-07-01 19:10:31 -07001103 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001104 key.number = behavior.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001105#if DEBUG_PARSER
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001106 ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key.number);
Jeff Brown5912f952013-07-01 19:10:31 -07001107#endif
1108 break;
1109 case PROPERTY_META: {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001110 for (const Behavior& b : key.behaviors) {
1111 if (b.metaState == property.metaState) {
Jeff Brown5912f952013-07-01 19:10:31 -07001112 ALOGE("%s: Duplicate key behavior for modifier.",
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001113 mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001114 return BAD_VALUE;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001115 }
Jeff Brown5912f952013-07-01 19:10:31 -07001116 }
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001117 Behavior newBehavior = behavior;
1118 newBehavior.metaState = property.metaState;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001119 key.behaviors.push_front(newBehavior);
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001120 ALOGD_IF(DEBUG_PARSER,
1121 "Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001122 mKeyCode, key.behaviors.front().metaState, key.behaviors.front().character,
1123 key.behaviors.front().fallbackKeyCode,
1124 key.behaviors.front().replacementKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -07001125 break;
1126 }
1127 }
1128 }
1129 return NO_ERROR;
1130}
1131
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001132status_t KeyCharacterMap::Parser::finishKey(Key& key) {
Jeff Brown5912f952013-07-01 19:10:31 -07001133 // Fill in default number property.
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001134 if (!key.number) {
Jeff Brown5912f952013-07-01 19:10:31 -07001135 char16_t digit = 0;
1136 char16_t symbol = 0;
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001137 for (const Behavior& b : key.behaviors) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001138 char16_t ch = b.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001139 if (ch) {
1140 if (ch >= '0' && ch <= '9') {
1141 digit = ch;
1142 } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
1143 || ch == '-' || ch == '+' || ch == ',' || ch == '.'
1144 || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
1145 symbol = ch;
1146 }
1147 }
1148 }
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001149 key.number = digit ? digit : symbol;
Jeff Brown5912f952013-07-01 19:10:31 -07001150 }
1151 return NO_ERROR;
1152}
1153
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001154status_t KeyCharacterMap::Parser::parseModifier(const std::string& token, int32_t* outMetaState) {
Jeff Brown5912f952013-07-01 19:10:31 -07001155 if (token == "base") {
1156 *outMetaState = 0;
1157 return NO_ERROR;
1158 }
1159
1160 int32_t combinedMeta = 0;
1161
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001162 const char* str = token.c_str();
Jeff Brown5912f952013-07-01 19:10:31 -07001163 const char* start = str;
1164 for (const char* cur = str; ; cur++) {
1165 char ch = *cur;
1166 if (ch == '+' || ch == '\0') {
1167 size_t len = cur - start;
1168 int32_t metaState = 0;
1169 for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
1170 if (strlen(modifiers[i].label) == len
1171 && strncmp(modifiers[i].label, start, len) == 0) {
1172 metaState = modifiers[i].metaState;
1173 break;
1174 }
1175 }
1176 if (!metaState) {
1177 return BAD_VALUE;
1178 }
1179 if (combinedMeta & metaState) {
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001180 ALOGE("%s: Duplicate modifier combination '%s'.", mTokenizer->getLocation().c_str(),
1181 token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001182 return BAD_VALUE;
1183 }
1184
1185 combinedMeta |= metaState;
1186 start = cur + 1;
1187
1188 if (ch == '\0') {
1189 break;
1190 }
1191 }
1192 }
1193 *outMetaState = combinedMeta;
1194 return NO_ERROR;
1195}
1196
1197status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
1198 char ch = mTokenizer->nextChar();
1199 if (ch != '\'') {
1200 goto Error;
1201 }
1202
1203 ch = mTokenizer->nextChar();
1204 if (ch == '\\') {
1205 // Escape sequence.
1206 ch = mTokenizer->nextChar();
1207 if (ch == 'n') {
1208 *outCharacter = '\n';
1209 } else if (ch == 't') {
1210 *outCharacter = '\t';
1211 } else if (ch == '\\') {
1212 *outCharacter = '\\';
1213 } else if (ch == '\'') {
1214 *outCharacter = '\'';
1215 } else if (ch == '"') {
1216 *outCharacter = '"';
1217 } else if (ch == 'u') {
1218 *outCharacter = 0;
1219 for (int i = 0; i < 4; i++) {
1220 ch = mTokenizer->nextChar();
1221 int digit;
1222 if (ch >= '0' && ch <= '9') {
1223 digit = ch - '0';
1224 } else if (ch >= 'A' && ch <= 'F') {
1225 digit = ch - 'A' + 10;
1226 } else if (ch >= 'a' && ch <= 'f') {
1227 digit = ch - 'a' + 10;
1228 } else {
1229 goto Error;
1230 }
1231 *outCharacter = (*outCharacter << 4) | digit;
1232 }
1233 } else {
1234 goto Error;
1235 }
1236 } else if (ch >= 32 && ch <= 126 && ch != '\'') {
1237 // ASCII literal character.
1238 *outCharacter = ch;
1239 } else {
1240 goto Error;
1241 }
1242
1243 ch = mTokenizer->nextChar();
1244 if (ch != '\'') {
1245 goto Error;
1246 }
1247
1248 // Ensure that we consumed the entire token.
Tomasz Wasilczyke50b2de2023-08-14 18:03:09 +00001249 if (mTokenizer->nextToken(WHITESPACE).empty()) {
Jeff Brown5912f952013-07-01 19:10:31 -07001250 return NO_ERROR;
1251 }
1252
1253Error:
Tomasz Wasilczyk00eac292023-08-16 15:04:36 +00001254 ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001255 return BAD_VALUE;
1256}
1257
1258} // namespace android