blob: 12c9e533c35e2b9fab911b0a2ae677e750934636 [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
Jeff Brown5912f952013-07-01 19:10:31 -070046namespace android {
47
48static const char* WHITESPACE = " \t\r";
49static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:";
50
51struct Modifier {
52 const char* label;
53 int32_t metaState;
54};
55static const Modifier modifiers[] = {
56 { "shift", AMETA_SHIFT_ON },
57 { "lshift", AMETA_SHIFT_LEFT_ON },
58 { "rshift", AMETA_SHIFT_RIGHT_ON },
59 { "alt", AMETA_ALT_ON },
60 { "lalt", AMETA_ALT_LEFT_ON },
61 { "ralt", AMETA_ALT_RIGHT_ON },
62 { "ctrl", AMETA_CTRL_ON },
63 { "lctrl", AMETA_CTRL_LEFT_ON },
64 { "rctrl", AMETA_CTRL_RIGHT_ON },
65 { "meta", AMETA_META_ON },
66 { "lmeta", AMETA_META_LEFT_ON },
67 { "rmeta", AMETA_META_RIGHT_ON },
68 { "sym", AMETA_SYM_ON },
69 { "fn", AMETA_FUNCTION_ON },
70 { "capslock", AMETA_CAPS_LOCK_ON },
71 { "numlock", AMETA_NUM_LOCK_ON },
72 { "scrolllock", AMETA_SCROLL_LOCK_ON },
73};
74
75#if DEBUG_MAPPING
76static String8 toString(const char16_t* chars, size_t numChars) {
77 String8 result;
78 for (size_t i = 0; i < numChars; i++) {
79 result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]);
80 }
81 return result;
82}
83#endif
84
85
86// --- KeyCharacterMap ---
87
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -070088KeyCharacterMap::KeyCharacterMap(const std::string& filename) : mLoadFileName(filename) {}
Philip Junker90bc9492021-12-10 18:39:42 +010089
Chris Ye3a1e4462020-08-12 10:13:15 -070090base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename,
91 Format format) {
Jeff Brown5912f952013-07-01 19:10:31 -070092 Tokenizer* tokenizer;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +010093 status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
Jeff Brown5912f952013-07-01 19:10:31 -070094 if (status) {
Chris Ye3a1e4462020-08-12 10:13:15 -070095 return Errorf("Error {} opening key character map file {}.", status, filename.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -070096 }
Philip Junker90bc9492021-12-10 18:39:42 +010097 std::shared_ptr<KeyCharacterMap> map =
98 std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
99 if (!map.get()) {
100 ALOGE("Error allocating key character map.");
101 return Errorf("Error allocating key character map.");
Chris Ye3a1e4462020-08-12 10:13:15 -0700102 }
Philip Junker90bc9492021-12-10 18:39:42 +0100103 std::unique_ptr<Tokenizer> t(tokenizer);
104 status = map->load(t.get(), format);
105 if (status == OK) {
106 return map;
107 }
108 return Errorf("Load KeyCharacterMap failed {}.", status);
Jeff Brown5912f952013-07-01 19:10:31 -0700109}
110
Chris Ye3a1e4462020-08-12 10:13:15 -0700111base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::loadContents(
112 const std::string& filename, const char* contents, Format format) {
Jeff Brown5912f952013-07-01 19:10:31 -0700113 Tokenizer* tokenizer;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100114 status_t status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
Jeff Brown5912f952013-07-01 19:10:31 -0700115 if (status) {
116 ALOGE("Error %d opening key character map.", status);
Chris Ye3a1e4462020-08-12 10:13:15 -0700117 return Errorf("Error {} opening key character map.", status);
Jeff Brown5912f952013-07-01 19:10:31 -0700118 }
Philip Junker90bc9492021-12-10 18:39:42 +0100119 std::shared_ptr<KeyCharacterMap> map =
120 std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
Jeff Brown5912f952013-07-01 19:10:31 -0700121 if (!map.get()) {
122 ALOGE("Error allocating key character map.");
Chris Ye3a1e4462020-08-12 10:13:15 -0700123 return Errorf("Error allocating key character map.");
Jeff Brown5912f952013-07-01 19:10:31 -0700124 }
Philip Junker90bc9492021-12-10 18:39:42 +0100125 std::unique_ptr<Tokenizer> t(tokenizer);
126 status = map->load(t.get(), format);
127 if (status == OK) {
128 return map;
129 }
130 return Errorf("Load KeyCharacterMap failed {}.", status);
131}
132
133status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format) {
134 status_t status = OK;
Chris Ye3a1e4462020-08-12 10:13:15 -0700135#if DEBUG_PARSER_PERFORMANCE
136 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
137#endif
Philip Junker90bc9492021-12-10 18:39:42 +0100138 Parser parser(this, tokenizer, format);
Chris Ye3a1e4462020-08-12 10:13:15 -0700139 status = parser.parse();
140#if DEBUG_PARSER_PERFORMANCE
141 nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
142 ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
143 tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0);
144#endif
Philip Junker90bc9492021-12-10 18:39:42 +0100145 if (status != OK) {
146 ALOGE("Loading KeyCharacterMap failed with status %s", statusToString(status).c_str());
Chris Ye3a1e4462020-08-12 10:13:15 -0700147 }
Philip Junker90bc9492021-12-10 18:39:42 +0100148 return status;
149}
Chris Ye3a1e4462020-08-12 10:13:15 -0700150
Philip Junker90bc9492021-12-10 18:39:42 +0100151void KeyCharacterMap::clear() {
152 mKeysByScanCode.clear();
153 mKeysByUsageCode.clear();
Philip Junker90bc9492021-12-10 18:39:42 +0100154 mKeys.clear();
155 mLayoutOverlayApplied = false;
156 mType = KeyboardType::UNKNOWN;
157}
158
159status_t KeyCharacterMap::reloadBaseFromFile() {
160 clear();
161 Tokenizer* tokenizer;
162 status_t status = Tokenizer::open(String8(mLoadFileName.c_str()), &tokenizer);
163 if (status) {
164 ALOGE("Error %s opening key character map file %s.", statusToString(status).c_str(),
165 mLoadFileName.c_str());
166 return status;
167 }
168 std::unique_ptr<Tokenizer> t(tokenizer);
169 return load(t.get(), KeyCharacterMap::Format::BASE);
Jeff Brown5912f952013-07-01 19:10:31 -0700170}
171
Chris Ye3a1e4462020-08-12 10:13:15 -0700172void KeyCharacterMap::combine(const KeyCharacterMap& overlay) {
Philip Junker90bc9492021-12-10 18:39:42 +0100173 if (mLayoutOverlayApplied) {
174 reloadBaseFromFile();
175 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700176 for (const auto& [keyCode, key] : overlay.mKeys) {
177 mKeys.insert_or_assign(keyCode, key);
Jeff Brown5912f952013-07-01 19:10:31 -0700178 }
179
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700180 for (const auto& [fromScanCode, toAndroidKeyCode] : overlay.mKeysByScanCode) {
181 mKeysByScanCode.insert_or_assign(fromScanCode, toAndroidKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700182 }
183
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700184 for (const auto& [fromHidUsageCode, toAndroidKeyCode] : overlay.mKeysByUsageCode) {
185 mKeysByUsageCode.insert_or_assign(fromHidUsageCode, toAndroidKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700186 }
Philip Junker90bc9492021-12-10 18:39:42 +0100187 mLayoutOverlayApplied = true;
Jeff Brown5912f952013-07-01 19:10:31 -0700188}
189
Vaibhav Devmurari23e8ae92022-12-29 12:07:56 +0000190void KeyCharacterMap::clearLayoutOverlay() {
191 if (mLayoutOverlayApplied) {
192 reloadBaseFromFile();
193 mLayoutOverlayApplied = false;
194 }
195}
196
Michael Wright102936e2020-11-04 03:44:27 +0000197KeyCharacterMap::KeyboardType KeyCharacterMap::getKeyboardType() const {
Jeff Brown5912f952013-07-01 19:10:31 -0700198 return mType;
199}
200
Chris Ye3a1e4462020-08-12 10:13:15 -0700201const std::string KeyCharacterMap::getLoadFileName() const {
202 return mLoadFileName;
203}
204
Jeff Brown5912f952013-07-01 19:10:31 -0700205char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const {
206 char16_t result = 0;
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700207 const Key* key = getKey(keyCode);
208 if (key != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700209 result = key->label;
210 }
211#if DEBUG_MAPPING
212 ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result);
213#endif
214 return result;
215}
216
217char16_t KeyCharacterMap::getNumber(int32_t keyCode) const {
218 char16_t result = 0;
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700219 const Key* key = getKey(keyCode);
220 if (key != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700221 result = key->number;
222 }
223#if DEBUG_MAPPING
224 ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result);
225#endif
226 return result;
227}
228
229char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
230 char16_t result = 0;
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700231 const Behavior* behavior = getKeyBehavior(keyCode, metaState);
232 if (behavior != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700233 result = behavior->character;
234 }
235#if DEBUG_MAPPING
236 ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result);
237#endif
238 return result;
239}
240
241bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState,
242 FallbackAction* outFallbackAction) const {
243 outFallbackAction->keyCode = 0;
244 outFallbackAction->metaState = 0;
245
246 bool result = false;
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700247 const Behavior* behavior = getKeyBehavior(keyCode, metaState);
248 if (behavior != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700249 if (behavior->fallbackKeyCode) {
250 outFallbackAction->keyCode = behavior->fallbackKeyCode;
251 outFallbackAction->metaState = metaState & ~behavior->metaState;
252 result = true;
253 }
254 }
255#if DEBUG_MAPPING
256 ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, "
257 "fallback keyCode=%d, fallback metaState=0x%08x.",
258 keyCode, metaState, result ? "true" : "false",
259 outFallbackAction->keyCode, outFallbackAction->metaState);
260#endif
261 return result;
262}
263
264char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars,
265 int32_t metaState) const {
266 char16_t result = 0;
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700267 const Key* key = getKey(keyCode);
268 if (key != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700269 // Try to find the most general behavior that maps to this character.
270 // For example, the base key behavior will usually be last in the list.
271 // However, if we find a perfect meta state match for one behavior then use that one.
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700272 for (const Behavior& behavior : key->behaviors) {
273 if (behavior.character) {
Jeff Brown5912f952013-07-01 19:10:31 -0700274 for (size_t i = 0; i < numChars; i++) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700275 if (behavior.character == chars[i]) {
276 result = behavior.character;
277 if ((behavior.metaState & metaState) == behavior.metaState) {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700278 // Found exact match!
279 return result;
Jeff Brown5912f952013-07-01 19:10:31 -0700280 }
281 break;
282 }
283 }
284 }
285 }
Jeff Brown5912f952013-07-01 19:10:31 -0700286 }
Jeff Brown5912f952013-07-01 19:10:31 -0700287 return result;
288}
289
290bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
291 Vector<KeyEvent>& outEvents) const {
292 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
293
294 for (size_t i = 0; i < numChars; i++) {
295 int32_t keyCode, metaState;
296 char16_t ch = chars[i];
297 if (!findKey(ch, &keyCode, &metaState)) {
298#if DEBUG_MAPPING
299 ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.",
300 deviceId, toString(chars, numChars).string(), ch);
301#endif
302 return false;
303 }
304
305 int32_t currentMetaState = 0;
306 addMetaKeys(outEvents, deviceId, metaState, true, now, &currentMetaState);
307 addKey(outEvents, deviceId, keyCode, currentMetaState, true, now);
308 addKey(outEvents, deviceId, keyCode, currentMetaState, false, now);
309 addMetaKeys(outEvents, deviceId, metaState, false, now, &currentMetaState);
310 }
311#if DEBUG_MAPPING
312 ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.",
313 deviceId, toString(chars, numChars).string(), int32_t(outEvents.size()));
314 for (size_t i = 0; i < outEvents.size(); i++) {
315 ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.",
316 outEvents[i].getKeyCode(), outEvents[i].getMetaState(),
317 outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up");
318 }
319#endif
320 return true;
321}
322
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000323void KeyCharacterMap::addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode) {
324 if (fromKeyCode == toKeyCode) {
325 mKeyRemapping.erase(fromKeyCode);
326#if DEBUG_MAPPING
327 ALOGD("addKeyRemapping: Cleared remapping forKeyCode=%d ~ Result Successful.", fromKeyCode);
328#endif
329 return;
330 }
331 mKeyRemapping.insert_or_assign(fromKeyCode, toKeyCode);
332#if DEBUG_MAPPING
333 ALOGD("addKeyRemapping: fromKeyCode=%d, toKeyCode=%d ~ Result Successful.", fromKeyCode,
334 toKeyCode);
335#endif
336}
337
Jeff Brown5912f952013-07-01 19:10:31 -0700338status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
339 if (usageCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000340 const auto it = mKeysByUsageCode.find(usageCode);
341 if (it != mKeysByUsageCode.end()) {
342 *outKeyCode = it->second;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700343#if DEBUG_MAPPING
344 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
345 scanCode, usageCode, *outKeyCode);
346#endif
Jeff Brown5912f952013-07-01 19:10:31 -0700347 return OK;
348 }
349 }
350 if (scanCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000351 const auto it = mKeysByScanCode.find(scanCode);
352 if (it != mKeysByScanCode.end()) {
353 *outKeyCode = it->second;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700354#if DEBUG_MAPPING
355 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
356 scanCode, usageCode, *outKeyCode);
357#endif
Jeff Brown5912f952013-07-01 19:10:31 -0700358 return OK;
359 }
360 }
361
362#if DEBUG_MAPPING
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700363 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700364#endif
365 *outKeyCode = AKEYCODE_UNKNOWN;
366 return NAME_NOT_FOUND;
367}
368
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000369int32_t KeyCharacterMap::applyKeyRemapping(int32_t fromKeyCode) const {
370 int32_t toKeyCode = fromKeyCode;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700371
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000372 const auto it = mKeyRemapping.find(fromKeyCode);
373 if (it != mKeyRemapping.end()) {
374 toKeyCode = it->second;
375 }
376#if DEBUG_MAPPING
377 ALOGD("applyKeyRemapping: keyCode=%d ~ replacement keyCode=%d.", fromKeyCode, toKeyCode);
378#endif
379 return toKeyCode;
380}
381
382std::pair<int32_t, int32_t> KeyCharacterMap::applyKeyBehavior(int32_t fromKeyCode,
383 int32_t fromMetaState) const {
384 int32_t toKeyCode = fromKeyCode;
385 int32_t toMetaState = fromMetaState;
386
387 const Behavior* behavior = getKeyBehavior(fromKeyCode, fromMetaState);
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700388 if (behavior != nullptr) {
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700389 if (behavior->replacementKeyCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000390 toKeyCode = behavior->replacementKeyCode;
391 toMetaState = fromMetaState & ~behavior->metaState;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700392 // Reset dependent meta states.
393 if (behavior->metaState & AMETA_ALT_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000394 toMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700395 }
396 if (behavior->metaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000397 toMetaState &= ~AMETA_ALT_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700398 }
399 if (behavior->metaState & AMETA_CTRL_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000400 toMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700401 }
402 if (behavior->metaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000403 toMetaState &= ~AMETA_CTRL_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700404 }
405 if (behavior->metaState & AMETA_SHIFT_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000406 toMetaState &= ~(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700407 }
408 if (behavior->metaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000409 toMetaState &= ~AMETA_SHIFT_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700410 }
411 // ... and put universal bits back if needed
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000412 toMetaState = normalizeMetaState(toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700413 }
414 }
415
416#if DEBUG_MAPPING
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000417 ALOGD("applyKeyBehavior: keyCode=%d, metaState=0x%08x ~ "
418 "replacement keyCode=%d, replacement metaState=0x%08x.",
419 fromKeyCode, fromMetaState, toKeyCode, toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700420#endif
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000421 return std::make_pair(toKeyCode, toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700422}
423
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700424const KeyCharacterMap::Key* KeyCharacterMap::getKey(int32_t keyCode) const {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700425 auto it = mKeys.find(keyCode);
426 if (it != mKeys.end()) {
427 return &it->second;
Jeff Brown5912f952013-07-01 19:10:31 -0700428 }
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700429 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700430}
431
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700432const KeyCharacterMap::Behavior* KeyCharacterMap::getKeyBehavior(int32_t keyCode,
433 int32_t metaState) const {
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700434 const Key* key = getKey(keyCode);
435 if (key != nullptr) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700436 for (const Behavior& behavior : key->behaviors) {
437 if (matchesMetaState(metaState, behavior.metaState)) {
438 return &behavior;
Jeff Brown5912f952013-07-01 19:10:31 -0700439 }
Jeff Brown5912f952013-07-01 19:10:31 -0700440 }
441 }
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700442 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700443}
444
445bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
446 // Behavior must have at least the set of meta states specified.
447 // And if the key event has CTRL, ALT or META then the behavior must exactly
448 // match those, taking into account that a behavior can specify that it handles
449 // one, both or either of a left/right modifier pair.
450 if ((eventMetaState & behaviorMetaState) == behaviorMetaState) {
451 const int32_t EXACT_META_STATES =
452 AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON
453 | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON
454 | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON;
455 int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES;
456 if (behaviorMetaState & AMETA_CTRL_ON) {
457 unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
458 } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
459 unmatchedMetaState &= ~AMETA_CTRL_ON;
460 }
461 if (behaviorMetaState & AMETA_ALT_ON) {
462 unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
463 } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
464 unmatchedMetaState &= ~AMETA_ALT_ON;
465 }
466 if (behaviorMetaState & AMETA_META_ON) {
467 unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
468 } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
469 unmatchedMetaState &= ~AMETA_META_ON;
470 }
471 return !unmatchedMetaState;
472 }
473 return false;
474}
475
476bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
477 if (!ch) {
478 return false;
479 }
480
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700481 for (const auto& [keyCode, key] : mKeys) {
Jeff Brown5912f952013-07-01 19:10:31 -0700482 // Try to find the most general behavior that maps to this character.
483 // For example, the base key behavior will usually be last in the list.
Yi Kong5bed83b2018-07-17 12:53:47 -0700484 const Behavior* found = nullptr;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700485 for (const Behavior& behavior : key.behaviors) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700486 if (behavior.character == ch) {
487 found = &behavior;
Jeff Brown5912f952013-07-01 19:10:31 -0700488 }
489 }
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700490 if (found != nullptr) {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700491 *outKeyCode = keyCode;
Jeff Brown5912f952013-07-01 19:10:31 -0700492 *outMetaState = found->metaState;
493 return true;
494 }
495 }
496 return false;
497}
498
499void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents,
500 int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
501 outEvents.push();
502 KeyEvent& event = outEvents.editTop();
Garfield Tan4cc839f2020-01-24 11:26:14 -0800503 event.initialize(InputEvent::nextId(), deviceId, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
504 INVALID_HMAC, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 0, keyCode,
505 0, metaState, 0, time, time);
Jeff Brown5912f952013-07-01 19:10:31 -0700506}
507
508void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
509 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
510 int32_t* currentMetaState) {
511 // Add and remove meta keys symmetrically.
512 if (down) {
513 addLockedMetaKey(outEvents, deviceId, metaState, time,
514 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
515 addLockedMetaKey(outEvents, deviceId, metaState, time,
516 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
517 addLockedMetaKey(outEvents, deviceId, metaState, time,
518 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
519
520 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
521 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
522 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
523 AMETA_SHIFT_ON, currentMetaState);
524 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
525 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
526 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
527 AMETA_ALT_ON, currentMetaState);
528 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
529 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
530 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
531 AMETA_CTRL_ON, currentMetaState);
532 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
533 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
534 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
535 AMETA_META_ON, currentMetaState);
536
537 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
538 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
539 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
540 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
541 } else {
542 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
543 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
544 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
545 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
546
547 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
548 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
549 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
550 AMETA_META_ON, currentMetaState);
551 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
552 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
553 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
554 AMETA_CTRL_ON, currentMetaState);
555 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
556 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
557 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
558 AMETA_ALT_ON, currentMetaState);
559 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
560 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
561 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
562 AMETA_SHIFT_ON, currentMetaState);
563
564 addLockedMetaKey(outEvents, deviceId, metaState, time,
565 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
566 addLockedMetaKey(outEvents, deviceId, metaState, time,
567 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
568 addLockedMetaKey(outEvents, deviceId, metaState, time,
569 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
570 }
571}
572
573bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
574 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
575 int32_t keyCode, int32_t keyMetaState,
576 int32_t* currentMetaState) {
577 if ((metaState & keyMetaState) == keyMetaState) {
578 *currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
579 addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
580 return true;
581 }
582 return false;
583}
584
585void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
586 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
587 int32_t leftKeyCode, int32_t leftKeyMetaState,
588 int32_t rightKeyCode, int32_t rightKeyMetaState,
589 int32_t eitherKeyMetaState,
590 int32_t* currentMetaState) {
591 bool specific = false;
592 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
593 leftKeyCode, leftKeyMetaState, currentMetaState);
594 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
595 rightKeyCode, rightKeyMetaState, currentMetaState);
596
597 if (!specific) {
598 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
599 leftKeyCode, eitherKeyMetaState, currentMetaState);
600 }
601}
602
603void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
604 int32_t deviceId, int32_t metaState, nsecs_t time,
605 int32_t keyCode, int32_t keyMetaState,
606 int32_t* currentMetaState) {
607 if ((metaState & keyMetaState) == keyMetaState) {
608 *currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
609 addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
610 *currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
611 addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
612 }
613}
614
Brett Chabotfaa986c2020-11-04 17:39:36 -0800615#ifdef __linux__
Chris Ye3a1e4462020-08-12 10:13:15 -0700616std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
617 if (parcel == nullptr) {
618 ALOGE("%s: Null parcel", __func__);
619 return nullptr;
620 }
Philip Junker90bc9492021-12-10 18:39:42 +0100621 std::string loadFileName = parcel->readCString();
622 std::shared_ptr<KeyCharacterMap> map =
623 std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(loadFileName));
Michael Wright102936e2020-11-04 03:44:27 +0000624 map->mType = static_cast<KeyCharacterMap::KeyboardType>(parcel->readInt32());
Philip Junker90bc9492021-12-10 18:39:42 +0100625 map->mLayoutOverlayApplied = parcel->readBool();
Jeff Brown5912f952013-07-01 19:10:31 -0700626 size_t numKeys = parcel->readInt32();
627 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700628 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700629 }
Michael Wright4c971c02015-10-21 14:38:03 +0100630 if (numKeys > MAX_KEYS) {
Ian Pedowitzd57d9b92016-02-19 08:34:43 +0000631 ALOGE("Too many keys in KeyCharacterMap (%zu > %d)", numKeys, MAX_KEYS);
Yi Kong5bed83b2018-07-17 12:53:47 -0700632 return nullptr;
Michael Wright4c971c02015-10-21 14:38:03 +0100633 }
Jeff Brown5912f952013-07-01 19:10:31 -0700634
635 for (size_t i = 0; i < numKeys; i++) {
636 int32_t keyCode = parcel->readInt32();
637 char16_t label = parcel->readInt32();
638 char16_t number = parcel->readInt32();
639 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700640 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700641 }
642
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700643 Key key{.label = label, .number = number};
Jeff Brown5912f952013-07-01 19:10:31 -0700644 while (parcel->readInt32()) {
645 int32_t metaState = parcel->readInt32();
646 char16_t character = parcel->readInt32();
647 int32_t fallbackKeyCode = parcel->readInt32();
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700648 int32_t replacementKeyCode = parcel->readInt32();
Jeff Brown5912f952013-07-01 19:10:31 -0700649 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700650 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700651 }
652
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700653 key.behaviors.push_back({
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700654 .metaState = metaState,
655 .character = character,
656 .fallbackKeyCode = fallbackKeyCode,
657 .replacementKeyCode = replacementKeyCode,
658 });
Jeff Brown5912f952013-07-01 19:10:31 -0700659 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700660 map->mKeys.emplace(keyCode, std::move(key));
Jeff Brown5912f952013-07-01 19:10:31 -0700661
662 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700663 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700664 }
665 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000666 size_t numKeyRemapping = parcel->readInt32();
667 if (parcel->errorCheck()) {
668 return nullptr;
669 }
670 for (size_t i = 0; i < numKeyRemapping; i++) {
671 int32_t key = parcel->readInt32();
672 int32_t value = parcel->readInt32();
673 map->mKeyRemapping.insert_or_assign(key, value);
674 if (parcel->errorCheck()) {
675 return nullptr;
676 }
677 }
Philip Junker90bc9492021-12-10 18:39:42 +0100678 size_t numKeysByScanCode = parcel->readInt32();
679 if (parcel->errorCheck()) {
680 return nullptr;
681 }
682 for (size_t i = 0; i < numKeysByScanCode; i++) {
683 int32_t key = parcel->readInt32();
684 int32_t value = parcel->readInt32();
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000685 map->mKeysByScanCode.insert_or_assign(key, value);
Philip Junker90bc9492021-12-10 18:39:42 +0100686 if (parcel->errorCheck()) {
687 return nullptr;
688 }
689 }
690 size_t numKeysByUsageCode = parcel->readInt32();
691 if (parcel->errorCheck()) {
692 return nullptr;
693 }
694 for (size_t i = 0; i < numKeysByUsageCode; i++) {
695 int32_t key = parcel->readInt32();
696 int32_t value = parcel->readInt32();
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000697 map->mKeysByUsageCode.insert_or_assign(key, value);
Philip Junker90bc9492021-12-10 18:39:42 +0100698 if (parcel->errorCheck()) {
699 return nullptr;
700 }
701 }
Jeff Brown5912f952013-07-01 19:10:31 -0700702 return map;
703}
704
705void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
Chris Ye3a1e4462020-08-12 10:13:15 -0700706 if (parcel == nullptr) {
707 ALOGE("%s: Null parcel", __func__);
708 return;
709 }
Philip Junker90bc9492021-12-10 18:39:42 +0100710 parcel->writeCString(mLoadFileName.c_str());
Michael Wright102936e2020-11-04 03:44:27 +0000711 parcel->writeInt32(static_cast<int32_t>(mType));
Philip Junker90bc9492021-12-10 18:39:42 +0100712 parcel->writeBool(mLayoutOverlayApplied);
Jeff Brown5912f952013-07-01 19:10:31 -0700713
714 size_t numKeys = mKeys.size();
715 parcel->writeInt32(numKeys);
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700716 for (const auto& [keyCode, key] : mKeys) {
Jeff Brown5912f952013-07-01 19:10:31 -0700717 parcel->writeInt32(keyCode);
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700718 parcel->writeInt32(key.label);
719 parcel->writeInt32(key.number);
720 for (const Behavior& behavior : key.behaviors) {
Jeff Brown5912f952013-07-01 19:10:31 -0700721 parcel->writeInt32(1);
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700722 parcel->writeInt32(behavior.metaState);
723 parcel->writeInt32(behavior.character);
724 parcel->writeInt32(behavior.fallbackKeyCode);
725 parcel->writeInt32(behavior.replacementKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700726 }
727 parcel->writeInt32(0);
728 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000729 size_t numKeyRemapping = mKeyRemapping.size();
730 parcel->writeInt32(numKeyRemapping);
731 for (auto const& [fromAndroidKeyCode, toAndroidKeyCode] : mKeyRemapping) {
732 parcel->writeInt32(fromAndroidKeyCode);
733 parcel->writeInt32(toAndroidKeyCode);
734 }
Philip Junker90bc9492021-12-10 18:39:42 +0100735 size_t numKeysByScanCode = mKeysByScanCode.size();
736 parcel->writeInt32(numKeysByScanCode);
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000737 for (auto const& [fromScanCode, toAndroidKeyCode] : mKeysByScanCode) {
738 parcel->writeInt32(fromScanCode);
739 parcel->writeInt32(toAndroidKeyCode);
Philip Junker90bc9492021-12-10 18:39:42 +0100740 }
741 size_t numKeysByUsageCode = mKeysByUsageCode.size();
742 parcel->writeInt32(numKeysByUsageCode);
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000743 for (auto const& [fromUsageCode, toAndroidKeyCode] : mKeysByUsageCode) {
744 parcel->writeInt32(fromUsageCode);
745 parcel->writeInt32(toAndroidKeyCode);
Philip Junker90bc9492021-12-10 18:39:42 +0100746 }
Jeff Brown5912f952013-07-01 19:10:31 -0700747}
Brett Chabotfaa986c2020-11-04 17:39:36 -0800748#endif // __linux__
Jeff Brown5912f952013-07-01 19:10:31 -0700749
Jeff Brown5912f952013-07-01 19:10:31 -0700750// --- KeyCharacterMap::Parser ---
751
752KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
753 mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
754}
755
Jeff Brown5912f952013-07-01 19:10:31 -0700756status_t KeyCharacterMap::Parser::parse() {
757 while (!mTokenizer->isEof()) {
758#if DEBUG_PARSER
759 ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
760 mTokenizer->peekRemainderOfLine().string());
761#endif
762
763 mTokenizer->skipDelimiters(WHITESPACE);
764
765 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
766 switch (mState) {
767 case STATE_TOP: {
768 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
769 if (keywordToken == "type") {
770 mTokenizer->skipDelimiters(WHITESPACE);
771 status_t status = parseType();
772 if (status) return status;
773 } else if (keywordToken == "map") {
774 mTokenizer->skipDelimiters(WHITESPACE);
775 status_t status = parseMap();
776 if (status) return status;
777 } else if (keywordToken == "key") {
778 mTokenizer->skipDelimiters(WHITESPACE);
779 status_t status = parseKey();
780 if (status) return status;
781 } else {
782 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
783 keywordToken.string());
784 return BAD_VALUE;
785 }
786 break;
787 }
788
789 case STATE_KEY: {
790 status_t status = parseKeyProperty();
791 if (status) return status;
792 break;
793 }
794 }
795
796 mTokenizer->skipDelimiters(WHITESPACE);
797 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
798 ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
799 mTokenizer->getLocation().string(),
800 mTokenizer->peekRemainderOfLine().string());
801 return BAD_VALUE;
802 }
803 }
804
805 mTokenizer->nextLine();
806 }
807
808 if (mState != STATE_TOP) {
809 ALOGE("%s: Unterminated key description at end of file.",
810 mTokenizer->getLocation().string());
811 return BAD_VALUE;
812 }
813
Michael Wright102936e2020-11-04 03:44:27 +0000814 if (mMap->mType == KeyboardType::UNKNOWN) {
Jeff Brown5912f952013-07-01 19:10:31 -0700815 ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
816 mTokenizer->getLocation().string());
817 return BAD_VALUE;
818 }
819
Michael Wright102936e2020-11-04 03:44:27 +0000820 if (mFormat == Format::BASE) {
821 if (mMap->mType == KeyboardType::OVERLAY) {
Jeff Brown5912f952013-07-01 19:10:31 -0700822 ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
823 mTokenizer->getLocation().string());
824 return BAD_VALUE;
825 }
Michael Wright102936e2020-11-04 03:44:27 +0000826 } else if (mFormat == Format::OVERLAY) {
827 if (mMap->mType != KeyboardType::OVERLAY) {
Jeff Brown5912f952013-07-01 19:10:31 -0700828 ALOGE("%s: Overlay keyboard layout missing required keyboard "
829 "'type OVERLAY' declaration.",
830 mTokenizer->getLocation().string());
831 return BAD_VALUE;
832 }
833 }
834
835 return NO_ERROR;
836}
837
838status_t KeyCharacterMap::Parser::parseType() {
Michael Wright102936e2020-11-04 03:44:27 +0000839 if (mMap->mType != KeyboardType::UNKNOWN) {
Jeff Brown5912f952013-07-01 19:10:31 -0700840 ALOGE("%s: Duplicate keyboard 'type' declaration.",
841 mTokenizer->getLocation().string());
842 return BAD_VALUE;
843 }
844
845 KeyboardType type;
846 String8 typeToken = mTokenizer->nextToken(WHITESPACE);
847 if (typeToken == "NUMERIC") {
Michael Wright102936e2020-11-04 03:44:27 +0000848 type = KeyboardType::NUMERIC;
Jeff Brown5912f952013-07-01 19:10:31 -0700849 } else if (typeToken == "PREDICTIVE") {
Michael Wright102936e2020-11-04 03:44:27 +0000850 type = KeyboardType::PREDICTIVE;
Jeff Brown5912f952013-07-01 19:10:31 -0700851 } else if (typeToken == "ALPHA") {
Michael Wright102936e2020-11-04 03:44:27 +0000852 type = KeyboardType::ALPHA;
Jeff Brown5912f952013-07-01 19:10:31 -0700853 } else if (typeToken == "FULL") {
Michael Wright102936e2020-11-04 03:44:27 +0000854 type = KeyboardType::FULL;
Jeff Brown5912f952013-07-01 19:10:31 -0700855 } else if (typeToken == "SPECIAL_FUNCTION") {
Siarhei Vishniakou61da25a2018-02-15 21:04:49 -0600856 ALOGW("The SPECIAL_FUNCTION type is now declared in the device's IDC file, please set "
857 "the property 'keyboard.specialFunction' to '1' there instead.");
858 // TODO: return BAD_VALUE here in Q
Michael Wright102936e2020-11-04 03:44:27 +0000859 type = KeyboardType::SPECIAL_FUNCTION;
Jeff Brown5912f952013-07-01 19:10:31 -0700860 } else if (typeToken == "OVERLAY") {
Michael Wright102936e2020-11-04 03:44:27 +0000861 type = KeyboardType::OVERLAY;
Jeff Brown5912f952013-07-01 19:10:31 -0700862 } else {
863 ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(),
864 typeToken.string());
865 return BAD_VALUE;
866 }
867
868#if DEBUG_PARSER
869 ALOGD("Parsed type: type=%d.", type);
870#endif
871 mMap->mType = type;
872 return NO_ERROR;
873}
874
875status_t KeyCharacterMap::Parser::parseMap() {
876 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
877 if (keywordToken == "key") {
878 mTokenizer->skipDelimiters(WHITESPACE);
879 return parseMapKey();
880 }
881 ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(),
882 keywordToken.string());
883 return BAD_VALUE;
884}
885
886status_t KeyCharacterMap::Parser::parseMapKey() {
887 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
888 bool mapUsage = false;
889 if (codeToken == "usage") {
890 mapUsage = true;
891 mTokenizer->skipDelimiters(WHITESPACE);
892 codeToken = mTokenizer->nextToken(WHITESPACE);
893 }
894
895 char* end;
896 int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
897 if (*end) {
898 ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
899 mapUsage ? "usage" : "scan code", codeToken.string());
900 return BAD_VALUE;
901 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000902 std::map<int32_t, int32_t>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
903 const auto it = map.find(code);
904 if (it != map.end()) {
Jeff Brown5912f952013-07-01 19:10:31 -0700905 ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
906 mapUsage ? "usage" : "scan code", codeToken.string());
907 return BAD_VALUE;
908 }
909
910 mTokenizer->skipDelimiters(WHITESPACE);
911 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800912 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700913 if (!keyCode) {
914 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
915 keyCodeToken.string());
916 return BAD_VALUE;
917 }
918
919#if DEBUG_PARSER
920 ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
921 mapUsage ? "usage" : "scan code", code, keyCode);
922#endif
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800923 map.insert_or_assign(code, *keyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700924 return NO_ERROR;
925}
926
927status_t KeyCharacterMap::Parser::parseKey() {
928 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800929 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -0700930 if (!keyCode) {
931 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
932 keyCodeToken.string());
933 return BAD_VALUE;
934 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700935 if (mMap->mKeys.find(*keyCode) != mMap->mKeys.end()) {
Jeff Brown5912f952013-07-01 19:10:31 -0700936 ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(),
937 keyCodeToken.string());
938 return BAD_VALUE;
939 }
940
941 mTokenizer->skipDelimiters(WHITESPACE);
942 String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
943 if (openBraceToken != "{") {
944 ALOGE("%s: Expected '{' after key code label, got '%s'.",
945 mTokenizer->getLocation().string(), openBraceToken.string());
946 return BAD_VALUE;
947 }
948
Siarhei Vishniakou5df34932023-01-23 12:41:01 -0800949 ALOGD_IF(DEBUG_PARSER, "Parsed beginning of key: keyCode=%d.", *keyCode);
950 mKeyCode = *keyCode;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700951 mMap->mKeys.emplace(*keyCode, Key{});
Jeff Brown5912f952013-07-01 19:10:31 -0700952 mState = STATE_KEY;
953 return NO_ERROR;
954}
955
956status_t KeyCharacterMap::Parser::parseKeyProperty() {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700957 Key& key = mMap->mKeys[mKeyCode];
Jeff Brown5912f952013-07-01 19:10:31 -0700958 String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
959 if (token == "}") {
960 mState = STATE_TOP;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -0700961 return finishKey(key);
Jeff Brown5912f952013-07-01 19:10:31 -0700962 }
963
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700964 std::vector<Property> properties;
Jeff Brown5912f952013-07-01 19:10:31 -0700965
966 // Parse all comma-delimited property names up to the first colon.
967 for (;;) {
968 if (token == "label") {
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700969 properties.emplace_back(PROPERTY_LABEL);
Jeff Brown5912f952013-07-01 19:10:31 -0700970 } else if (token == "number") {
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700971 properties.emplace_back(PROPERTY_NUMBER);
Jeff Brown5912f952013-07-01 19:10:31 -0700972 } else {
973 int32_t metaState;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100974 status_t status = parseModifier(token.string(), &metaState);
Jeff Brown5912f952013-07-01 19:10:31 -0700975 if (status) {
976 ALOGE("%s: Expected a property name or modifier, got '%s'.",
977 mTokenizer->getLocation().string(), token.string());
978 return status;
979 }
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -0700980 properties.emplace_back(PROPERTY_META, metaState);
Jeff Brown5912f952013-07-01 19:10:31 -0700981 }
982
983 mTokenizer->skipDelimiters(WHITESPACE);
984 if (!mTokenizer->isEol()) {
985 char ch = mTokenizer->nextChar();
986 if (ch == ':') {
987 break;
988 } else if (ch == ',') {
989 mTokenizer->skipDelimiters(WHITESPACE);
990 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
991 continue;
992 }
993 }
994
995 ALOGE("%s: Expected ',' or ':' after property name.",
996 mTokenizer->getLocation().string());
997 return BAD_VALUE;
998 }
999
1000 // Parse behavior after the colon.
1001 mTokenizer->skipDelimiters(WHITESPACE);
1002
1003 Behavior behavior;
1004 bool haveCharacter = false;
1005 bool haveFallback = false;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001006 bool haveReplacement = false;
Jeff Brown5912f952013-07-01 19:10:31 -07001007
1008 do {
1009 char ch = mTokenizer->peekChar();
1010 if (ch == '\'') {
1011 char16_t character;
1012 status_t status = parseCharacterLiteral(&character);
1013 if (status || !character) {
1014 ALOGE("%s: Invalid character literal for key.",
1015 mTokenizer->getLocation().string());
1016 return BAD_VALUE;
1017 }
1018 if (haveCharacter) {
1019 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
1020 mTokenizer->getLocation().string());
1021 return BAD_VALUE;
1022 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001023 if (haveReplacement) {
1024 ALOGE("%s: Cannot combine character literal with replace action.",
1025 mTokenizer->getLocation().string());
1026 return BAD_VALUE;
1027 }
Jeff Brown5912f952013-07-01 19:10:31 -07001028 behavior.character = character;
1029 haveCharacter = true;
1030 } else {
1031 token = mTokenizer->nextToken(WHITESPACE);
1032 if (token == "none") {
1033 if (haveCharacter) {
1034 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
1035 mTokenizer->getLocation().string());
1036 return BAD_VALUE;
1037 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001038 if (haveReplacement) {
1039 ALOGE("%s: Cannot combine 'none' with replace action.",
1040 mTokenizer->getLocation().string());
1041 return BAD_VALUE;
1042 }
Jeff Brown5912f952013-07-01 19:10:31 -07001043 haveCharacter = true;
1044 } else if (token == "fallback") {
1045 mTokenizer->skipDelimiters(WHITESPACE);
1046 token = mTokenizer->nextToken(WHITESPACE);
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001047 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(token.string());
Jeff Brown5912f952013-07-01 19:10:31 -07001048 if (!keyCode) {
1049 ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
1050 mTokenizer->getLocation().string(),
1051 token.string());
1052 return BAD_VALUE;
1053 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001054 if (haveFallback || haveReplacement) {
1055 ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
Jeff Brown5912f952013-07-01 19:10:31 -07001056 mTokenizer->getLocation().string());
1057 return BAD_VALUE;
1058 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001059 behavior.fallbackKeyCode = *keyCode;
Jeff Brown5912f952013-07-01 19:10:31 -07001060 haveFallback = true;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001061 } else if (token == "replace") {
1062 mTokenizer->skipDelimiters(WHITESPACE);
1063 token = mTokenizer->nextToken(WHITESPACE);
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001064 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(token.string());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001065 if (!keyCode) {
1066 ALOGE("%s: Invalid key code label for replace, got '%s'.",
1067 mTokenizer->getLocation().string(),
1068 token.string());
1069 return BAD_VALUE;
1070 }
1071 if (haveCharacter) {
1072 ALOGE("%s: Cannot combine character literal with replace action.",
1073 mTokenizer->getLocation().string());
1074 return BAD_VALUE;
1075 }
1076 if (haveFallback || haveReplacement) {
1077 ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
1078 mTokenizer->getLocation().string());
1079 return BAD_VALUE;
1080 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001081 behavior.replacementKeyCode = *keyCode;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001082 haveReplacement = true;
1083
Jeff Brown5912f952013-07-01 19:10:31 -07001084 } else {
1085 ALOGE("%s: Expected a key behavior after ':'.",
1086 mTokenizer->getLocation().string());
1087 return BAD_VALUE;
1088 }
1089 }
1090
1091 mTokenizer->skipDelimiters(WHITESPACE);
1092 } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#');
1093
1094 // Add the behavior.
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -07001095 for (const Property& property : properties) {
Jeff Brown5912f952013-07-01 19:10:31 -07001096 switch (property.property) {
1097 case PROPERTY_LABEL:
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001098 if (key.label) {
1099 ALOGE("%s: Duplicate label for key.", mTokenizer->getLocation().string());
1100 return BAD_VALUE;
1101 }
1102 key.label = behavior.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001103#if DEBUG_PARSER
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001104 ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key.label);
Jeff Brown5912f952013-07-01 19:10:31 -07001105#endif
1106 break;
1107 case PROPERTY_NUMBER:
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001108 if (key.number) {
1109 ALOGE("%s: Duplicate number for key.", mTokenizer->getLocation().string());
1110 return BAD_VALUE;
Jeff Brown5912f952013-07-01 19:10:31 -07001111 }
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001112 key.number = behavior.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001113#if DEBUG_PARSER
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001114 ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key.number);
Jeff Brown5912f952013-07-01 19:10:31 -07001115#endif
1116 break;
1117 case PROPERTY_META: {
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001118 for (const Behavior& b : key.behaviors) {
1119 if (b.metaState == property.metaState) {
Jeff Brown5912f952013-07-01 19:10:31 -07001120 ALOGE("%s: Duplicate key behavior for modifier.",
1121 mTokenizer->getLocation().string());
1122 return BAD_VALUE;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001123 }
Jeff Brown5912f952013-07-01 19:10:31 -07001124 }
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001125 Behavior newBehavior = behavior;
1126 newBehavior.metaState = property.metaState;
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001127 key.behaviors.push_front(newBehavior);
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001128 ALOGD_IF(DEBUG_PARSER,
1129 "Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
Siarhei Vishniakou2a916c42023-04-17 10:37:05 -07001130 mKeyCode, key.behaviors.front().metaState, key.behaviors.front().character,
1131 key.behaviors.front().fallbackKeyCode,
1132 key.behaviors.front().replacementKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -07001133 break;
1134 }
1135 }
1136 }
1137 return NO_ERROR;
1138}
1139
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001140status_t KeyCharacterMap::Parser::finishKey(Key& key) {
Jeff Brown5912f952013-07-01 19:10:31 -07001141 // Fill in default number property.
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001142 if (!key.number) {
Jeff Brown5912f952013-07-01 19:10:31 -07001143 char16_t digit = 0;
1144 char16_t symbol = 0;
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001145 for (const Behavior& b : key.behaviors) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001146 char16_t ch = b.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001147 if (ch) {
1148 if (ch >= '0' && ch <= '9') {
1149 digit = ch;
1150 } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
1151 || ch == '-' || ch == '+' || ch == ',' || ch == '.'
1152 || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
1153 symbol = ch;
1154 }
1155 }
1156 }
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001157 key.number = digit ? digit : symbol;
Jeff Brown5912f952013-07-01 19:10:31 -07001158 }
1159 return NO_ERROR;
1160}
1161
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001162status_t KeyCharacterMap::Parser::parseModifier(const std::string& token, int32_t* outMetaState) {
Jeff Brown5912f952013-07-01 19:10:31 -07001163 if (token == "base") {
1164 *outMetaState = 0;
1165 return NO_ERROR;
1166 }
1167
1168 int32_t combinedMeta = 0;
1169
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001170 const char* str = token.c_str();
Jeff Brown5912f952013-07-01 19:10:31 -07001171 const char* start = str;
1172 for (const char* cur = str; ; cur++) {
1173 char ch = *cur;
1174 if (ch == '+' || ch == '\0') {
1175 size_t len = cur - start;
1176 int32_t metaState = 0;
1177 for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
1178 if (strlen(modifiers[i].label) == len
1179 && strncmp(modifiers[i].label, start, len) == 0) {
1180 metaState = modifiers[i].metaState;
1181 break;
1182 }
1183 }
1184 if (!metaState) {
1185 return BAD_VALUE;
1186 }
1187 if (combinedMeta & metaState) {
1188 ALOGE("%s: Duplicate modifier combination '%s'.",
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001189 mTokenizer->getLocation().string(), token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001190 return BAD_VALUE;
1191 }
1192
1193 combinedMeta |= metaState;
1194 start = cur + 1;
1195
1196 if (ch == '\0') {
1197 break;
1198 }
1199 }
1200 }
1201 *outMetaState = combinedMeta;
1202 return NO_ERROR;
1203}
1204
1205status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
1206 char ch = mTokenizer->nextChar();
1207 if (ch != '\'') {
1208 goto Error;
1209 }
1210
1211 ch = mTokenizer->nextChar();
1212 if (ch == '\\') {
1213 // Escape sequence.
1214 ch = mTokenizer->nextChar();
1215 if (ch == 'n') {
1216 *outCharacter = '\n';
1217 } else if (ch == 't') {
1218 *outCharacter = '\t';
1219 } else if (ch == '\\') {
1220 *outCharacter = '\\';
1221 } else if (ch == '\'') {
1222 *outCharacter = '\'';
1223 } else if (ch == '"') {
1224 *outCharacter = '"';
1225 } else if (ch == 'u') {
1226 *outCharacter = 0;
1227 for (int i = 0; i < 4; i++) {
1228 ch = mTokenizer->nextChar();
1229 int digit;
1230 if (ch >= '0' && ch <= '9') {
1231 digit = ch - '0';
1232 } else if (ch >= 'A' && ch <= 'F') {
1233 digit = ch - 'A' + 10;
1234 } else if (ch >= 'a' && ch <= 'f') {
1235 digit = ch - 'a' + 10;
1236 } else {
1237 goto Error;
1238 }
1239 *outCharacter = (*outCharacter << 4) | digit;
1240 }
1241 } else {
1242 goto Error;
1243 }
1244 } else if (ch >= 32 && ch <= 126 && ch != '\'') {
1245 // ASCII literal character.
1246 *outCharacter = ch;
1247 } else {
1248 goto Error;
1249 }
1250
1251 ch = mTokenizer->nextChar();
1252 if (ch != '\'') {
1253 goto Error;
1254 }
1255
1256 // Ensure that we consumed the entire token.
1257 if (mTokenizer->nextToken(WHITESPACE).isEmpty()) {
1258 return NO_ERROR;
1259 }
1260
1261Error:
1262 ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string());
1263 return BAD_VALUE;
1264}
1265
1266} // namespace android