blob: 422e6e09eb39b208ee872334232f5d4aff11560e [file] [log] [blame]
Jeff Brown5912f952013-07-01 19:10:31 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "KeyCharacterMap"
18
19#include <stdlib.h>
20#include <string.h>
21
Brett Chabotfaa986c2020-11-04 17:39:36 -080022#ifdef __linux__
Jeff Brown5912f952013-07-01 19:10:31 -070023#include <binder/Parcel.h>
Brett Chabotfaa986c2020-11-04 17:39:36 -080024#endif
Jeff Brown5912f952013-07-01 19:10:31 -070025#include <android/keycodes.h>
chaviw09c8d2d2020-08-24 15:48:26 -070026#include <attestation/HmacKeyManager.h>
Michael Wright872db4f2014-04-22 15:03:51 -070027#include <input/InputEventLabels.h>
Jeff Brown5912f952013-07-01 19:10:31 -070028#include <input/KeyCharacterMap.h>
chaviw09c8d2d2020-08-24 15:48:26 -070029#include <input/Keyboard.h>
Jeff Brown5912f952013-07-01 19:10:31 -070030
chaviw98318de2021-05-19 16:45:23 -050031#include <gui/constants.h>
Jeff Brown5912f952013-07-01 19:10:31 -070032#include <utils/Errors.h>
chaviw98318de2021-05-19 16:45:23 -050033#include <utils/Log.h>
Jeff Brown5912f952013-07-01 19:10:31 -070034#include <utils/Timers.h>
chaviw98318de2021-05-19 16:45:23 -050035#include <utils/Tokenizer.h>
Jeff Brown5912f952013-07-01 19:10:31 -070036
37// Enables debug output for the parser.
38#define DEBUG_PARSER 0
39
40// Enables debug output for parser performance.
41#define DEBUG_PARSER_PERFORMANCE 0
42
43// Enables debug output for mapping.
44#define DEBUG_MAPPING 0
45
46
47namespace android {
48
49static const char* WHITESPACE = " \t\r";
50static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:";
51
52struct Modifier {
53 const char* label;
54 int32_t metaState;
55};
56static const Modifier modifiers[] = {
57 { "shift", AMETA_SHIFT_ON },
58 { "lshift", AMETA_SHIFT_LEFT_ON },
59 { "rshift", AMETA_SHIFT_RIGHT_ON },
60 { "alt", AMETA_ALT_ON },
61 { "lalt", AMETA_ALT_LEFT_ON },
62 { "ralt", AMETA_ALT_RIGHT_ON },
63 { "ctrl", AMETA_CTRL_ON },
64 { "lctrl", AMETA_CTRL_LEFT_ON },
65 { "rctrl", AMETA_CTRL_RIGHT_ON },
66 { "meta", AMETA_META_ON },
67 { "lmeta", AMETA_META_LEFT_ON },
68 { "rmeta", AMETA_META_RIGHT_ON },
69 { "sym", AMETA_SYM_ON },
70 { "fn", AMETA_FUNCTION_ON },
71 { "capslock", AMETA_CAPS_LOCK_ON },
72 { "numlock", AMETA_NUM_LOCK_ON },
73 { "scrolllock", AMETA_SCROLL_LOCK_ON },
74};
75
76#if DEBUG_MAPPING
77static String8 toString(const char16_t* chars, size_t numChars) {
78 String8 result;
79 for (size_t i = 0; i < numChars; i++) {
80 result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]);
81 }
82 return result;
83}
84#endif
85
86
87// --- KeyCharacterMap ---
88
Philip Junker90bc9492021-12-10 18:39:42 +010089KeyCharacterMap::KeyCharacterMap(const std::string& filename)
90 : mType(KeyboardType::UNKNOWN), mLoadFileName(filename) {}
Jeff Brown5912f952013-07-01 19:10:31 -070091
Chris Ye3a1e4462020-08-12 10:13:15 -070092KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other)
93 : mType(other.mType),
Philip Junker90bc9492021-12-10 18:39:42 +010094 mLoadFileName(other.mLoadFileName),
95 mLayoutOverlayApplied(other.mLayoutOverlayApplied),
Chris Ye3a1e4462020-08-12 10:13:15 -070096 mKeysByScanCode(other.mKeysByScanCode),
97 mKeysByUsageCode(other.mKeysByUsageCode) {
Jeff Brown5912f952013-07-01 19:10:31 -070098 for (size_t i = 0; i < other.mKeys.size(); i++) {
99 mKeys.add(other.mKeys.keyAt(i), new Key(*other.mKeys.valueAt(i)));
100 }
101}
102
103KeyCharacterMap::~KeyCharacterMap() {
Philip Junker90bc9492021-12-10 18:39:42 +0100104 clear();
Jeff Brown5912f952013-07-01 19:10:31 -0700105}
106
Chris Yef59a2f42020-10-16 12:55:26 -0700107bool KeyCharacterMap::operator==(const KeyCharacterMap& other) const {
108 if (mType != other.mType) {
109 return false;
110 }
Philip Junker90bc9492021-12-10 18:39:42 +0100111 if (mLoadFileName != other.mLoadFileName) {
112 return false;
113 }
114 if (mLayoutOverlayApplied != other.mLayoutOverlayApplied) {
115 return false;
116 }
Chris Yef59a2f42020-10-16 12:55:26 -0700117 if (mKeys.size() != other.mKeys.size() ||
118 mKeysByScanCode.size() != other.mKeysByScanCode.size() ||
119 mKeysByUsageCode.size() != other.mKeysByUsageCode.size()) {
120 return false;
121 }
122
123 for (size_t i = 0; i < mKeys.size(); i++) {
124 if (mKeys.keyAt(i) != other.mKeys.keyAt(i)) {
125 return false;
126 }
127 const Key* key = mKeys.valueAt(i);
128 const Key* otherKey = other.mKeys.valueAt(i);
129 if (key->label != otherKey->label || key->number != otherKey->number) {
130 return false;
131 }
132 }
133
134 for (size_t i = 0; i < mKeysByScanCode.size(); i++) {
135 if (mKeysByScanCode.keyAt(i) != other.mKeysByScanCode.keyAt(i)) {
136 return false;
137 }
138 if (mKeysByScanCode.valueAt(i) != other.mKeysByScanCode.valueAt(i)) {
139 return false;
140 }
141 }
142
143 for (size_t i = 0; i < mKeysByUsageCode.size(); i++) {
144 if (mKeysByUsageCode.keyAt(i) != other.mKeysByUsageCode.keyAt(i)) {
145 return false;
146 }
147 if (mKeysByUsageCode.valueAt(i) != other.mKeysByUsageCode.valueAt(i)) {
148 return false;
149 }
150 }
151
152 return true;
153}
154
Philip Junker90bc9492021-12-10 18:39:42 +0100155bool KeyCharacterMap::operator!=(const KeyCharacterMap& other) const {
156 return !(*this == other);
157}
158
Chris Ye3a1e4462020-08-12 10:13:15 -0700159base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename,
160 Format format) {
Jeff Brown5912f952013-07-01 19:10:31 -0700161 Tokenizer* tokenizer;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100162 status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
Jeff Brown5912f952013-07-01 19:10:31 -0700163 if (status) {
Chris Ye3a1e4462020-08-12 10:13:15 -0700164 return Errorf("Error {} opening key character map file {}.", status, filename.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700165 }
Philip Junker90bc9492021-12-10 18:39:42 +0100166 std::shared_ptr<KeyCharacterMap> map =
167 std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
168 if (!map.get()) {
169 ALOGE("Error allocating key character map.");
170 return Errorf("Error allocating key character map.");
Chris Ye3a1e4462020-08-12 10:13:15 -0700171 }
Philip Junker90bc9492021-12-10 18:39:42 +0100172 std::unique_ptr<Tokenizer> t(tokenizer);
173 status = map->load(t.get(), format);
174 if (status == OK) {
175 return map;
176 }
177 return Errorf("Load KeyCharacterMap failed {}.", status);
Jeff Brown5912f952013-07-01 19:10:31 -0700178}
179
Chris Ye3a1e4462020-08-12 10:13:15 -0700180base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::loadContents(
181 const std::string& filename, const char* contents, Format format) {
Jeff Brown5912f952013-07-01 19:10:31 -0700182 Tokenizer* tokenizer;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100183 status_t status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
Jeff Brown5912f952013-07-01 19:10:31 -0700184 if (status) {
185 ALOGE("Error %d opening key character map.", status);
Chris Ye3a1e4462020-08-12 10:13:15 -0700186 return Errorf("Error {} opening key character map.", status);
Jeff Brown5912f952013-07-01 19:10:31 -0700187 }
Philip Junker90bc9492021-12-10 18:39:42 +0100188 std::shared_ptr<KeyCharacterMap> map =
189 std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
Jeff Brown5912f952013-07-01 19:10:31 -0700190 if (!map.get()) {
191 ALOGE("Error allocating key character map.");
Chris Ye3a1e4462020-08-12 10:13:15 -0700192 return Errorf("Error allocating key character map.");
Jeff Brown5912f952013-07-01 19:10:31 -0700193 }
Philip Junker90bc9492021-12-10 18:39:42 +0100194 std::unique_ptr<Tokenizer> t(tokenizer);
195 status = map->load(t.get(), format);
196 if (status == OK) {
197 return map;
198 }
199 return Errorf("Load KeyCharacterMap failed {}.", status);
200}
201
202status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format) {
203 status_t status = OK;
Chris Ye3a1e4462020-08-12 10:13:15 -0700204#if DEBUG_PARSER_PERFORMANCE
205 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
206#endif
Philip Junker90bc9492021-12-10 18:39:42 +0100207 Parser parser(this, tokenizer, format);
Chris Ye3a1e4462020-08-12 10:13:15 -0700208 status = parser.parse();
209#if DEBUG_PARSER_PERFORMANCE
210 nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
211 ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
212 tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0);
213#endif
Philip Junker90bc9492021-12-10 18:39:42 +0100214 if (status != OK) {
215 ALOGE("Loading KeyCharacterMap failed with status %s", statusToString(status).c_str());
Chris Ye3a1e4462020-08-12 10:13:15 -0700216 }
Philip Junker90bc9492021-12-10 18:39:42 +0100217 return status;
218}
Chris Ye3a1e4462020-08-12 10:13:15 -0700219
Philip Junker90bc9492021-12-10 18:39:42 +0100220void KeyCharacterMap::clear() {
221 mKeysByScanCode.clear();
222 mKeysByUsageCode.clear();
223 for (size_t i = 0; i < mKeys.size(); i++) {
224 Key* key = mKeys.editValueAt(i);
225 delete key;
226 }
227 mKeys.clear();
228 mLayoutOverlayApplied = false;
229 mType = KeyboardType::UNKNOWN;
230}
231
232status_t KeyCharacterMap::reloadBaseFromFile() {
233 clear();
234 Tokenizer* tokenizer;
235 status_t status = Tokenizer::open(String8(mLoadFileName.c_str()), &tokenizer);
236 if (status) {
237 ALOGE("Error %s opening key character map file %s.", statusToString(status).c_str(),
238 mLoadFileName.c_str());
239 return status;
240 }
241 std::unique_ptr<Tokenizer> t(tokenizer);
242 return load(t.get(), KeyCharacterMap::Format::BASE);
Jeff Brown5912f952013-07-01 19:10:31 -0700243}
244
Chris Ye3a1e4462020-08-12 10:13:15 -0700245void KeyCharacterMap::combine(const KeyCharacterMap& overlay) {
Philip Junker90bc9492021-12-10 18:39:42 +0100246 if (mLayoutOverlayApplied) {
247 reloadBaseFromFile();
248 }
Chris Ye3a1e4462020-08-12 10:13:15 -0700249 for (size_t i = 0; i < overlay.mKeys.size(); i++) {
250 int32_t keyCode = overlay.mKeys.keyAt(i);
251 Key* key = overlay.mKeys.valueAt(i);
252 ssize_t oldIndex = mKeys.indexOfKey(keyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700253 if (oldIndex >= 0) {
Chris Ye3a1e4462020-08-12 10:13:15 -0700254 delete mKeys.valueAt(oldIndex);
255 mKeys.editValueAt(oldIndex) = new Key(*key);
Jeff Brown5912f952013-07-01 19:10:31 -0700256 } else {
Chris Ye3a1e4462020-08-12 10:13:15 -0700257 mKeys.add(keyCode, new Key(*key));
Jeff Brown5912f952013-07-01 19:10:31 -0700258 }
259 }
260
Chris Ye3a1e4462020-08-12 10:13:15 -0700261 for (size_t i = 0; i < overlay.mKeysByScanCode.size(); i++) {
262 mKeysByScanCode.replaceValueFor(overlay.mKeysByScanCode.keyAt(i),
263 overlay.mKeysByScanCode.valueAt(i));
Jeff Brown5912f952013-07-01 19:10:31 -0700264 }
265
Chris Ye3a1e4462020-08-12 10:13:15 -0700266 for (size_t i = 0; i < overlay.mKeysByUsageCode.size(); i++) {
267 mKeysByUsageCode.replaceValueFor(overlay.mKeysByUsageCode.keyAt(i),
268 overlay.mKeysByUsageCode.valueAt(i));
Jeff Brown5912f952013-07-01 19:10:31 -0700269 }
Philip Junker90bc9492021-12-10 18:39:42 +0100270 mLayoutOverlayApplied = true;
Jeff Brown5912f952013-07-01 19:10:31 -0700271}
272
Michael Wright102936e2020-11-04 03:44:27 +0000273KeyCharacterMap::KeyboardType KeyCharacterMap::getKeyboardType() const {
Jeff Brown5912f952013-07-01 19:10:31 -0700274 return mType;
275}
276
Chris Ye3a1e4462020-08-12 10:13:15 -0700277const std::string KeyCharacterMap::getLoadFileName() const {
278 return mLoadFileName;
279}
280
Jeff Brown5912f952013-07-01 19:10:31 -0700281char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const {
282 char16_t result = 0;
283 const Key* key;
284 if (getKey(keyCode, &key)) {
285 result = key->label;
286 }
287#if DEBUG_MAPPING
288 ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result);
289#endif
290 return result;
291}
292
293char16_t KeyCharacterMap::getNumber(int32_t keyCode) const {
294 char16_t result = 0;
295 const Key* key;
296 if (getKey(keyCode, &key)) {
297 result = key->number;
298 }
299#if DEBUG_MAPPING
300 ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result);
301#endif
302 return result;
303}
304
305char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
306 char16_t result = 0;
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700307 const Behavior* behavior = getKeyBehavior(keyCode, metaState);
308 if (behavior != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700309 result = behavior->character;
310 }
311#if DEBUG_MAPPING
312 ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result);
313#endif
314 return result;
315}
316
317bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState,
318 FallbackAction* outFallbackAction) const {
319 outFallbackAction->keyCode = 0;
320 outFallbackAction->metaState = 0;
321
322 bool result = false;
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700323 const Behavior* behavior = getKeyBehavior(keyCode, metaState);
324 if (behavior != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700325 if (behavior->fallbackKeyCode) {
326 outFallbackAction->keyCode = behavior->fallbackKeyCode;
327 outFallbackAction->metaState = metaState & ~behavior->metaState;
328 result = true;
329 }
330 }
331#if DEBUG_MAPPING
332 ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, "
333 "fallback keyCode=%d, fallback metaState=0x%08x.",
334 keyCode, metaState, result ? "true" : "false",
335 outFallbackAction->keyCode, outFallbackAction->metaState);
336#endif
337 return result;
338}
339
340char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars,
341 int32_t metaState) const {
342 char16_t result = 0;
343 const Key* key;
344 if (getKey(keyCode, &key)) {
345 // Try to find the most general behavior that maps to this character.
346 // For example, the base key behavior will usually be last in the list.
347 // However, if we find a perfect meta state match for one behavior then use that one.
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700348 for (const Behavior& behavior : key->behaviors) {
349 if (behavior.character) {
Jeff Brown5912f952013-07-01 19:10:31 -0700350 for (size_t i = 0; i < numChars; i++) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700351 if (behavior.character == chars[i]) {
352 result = behavior.character;
353 if ((behavior.metaState & metaState) == behavior.metaState) {
Jeff Brown5912f952013-07-01 19:10:31 -0700354 goto ExactMatch;
355 }
356 break;
357 }
358 }
359 }
360 }
361 ExactMatch: ;
362 }
363#if DEBUG_MAPPING
364 ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.",
365 keyCode, toString(chars, numChars).string(), metaState, result);
366#endif
367 return result;
368}
369
370bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
371 Vector<KeyEvent>& outEvents) const {
372 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
373
374 for (size_t i = 0; i < numChars; i++) {
375 int32_t keyCode, metaState;
376 char16_t ch = chars[i];
377 if (!findKey(ch, &keyCode, &metaState)) {
378#if DEBUG_MAPPING
379 ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.",
380 deviceId, toString(chars, numChars).string(), ch);
381#endif
382 return false;
383 }
384
385 int32_t currentMetaState = 0;
386 addMetaKeys(outEvents, deviceId, metaState, true, now, &currentMetaState);
387 addKey(outEvents, deviceId, keyCode, currentMetaState, true, now);
388 addKey(outEvents, deviceId, keyCode, currentMetaState, false, now);
389 addMetaKeys(outEvents, deviceId, metaState, false, now, &currentMetaState);
390 }
391#if DEBUG_MAPPING
392 ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.",
393 deviceId, toString(chars, numChars).string(), int32_t(outEvents.size()));
394 for (size_t i = 0; i < outEvents.size(); i++) {
395 ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.",
396 outEvents[i].getKeyCode(), outEvents[i].getMetaState(),
397 outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up");
398 }
399#endif
400 return true;
401}
402
403status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
404 if (usageCode) {
405 ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
406 if (index >= 0) {
Jeff Brown5912f952013-07-01 19:10:31 -0700407 *outKeyCode = mKeysByUsageCode.valueAt(index);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700408#if DEBUG_MAPPING
409 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
410 scanCode, usageCode, *outKeyCode);
411#endif
Jeff Brown5912f952013-07-01 19:10:31 -0700412 return OK;
413 }
414 }
415 if (scanCode) {
416 ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
417 if (index >= 0) {
Jeff Brown5912f952013-07-01 19:10:31 -0700418 *outKeyCode = mKeysByScanCode.valueAt(index);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700419#if DEBUG_MAPPING
420 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
421 scanCode, usageCode, *outKeyCode);
422#endif
Jeff Brown5912f952013-07-01 19:10:31 -0700423 return OK;
424 }
425 }
426
427#if DEBUG_MAPPING
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700428 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700429#endif
430 *outKeyCode = AKEYCODE_UNKNOWN;
431 return NAME_NOT_FOUND;
432}
433
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700434void KeyCharacterMap::tryRemapKey(int32_t keyCode, int32_t metaState,
435 int32_t *outKeyCode, int32_t *outMetaState) const {
436 *outKeyCode = keyCode;
437 *outMetaState = metaState;
438
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700439 const Behavior* behavior = getKeyBehavior(keyCode, metaState);
440 if (behavior != nullptr) {
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700441 if (behavior->replacementKeyCode) {
442 *outKeyCode = behavior->replacementKeyCode;
443 int32_t newMetaState = metaState & ~behavior->metaState;
444 // Reset dependent meta states.
445 if (behavior->metaState & AMETA_ALT_ON) {
446 newMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
447 }
448 if (behavior->metaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
449 newMetaState &= ~AMETA_ALT_ON;
450 }
451 if (behavior->metaState & AMETA_CTRL_ON) {
452 newMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
453 }
454 if (behavior->metaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
455 newMetaState &= ~AMETA_CTRL_ON;
456 }
457 if (behavior->metaState & AMETA_SHIFT_ON) {
458 newMetaState &= ~(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON);
459 }
460 if (behavior->metaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
461 newMetaState &= ~AMETA_SHIFT_ON;
462 }
463 // ... and put universal bits back if needed
464 *outMetaState = normalizeMetaState(newMetaState);
465 }
466 }
467
468#if DEBUG_MAPPING
469 ALOGD("tryRemapKey: keyCode=%d, metaState=0x%08x ~ "
470 "replacement keyCode=%d, replacement metaState=0x%08x.",
471 keyCode, metaState, *outKeyCode, *outMetaState);
472#endif
473}
474
Jeff Brown5912f952013-07-01 19:10:31 -0700475bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
476 ssize_t index = mKeys.indexOfKey(keyCode);
477 if (index >= 0) {
478 *outKey = mKeys.valueAt(index);
479 return true;
480 }
481 return false;
482}
483
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700484const KeyCharacterMap::Behavior* KeyCharacterMap::getKeyBehavior(int32_t keyCode,
485 int32_t metaState) const {
Jeff Brown5912f952013-07-01 19:10:31 -0700486 const Key* key;
487 if (getKey(keyCode, &key)) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700488 for (const Behavior& behavior : key->behaviors) {
489 if (matchesMetaState(metaState, behavior.metaState)) {
490 return &behavior;
Jeff Brown5912f952013-07-01 19:10:31 -0700491 }
Jeff Brown5912f952013-07-01 19:10:31 -0700492 }
493 }
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700494 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700495}
496
497bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
498 // Behavior must have at least the set of meta states specified.
499 // And if the key event has CTRL, ALT or META then the behavior must exactly
500 // match those, taking into account that a behavior can specify that it handles
501 // one, both or either of a left/right modifier pair.
502 if ((eventMetaState & behaviorMetaState) == behaviorMetaState) {
503 const int32_t EXACT_META_STATES =
504 AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON
505 | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON
506 | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON;
507 int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES;
508 if (behaviorMetaState & AMETA_CTRL_ON) {
509 unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
510 } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
511 unmatchedMetaState &= ~AMETA_CTRL_ON;
512 }
513 if (behaviorMetaState & AMETA_ALT_ON) {
514 unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
515 } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
516 unmatchedMetaState &= ~AMETA_ALT_ON;
517 }
518 if (behaviorMetaState & AMETA_META_ON) {
519 unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
520 } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
521 unmatchedMetaState &= ~AMETA_META_ON;
522 }
523 return !unmatchedMetaState;
524 }
525 return false;
526}
527
528bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
529 if (!ch) {
530 return false;
531 }
532
533 for (size_t i = 0; i < mKeys.size(); i++) {
534 const Key* key = mKeys.valueAt(i);
535
536 // Try to find the most general behavior that maps to this character.
537 // For example, the base key behavior will usually be last in the list.
Yi Kong5bed83b2018-07-17 12:53:47 -0700538 const Behavior* found = nullptr;
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700539 for (const Behavior& behavior : key->behaviors) {
540 if (behavior.character == ch) {
541 found = &behavior;
Jeff Brown5912f952013-07-01 19:10:31 -0700542 }
543 }
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700544 if (found != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700545 *outKeyCode = mKeys.keyAt(i);
546 *outMetaState = found->metaState;
547 return true;
548 }
549 }
550 return false;
551}
552
553void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents,
554 int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
555 outEvents.push();
556 KeyEvent& event = outEvents.editTop();
Garfield Tan4cc839f2020-01-24 11:26:14 -0800557 event.initialize(InputEvent::nextId(), deviceId, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
558 INVALID_HMAC, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 0, keyCode,
559 0, metaState, 0, time, time);
Jeff Brown5912f952013-07-01 19:10:31 -0700560}
561
562void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
563 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
564 int32_t* currentMetaState) {
565 // Add and remove meta keys symmetrically.
566 if (down) {
567 addLockedMetaKey(outEvents, deviceId, metaState, time,
568 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
569 addLockedMetaKey(outEvents, deviceId, metaState, time,
570 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
571 addLockedMetaKey(outEvents, deviceId, metaState, time,
572 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
573
574 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
575 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
576 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
577 AMETA_SHIFT_ON, currentMetaState);
578 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
579 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
580 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
581 AMETA_ALT_ON, currentMetaState);
582 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
583 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
584 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
585 AMETA_CTRL_ON, currentMetaState);
586 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
587 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
588 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
589 AMETA_META_ON, currentMetaState);
590
591 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
592 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
593 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
594 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
595 } else {
596 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
597 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
598 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
599 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
600
601 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
602 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
603 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
604 AMETA_META_ON, currentMetaState);
605 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
606 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
607 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
608 AMETA_CTRL_ON, currentMetaState);
609 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
610 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
611 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
612 AMETA_ALT_ON, currentMetaState);
613 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
614 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
615 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
616 AMETA_SHIFT_ON, currentMetaState);
617
618 addLockedMetaKey(outEvents, deviceId, metaState, time,
619 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
620 addLockedMetaKey(outEvents, deviceId, metaState, time,
621 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
622 addLockedMetaKey(outEvents, deviceId, metaState, time,
623 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
624 }
625}
626
627bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
628 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
629 int32_t keyCode, int32_t keyMetaState,
630 int32_t* currentMetaState) {
631 if ((metaState & keyMetaState) == keyMetaState) {
632 *currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
633 addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
634 return true;
635 }
636 return false;
637}
638
639void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
640 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
641 int32_t leftKeyCode, int32_t leftKeyMetaState,
642 int32_t rightKeyCode, int32_t rightKeyMetaState,
643 int32_t eitherKeyMetaState,
644 int32_t* currentMetaState) {
645 bool specific = false;
646 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
647 leftKeyCode, leftKeyMetaState, currentMetaState);
648 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
649 rightKeyCode, rightKeyMetaState, currentMetaState);
650
651 if (!specific) {
652 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
653 leftKeyCode, eitherKeyMetaState, currentMetaState);
654 }
655}
656
657void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
658 int32_t deviceId, int32_t metaState, nsecs_t time,
659 int32_t keyCode, int32_t keyMetaState,
660 int32_t* currentMetaState) {
661 if ((metaState & keyMetaState) == keyMetaState) {
662 *currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
663 addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
664 *currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
665 addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
666 }
667}
668
Brett Chabotfaa986c2020-11-04 17:39:36 -0800669#ifdef __linux__
Chris Ye3a1e4462020-08-12 10:13:15 -0700670std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
671 if (parcel == nullptr) {
672 ALOGE("%s: Null parcel", __func__);
673 return nullptr;
674 }
Philip Junker90bc9492021-12-10 18:39:42 +0100675 std::string loadFileName = parcel->readCString();
676 std::shared_ptr<KeyCharacterMap> map =
677 std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(loadFileName));
Michael Wright102936e2020-11-04 03:44:27 +0000678 map->mType = static_cast<KeyCharacterMap::KeyboardType>(parcel->readInt32());
Philip Junker90bc9492021-12-10 18:39:42 +0100679 map->mLayoutOverlayApplied = parcel->readBool();
Jeff Brown5912f952013-07-01 19:10:31 -0700680 size_t numKeys = parcel->readInt32();
681 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700682 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700683 }
Michael Wright4c971c02015-10-21 14:38:03 +0100684 if (numKeys > MAX_KEYS) {
Ian Pedowitzd57d9b92016-02-19 08:34:43 +0000685 ALOGE("Too many keys in KeyCharacterMap (%zu > %d)", numKeys, MAX_KEYS);
Yi Kong5bed83b2018-07-17 12:53:47 -0700686 return nullptr;
Michael Wright4c971c02015-10-21 14:38:03 +0100687 }
Jeff Brown5912f952013-07-01 19:10:31 -0700688
689 for (size_t i = 0; i < numKeys; i++) {
690 int32_t keyCode = parcel->readInt32();
691 char16_t label = parcel->readInt32();
692 char16_t number = parcel->readInt32();
693 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700694 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700695 }
696
697 Key* key = new Key();
698 key->label = label;
699 key->number = number;
700 map->mKeys.add(keyCode, key);
701
Jeff Brown5912f952013-07-01 19:10:31 -0700702 while (parcel->readInt32()) {
703 int32_t metaState = parcel->readInt32();
704 char16_t character = parcel->readInt32();
705 int32_t fallbackKeyCode = parcel->readInt32();
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700706 int32_t replacementKeyCode = parcel->readInt32();
Jeff Brown5912f952013-07-01 19:10:31 -0700707 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700708 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700709 }
710
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700711 key->behaviors.push_back({
712 .metaState = metaState,
713 .character = character,
714 .fallbackKeyCode = fallbackKeyCode,
715 .replacementKeyCode = replacementKeyCode,
716 });
Jeff Brown5912f952013-07-01 19:10:31 -0700717 }
718
719 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700720 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700721 }
722 }
Philip Junker90bc9492021-12-10 18:39:42 +0100723 size_t numKeysByScanCode = parcel->readInt32();
724 if (parcel->errorCheck()) {
725 return nullptr;
726 }
727 for (size_t i = 0; i < numKeysByScanCode; i++) {
728 int32_t key = parcel->readInt32();
729 int32_t value = parcel->readInt32();
730 map->mKeysByScanCode.add(key, value);
731 if (parcel->errorCheck()) {
732 return nullptr;
733 }
734 }
735 size_t numKeysByUsageCode = parcel->readInt32();
736 if (parcel->errorCheck()) {
737 return nullptr;
738 }
739 for (size_t i = 0; i < numKeysByUsageCode; i++) {
740 int32_t key = parcel->readInt32();
741 int32_t value = parcel->readInt32();
742 map->mKeysByUsageCode.add(key, value);
743 if (parcel->errorCheck()) {
744 return nullptr;
745 }
746 }
Jeff Brown5912f952013-07-01 19:10:31 -0700747 return map;
748}
749
750void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
Chris Ye3a1e4462020-08-12 10:13:15 -0700751 if (parcel == nullptr) {
752 ALOGE("%s: Null parcel", __func__);
753 return;
754 }
Philip Junker90bc9492021-12-10 18:39:42 +0100755 parcel->writeCString(mLoadFileName.c_str());
Michael Wright102936e2020-11-04 03:44:27 +0000756 parcel->writeInt32(static_cast<int32_t>(mType));
Philip Junker90bc9492021-12-10 18:39:42 +0100757 parcel->writeBool(mLayoutOverlayApplied);
Jeff Brown5912f952013-07-01 19:10:31 -0700758
759 size_t numKeys = mKeys.size();
760 parcel->writeInt32(numKeys);
761 for (size_t i = 0; i < numKeys; i++) {
762 int32_t keyCode = mKeys.keyAt(i);
763 const Key* key = mKeys.valueAt(i);
764 parcel->writeInt32(keyCode);
765 parcel->writeInt32(key->label);
766 parcel->writeInt32(key->number);
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700767 for (const Behavior& behavior : key->behaviors) {
Jeff Brown5912f952013-07-01 19:10:31 -0700768 parcel->writeInt32(1);
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700769 parcel->writeInt32(behavior.metaState);
770 parcel->writeInt32(behavior.character);
771 parcel->writeInt32(behavior.fallbackKeyCode);
772 parcel->writeInt32(behavior.replacementKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700773 }
774 parcel->writeInt32(0);
775 }
Philip Junker90bc9492021-12-10 18:39:42 +0100776 size_t numKeysByScanCode = mKeysByScanCode.size();
777 parcel->writeInt32(numKeysByScanCode);
778 for (size_t i = 0; i < numKeysByScanCode; i++) {
779 parcel->writeInt32(mKeysByScanCode.keyAt(i));
780 parcel->writeInt32(mKeysByScanCode.valueAt(i));
781 }
782 size_t numKeysByUsageCode = mKeysByUsageCode.size();
783 parcel->writeInt32(numKeysByUsageCode);
784 for (size_t i = 0; i < numKeysByUsageCode; i++) {
785 parcel->writeInt32(mKeysByUsageCode.keyAt(i));
786 parcel->writeInt32(mKeysByUsageCode.valueAt(i));
787 }
Jeff Brown5912f952013-07-01 19:10:31 -0700788}
Brett Chabotfaa986c2020-11-04 17:39:36 -0800789#endif // __linux__
Jeff Brown5912f952013-07-01 19:10:31 -0700790
791// --- KeyCharacterMap::Key ---
792
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700793KeyCharacterMap::Key::Key() : label(0), number(0) {}
Jeff Brown5912f952013-07-01 19:10:31 -0700794
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700795KeyCharacterMap::Key::Key(const Key& other)
796 : label(other.label), number(other.number), behaviors(other.behaviors) {}
Jeff Brown5912f952013-07-01 19:10:31 -0700797
798// --- KeyCharacterMap::Parser ---
799
800KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
801 mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
802}
803
804KeyCharacterMap::Parser::~Parser() {
805}
806
807status_t KeyCharacterMap::Parser::parse() {
808 while (!mTokenizer->isEof()) {
809#if DEBUG_PARSER
810 ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
811 mTokenizer->peekRemainderOfLine().string());
812#endif
813
814 mTokenizer->skipDelimiters(WHITESPACE);
815
816 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
817 switch (mState) {
818 case STATE_TOP: {
819 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
820 if (keywordToken == "type") {
821 mTokenizer->skipDelimiters(WHITESPACE);
822 status_t status = parseType();
823 if (status) return status;
824 } else if (keywordToken == "map") {
825 mTokenizer->skipDelimiters(WHITESPACE);
826 status_t status = parseMap();
827 if (status) return status;
828 } else if (keywordToken == "key") {
829 mTokenizer->skipDelimiters(WHITESPACE);
830 status_t status = parseKey();
831 if (status) return status;
832 } else {
833 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
834 keywordToken.string());
835 return BAD_VALUE;
836 }
837 break;
838 }
839
840 case STATE_KEY: {
841 status_t status = parseKeyProperty();
842 if (status) return status;
843 break;
844 }
845 }
846
847 mTokenizer->skipDelimiters(WHITESPACE);
848 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
849 ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
850 mTokenizer->getLocation().string(),
851 mTokenizer->peekRemainderOfLine().string());
852 return BAD_VALUE;
853 }
854 }
855
856 mTokenizer->nextLine();
857 }
858
859 if (mState != STATE_TOP) {
860 ALOGE("%s: Unterminated key description at end of file.",
861 mTokenizer->getLocation().string());
862 return BAD_VALUE;
863 }
864
Michael Wright102936e2020-11-04 03:44:27 +0000865 if (mMap->mType == KeyboardType::UNKNOWN) {
Jeff Brown5912f952013-07-01 19:10:31 -0700866 ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
867 mTokenizer->getLocation().string());
868 return BAD_VALUE;
869 }
870
Michael Wright102936e2020-11-04 03:44:27 +0000871 if (mFormat == Format::BASE) {
872 if (mMap->mType == KeyboardType::OVERLAY) {
Jeff Brown5912f952013-07-01 19:10:31 -0700873 ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
874 mTokenizer->getLocation().string());
875 return BAD_VALUE;
876 }
Michael Wright102936e2020-11-04 03:44:27 +0000877 } else if (mFormat == Format::OVERLAY) {
878 if (mMap->mType != KeyboardType::OVERLAY) {
Jeff Brown5912f952013-07-01 19:10:31 -0700879 ALOGE("%s: Overlay keyboard layout missing required keyboard "
880 "'type OVERLAY' declaration.",
881 mTokenizer->getLocation().string());
882 return BAD_VALUE;
883 }
884 }
885
886 return NO_ERROR;
887}
888
889status_t KeyCharacterMap::Parser::parseType() {
Michael Wright102936e2020-11-04 03:44:27 +0000890 if (mMap->mType != KeyboardType::UNKNOWN) {
Jeff Brown5912f952013-07-01 19:10:31 -0700891 ALOGE("%s: Duplicate keyboard 'type' declaration.",
892 mTokenizer->getLocation().string());
893 return BAD_VALUE;
894 }
895
896 KeyboardType type;
897 String8 typeToken = mTokenizer->nextToken(WHITESPACE);
898 if (typeToken == "NUMERIC") {
Michael Wright102936e2020-11-04 03:44:27 +0000899 type = KeyboardType::NUMERIC;
Jeff Brown5912f952013-07-01 19:10:31 -0700900 } else if (typeToken == "PREDICTIVE") {
Michael Wright102936e2020-11-04 03:44:27 +0000901 type = KeyboardType::PREDICTIVE;
Jeff Brown5912f952013-07-01 19:10:31 -0700902 } else if (typeToken == "ALPHA") {
Michael Wright102936e2020-11-04 03:44:27 +0000903 type = KeyboardType::ALPHA;
Jeff Brown5912f952013-07-01 19:10:31 -0700904 } else if (typeToken == "FULL") {
Michael Wright102936e2020-11-04 03:44:27 +0000905 type = KeyboardType::FULL;
Jeff Brown5912f952013-07-01 19:10:31 -0700906 } else if (typeToken == "SPECIAL_FUNCTION") {
Siarhei Vishniakou61da25a2018-02-15 21:04:49 -0600907 ALOGW("The SPECIAL_FUNCTION type is now declared in the device's IDC file, please set "
908 "the property 'keyboard.specialFunction' to '1' there instead.");
909 // TODO: return BAD_VALUE here in Q
Michael Wright102936e2020-11-04 03:44:27 +0000910 type = KeyboardType::SPECIAL_FUNCTION;
Jeff Brown5912f952013-07-01 19:10:31 -0700911 } else if (typeToken == "OVERLAY") {
Michael Wright102936e2020-11-04 03:44:27 +0000912 type = KeyboardType::OVERLAY;
Jeff Brown5912f952013-07-01 19:10:31 -0700913 } else {
914 ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(),
915 typeToken.string());
916 return BAD_VALUE;
917 }
918
919#if DEBUG_PARSER
920 ALOGD("Parsed type: type=%d.", type);
921#endif
922 mMap->mType = type;
923 return NO_ERROR;
924}
925
926status_t KeyCharacterMap::Parser::parseMap() {
927 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
928 if (keywordToken == "key") {
929 mTokenizer->skipDelimiters(WHITESPACE);
930 return parseMapKey();
931 }
932 ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(),
933 keywordToken.string());
934 return BAD_VALUE;
935}
936
937status_t KeyCharacterMap::Parser::parseMapKey() {
938 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
939 bool mapUsage = false;
940 if (codeToken == "usage") {
941 mapUsage = true;
942 mTokenizer->skipDelimiters(WHITESPACE);
943 codeToken = mTokenizer->nextToken(WHITESPACE);
944 }
945
946 char* end;
947 int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
948 if (*end) {
949 ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
950 mapUsage ? "usage" : "scan code", codeToken.string());
951 return BAD_VALUE;
952 }
953 KeyedVector<int32_t, int32_t>& map =
954 mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
955 if (map.indexOfKey(code) >= 0) {
956 ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
957 mapUsage ? "usage" : "scan code", codeToken.string());
958 return BAD_VALUE;
959 }
960
961 mTokenizer->skipDelimiters(WHITESPACE);
962 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700963 int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700964 if (!keyCode) {
965 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
966 keyCodeToken.string());
967 return BAD_VALUE;
968 }
969
970#if DEBUG_PARSER
971 ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
972 mapUsage ? "usage" : "scan code", code, keyCode);
973#endif
974 map.add(code, keyCode);
975 return NO_ERROR;
976}
977
978status_t KeyCharacterMap::Parser::parseKey() {
979 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -0700980 int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700981 if (!keyCode) {
982 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
983 keyCodeToken.string());
984 return BAD_VALUE;
985 }
986 if (mMap->mKeys.indexOfKey(keyCode) >= 0) {
987 ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(),
988 keyCodeToken.string());
989 return BAD_VALUE;
990 }
991
992 mTokenizer->skipDelimiters(WHITESPACE);
993 String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
994 if (openBraceToken != "{") {
995 ALOGE("%s: Expected '{' after key code label, got '%s'.",
996 mTokenizer->getLocation().string(), openBraceToken.string());
997 return BAD_VALUE;
998 }
999
1000#if DEBUG_PARSER
1001 ALOGD("Parsed beginning of key: keyCode=%d.", keyCode);
1002#endif
1003 mKeyCode = keyCode;
1004 mMap->mKeys.add(keyCode, new Key());
1005 mState = STATE_KEY;
1006 return NO_ERROR;
1007}
1008
1009status_t KeyCharacterMap::Parser::parseKeyProperty() {
1010 Key* key = mMap->mKeys.valueFor(mKeyCode);
1011 String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
1012 if (token == "}") {
1013 mState = STATE_TOP;
1014 return finishKey(key);
1015 }
1016
1017 Vector<Property> properties;
1018
1019 // Parse all comma-delimited property names up to the first colon.
1020 for (;;) {
1021 if (token == "label") {
1022 properties.add(Property(PROPERTY_LABEL));
1023 } else if (token == "number") {
1024 properties.add(Property(PROPERTY_NUMBER));
1025 } else {
1026 int32_t metaState;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001027 status_t status = parseModifier(token.string(), &metaState);
Jeff Brown5912f952013-07-01 19:10:31 -07001028 if (status) {
1029 ALOGE("%s: Expected a property name or modifier, got '%s'.",
1030 mTokenizer->getLocation().string(), token.string());
1031 return status;
1032 }
1033 properties.add(Property(PROPERTY_META, metaState));
1034 }
1035
1036 mTokenizer->skipDelimiters(WHITESPACE);
1037 if (!mTokenizer->isEol()) {
1038 char ch = mTokenizer->nextChar();
1039 if (ch == ':') {
1040 break;
1041 } else if (ch == ',') {
1042 mTokenizer->skipDelimiters(WHITESPACE);
1043 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
1044 continue;
1045 }
1046 }
1047
1048 ALOGE("%s: Expected ',' or ':' after property name.",
1049 mTokenizer->getLocation().string());
1050 return BAD_VALUE;
1051 }
1052
1053 // Parse behavior after the colon.
1054 mTokenizer->skipDelimiters(WHITESPACE);
1055
1056 Behavior behavior;
1057 bool haveCharacter = false;
1058 bool haveFallback = false;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001059 bool haveReplacement = false;
Jeff Brown5912f952013-07-01 19:10:31 -07001060
1061 do {
1062 char ch = mTokenizer->peekChar();
1063 if (ch == '\'') {
1064 char16_t character;
1065 status_t status = parseCharacterLiteral(&character);
1066 if (status || !character) {
1067 ALOGE("%s: Invalid character literal for key.",
1068 mTokenizer->getLocation().string());
1069 return BAD_VALUE;
1070 }
1071 if (haveCharacter) {
1072 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
1073 mTokenizer->getLocation().string());
1074 return BAD_VALUE;
1075 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001076 if (haveReplacement) {
1077 ALOGE("%s: Cannot combine character literal with replace action.",
1078 mTokenizer->getLocation().string());
1079 return BAD_VALUE;
1080 }
Jeff Brown5912f952013-07-01 19:10:31 -07001081 behavior.character = character;
1082 haveCharacter = true;
1083 } else {
1084 token = mTokenizer->nextToken(WHITESPACE);
1085 if (token == "none") {
1086 if (haveCharacter) {
1087 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
1088 mTokenizer->getLocation().string());
1089 return BAD_VALUE;
1090 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001091 if (haveReplacement) {
1092 ALOGE("%s: Cannot combine 'none' with replace action.",
1093 mTokenizer->getLocation().string());
1094 return BAD_VALUE;
1095 }
Jeff Brown5912f952013-07-01 19:10:31 -07001096 haveCharacter = true;
1097 } else if (token == "fallback") {
1098 mTokenizer->skipDelimiters(WHITESPACE);
1099 token = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -07001100 int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.string());
Jeff Brown5912f952013-07-01 19:10:31 -07001101 if (!keyCode) {
1102 ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
1103 mTokenizer->getLocation().string(),
1104 token.string());
1105 return BAD_VALUE;
1106 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001107 if (haveFallback || haveReplacement) {
1108 ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
Jeff Brown5912f952013-07-01 19:10:31 -07001109 mTokenizer->getLocation().string());
1110 return BAD_VALUE;
1111 }
1112 behavior.fallbackKeyCode = keyCode;
1113 haveFallback = true;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001114 } else if (token == "replace") {
1115 mTokenizer->skipDelimiters(WHITESPACE);
1116 token = mTokenizer->nextToken(WHITESPACE);
Chris Ye4958d062020-08-20 13:21:10 -07001117 int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.string());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001118 if (!keyCode) {
1119 ALOGE("%s: Invalid key code label for replace, got '%s'.",
1120 mTokenizer->getLocation().string(),
1121 token.string());
1122 return BAD_VALUE;
1123 }
1124 if (haveCharacter) {
1125 ALOGE("%s: Cannot combine character literal with replace action.",
1126 mTokenizer->getLocation().string());
1127 return BAD_VALUE;
1128 }
1129 if (haveFallback || haveReplacement) {
1130 ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
1131 mTokenizer->getLocation().string());
1132 return BAD_VALUE;
1133 }
1134 behavior.replacementKeyCode = keyCode;
1135 haveReplacement = true;
1136
Jeff Brown5912f952013-07-01 19:10:31 -07001137 } else {
1138 ALOGE("%s: Expected a key behavior after ':'.",
1139 mTokenizer->getLocation().string());
1140 return BAD_VALUE;
1141 }
1142 }
1143
1144 mTokenizer->skipDelimiters(WHITESPACE);
1145 } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#');
1146
1147 // Add the behavior.
1148 for (size_t i = 0; i < properties.size(); i++) {
1149 const Property& property = properties.itemAt(i);
1150 switch (property.property) {
1151 case PROPERTY_LABEL:
1152 if (key->label) {
1153 ALOGE("%s: Duplicate label for key.",
1154 mTokenizer->getLocation().string());
1155 return BAD_VALUE;
1156 }
1157 key->label = behavior.character;
1158#if DEBUG_PARSER
1159 ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label);
1160#endif
1161 break;
1162 case PROPERTY_NUMBER:
1163 if (key->number) {
1164 ALOGE("%s: Duplicate number for key.",
1165 mTokenizer->getLocation().string());
1166 return BAD_VALUE;
1167 }
1168 key->number = behavior.character;
1169#if DEBUG_PARSER
1170 ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number);
1171#endif
1172 break;
1173 case PROPERTY_META: {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001174 for (const Behavior& b : key->behaviors) {
1175 if (b.metaState == property.metaState) {
Jeff Brown5912f952013-07-01 19:10:31 -07001176 ALOGE("%s: Duplicate key behavior for modifier.",
1177 mTokenizer->getLocation().string());
1178 return BAD_VALUE;
1179 }
1180 }
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001181 Behavior newBehavior = behavior;
1182 newBehavior.metaState = property.metaState;
1183 key->behaviors.push_front(newBehavior);
1184 ALOGD_IF(DEBUG_PARSER,
1185 "Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
1186 mKeyCode, key->behaviors.front().metaState, key->behaviors.front().character,
1187 key->behaviors.front().fallbackKeyCode,
1188 key->behaviors.front().replacementKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -07001189 break;
1190 }
1191 }
1192 }
1193 return NO_ERROR;
1194}
1195
1196status_t KeyCharacterMap::Parser::finishKey(Key* key) {
1197 // Fill in default number property.
1198 if (!key->number) {
1199 char16_t digit = 0;
1200 char16_t symbol = 0;
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001201 for (const Behavior& b : key->behaviors) {
1202 char16_t ch = b.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001203 if (ch) {
1204 if (ch >= '0' && ch <= '9') {
1205 digit = ch;
1206 } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
1207 || ch == '-' || ch == '+' || ch == ',' || ch == '.'
1208 || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
1209 symbol = ch;
1210 }
1211 }
1212 }
1213 key->number = digit ? digit : symbol;
1214 }
1215 return NO_ERROR;
1216}
1217
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001218status_t KeyCharacterMap::Parser::parseModifier(const std::string& token, int32_t* outMetaState) {
Jeff Brown5912f952013-07-01 19:10:31 -07001219 if (token == "base") {
1220 *outMetaState = 0;
1221 return NO_ERROR;
1222 }
1223
1224 int32_t combinedMeta = 0;
1225
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001226 const char* str = token.c_str();
Jeff Brown5912f952013-07-01 19:10:31 -07001227 const char* start = str;
1228 for (const char* cur = str; ; cur++) {
1229 char ch = *cur;
1230 if (ch == '+' || ch == '\0') {
1231 size_t len = cur - start;
1232 int32_t metaState = 0;
1233 for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
1234 if (strlen(modifiers[i].label) == len
1235 && strncmp(modifiers[i].label, start, len) == 0) {
1236 metaState = modifiers[i].metaState;
1237 break;
1238 }
1239 }
1240 if (!metaState) {
1241 return BAD_VALUE;
1242 }
1243 if (combinedMeta & metaState) {
1244 ALOGE("%s: Duplicate modifier combination '%s'.",
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001245 mTokenizer->getLocation().string(), token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001246 return BAD_VALUE;
1247 }
1248
1249 combinedMeta |= metaState;
1250 start = cur + 1;
1251
1252 if (ch == '\0') {
1253 break;
1254 }
1255 }
1256 }
1257 *outMetaState = combinedMeta;
1258 return NO_ERROR;
1259}
1260
1261status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
1262 char ch = mTokenizer->nextChar();
1263 if (ch != '\'') {
1264 goto Error;
1265 }
1266
1267 ch = mTokenizer->nextChar();
1268 if (ch == '\\') {
1269 // Escape sequence.
1270 ch = mTokenizer->nextChar();
1271 if (ch == 'n') {
1272 *outCharacter = '\n';
1273 } else if (ch == 't') {
1274 *outCharacter = '\t';
1275 } else if (ch == '\\') {
1276 *outCharacter = '\\';
1277 } else if (ch == '\'') {
1278 *outCharacter = '\'';
1279 } else if (ch == '"') {
1280 *outCharacter = '"';
1281 } else if (ch == 'u') {
1282 *outCharacter = 0;
1283 for (int i = 0; i < 4; i++) {
1284 ch = mTokenizer->nextChar();
1285 int digit;
1286 if (ch >= '0' && ch <= '9') {
1287 digit = ch - '0';
1288 } else if (ch >= 'A' && ch <= 'F') {
1289 digit = ch - 'A' + 10;
1290 } else if (ch >= 'a' && ch <= 'f') {
1291 digit = ch - 'a' + 10;
1292 } else {
1293 goto Error;
1294 }
1295 *outCharacter = (*outCharacter << 4) | digit;
1296 }
1297 } else {
1298 goto Error;
1299 }
1300 } else if (ch >= 32 && ch <= 126 && ch != '\'') {
1301 // ASCII literal character.
1302 *outCharacter = ch;
1303 } else {
1304 goto Error;
1305 }
1306
1307 ch = mTokenizer->nextChar();
1308 if (ch != '\'') {
1309 goto Error;
1310 }
1311
1312 // Ensure that we consumed the entire token.
1313 if (mTokenizer->nextToken(WHITESPACE).isEmpty()) {
1314 return NO_ERROR;
1315 }
1316
1317Error:
1318 ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string());
1319 return BAD_VALUE;
1320}
1321
1322} // namespace android