blob: f703901ed9f96ce2df3559b65ba4932868f9523b [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
Philip Junker90bc9492021-12-10 18:39:42 +010088KeyCharacterMap::KeyCharacterMap(const std::string& filename)
89 : mType(KeyboardType::UNKNOWN), mLoadFileName(filename) {}
Jeff Brown5912f952013-07-01 19:10:31 -070090
Chris Ye3a1e4462020-08-12 10:13:15 -070091KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other)
92 : mType(other.mType),
Philip Junker90bc9492021-12-10 18:39:42 +010093 mLoadFileName(other.mLoadFileName),
94 mLayoutOverlayApplied(other.mLayoutOverlayApplied),
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +000095 mKeyRemapping(other.mKeyRemapping),
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 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000117 if (mKeys.size() != other.mKeys.size() || mKeyRemapping.size() != other.mKeyRemapping.size() ||
Chris Yef59a2f42020-10-16 12:55:26 -0700118 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
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000134 if (mKeyRemapping != other.mKeyRemapping || mKeysByScanCode != other.mKeysByScanCode ||
135 mKeysByUsageCode != other.mKeysByUsageCode) {
136 return false;
Chris Yef59a2f42020-10-16 12:55:26 -0700137 }
138
139 return true;
140}
141
Philip Junker90bc9492021-12-10 18:39:42 +0100142bool KeyCharacterMap::operator!=(const KeyCharacterMap& other) const {
143 return !(*this == other);
144}
145
Chris Ye3a1e4462020-08-12 10:13:15 -0700146base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename,
147 Format format) {
Jeff Brown5912f952013-07-01 19:10:31 -0700148 Tokenizer* tokenizer;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100149 status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
Jeff Brown5912f952013-07-01 19:10:31 -0700150 if (status) {
Chris Ye3a1e4462020-08-12 10:13:15 -0700151 return Errorf("Error {} opening key character map file {}.", status, filename.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700152 }
Philip Junker90bc9492021-12-10 18:39:42 +0100153 std::shared_ptr<KeyCharacterMap> map =
154 std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
155 if (!map.get()) {
156 ALOGE("Error allocating key character map.");
157 return Errorf("Error allocating key character map.");
Chris Ye3a1e4462020-08-12 10:13:15 -0700158 }
Philip Junker90bc9492021-12-10 18:39:42 +0100159 std::unique_ptr<Tokenizer> t(tokenizer);
160 status = map->load(t.get(), format);
161 if (status == OK) {
162 return map;
163 }
164 return Errorf("Load KeyCharacterMap failed {}.", status);
Jeff Brown5912f952013-07-01 19:10:31 -0700165}
166
Chris Ye3a1e4462020-08-12 10:13:15 -0700167base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::loadContents(
168 const std::string& filename, const char* contents, Format format) {
Jeff Brown5912f952013-07-01 19:10:31 -0700169 Tokenizer* tokenizer;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100170 status_t status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
Jeff Brown5912f952013-07-01 19:10:31 -0700171 if (status) {
172 ALOGE("Error %d opening key character map.", status);
Chris Ye3a1e4462020-08-12 10:13:15 -0700173 return Errorf("Error {} opening key character map.", status);
Jeff Brown5912f952013-07-01 19:10:31 -0700174 }
Philip Junker90bc9492021-12-10 18:39:42 +0100175 std::shared_ptr<KeyCharacterMap> map =
176 std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
Jeff Brown5912f952013-07-01 19:10:31 -0700177 if (!map.get()) {
178 ALOGE("Error allocating key character map.");
Chris Ye3a1e4462020-08-12 10:13:15 -0700179 return Errorf("Error allocating key character map.");
Jeff Brown5912f952013-07-01 19:10:31 -0700180 }
Philip Junker90bc9492021-12-10 18:39:42 +0100181 std::unique_ptr<Tokenizer> t(tokenizer);
182 status = map->load(t.get(), format);
183 if (status == OK) {
184 return map;
185 }
186 return Errorf("Load KeyCharacterMap failed {}.", status);
187}
188
189status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format) {
190 status_t status = OK;
Chris Ye3a1e4462020-08-12 10:13:15 -0700191#if DEBUG_PARSER_PERFORMANCE
192 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
193#endif
Philip Junker90bc9492021-12-10 18:39:42 +0100194 Parser parser(this, tokenizer, format);
Chris Ye3a1e4462020-08-12 10:13:15 -0700195 status = parser.parse();
196#if DEBUG_PARSER_PERFORMANCE
197 nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
198 ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
199 tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0);
200#endif
Philip Junker90bc9492021-12-10 18:39:42 +0100201 if (status != OK) {
202 ALOGE("Loading KeyCharacterMap failed with status %s", statusToString(status).c_str());
Chris Ye3a1e4462020-08-12 10:13:15 -0700203 }
Philip Junker90bc9492021-12-10 18:39:42 +0100204 return status;
205}
Chris Ye3a1e4462020-08-12 10:13:15 -0700206
Philip Junker90bc9492021-12-10 18:39:42 +0100207void KeyCharacterMap::clear() {
208 mKeysByScanCode.clear();
209 mKeysByUsageCode.clear();
210 for (size_t i = 0; i < mKeys.size(); i++) {
211 Key* key = mKeys.editValueAt(i);
212 delete key;
213 }
214 mKeys.clear();
215 mLayoutOverlayApplied = false;
216 mType = KeyboardType::UNKNOWN;
217}
218
219status_t KeyCharacterMap::reloadBaseFromFile() {
220 clear();
221 Tokenizer* tokenizer;
222 status_t status = Tokenizer::open(String8(mLoadFileName.c_str()), &tokenizer);
223 if (status) {
224 ALOGE("Error %s opening key character map file %s.", statusToString(status).c_str(),
225 mLoadFileName.c_str());
226 return status;
227 }
228 std::unique_ptr<Tokenizer> t(tokenizer);
229 return load(t.get(), KeyCharacterMap::Format::BASE);
Jeff Brown5912f952013-07-01 19:10:31 -0700230}
231
Chris Ye3a1e4462020-08-12 10:13:15 -0700232void KeyCharacterMap::combine(const KeyCharacterMap& overlay) {
Philip Junker90bc9492021-12-10 18:39:42 +0100233 if (mLayoutOverlayApplied) {
234 reloadBaseFromFile();
235 }
Chris Ye3a1e4462020-08-12 10:13:15 -0700236 for (size_t i = 0; i < overlay.mKeys.size(); i++) {
237 int32_t keyCode = overlay.mKeys.keyAt(i);
238 Key* key = overlay.mKeys.valueAt(i);
239 ssize_t oldIndex = mKeys.indexOfKey(keyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700240 if (oldIndex >= 0) {
Chris Ye3a1e4462020-08-12 10:13:15 -0700241 delete mKeys.valueAt(oldIndex);
242 mKeys.editValueAt(oldIndex) = new Key(*key);
Jeff Brown5912f952013-07-01 19:10:31 -0700243 } else {
Chris Ye3a1e4462020-08-12 10:13:15 -0700244 mKeys.add(keyCode, new Key(*key));
Jeff Brown5912f952013-07-01 19:10:31 -0700245 }
246 }
247
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000248 for (auto const& it : overlay.mKeysByScanCode) {
249 mKeysByScanCode.insert_or_assign(it.first, it.second);
Jeff Brown5912f952013-07-01 19:10:31 -0700250 }
251
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000252 for (auto const& it : overlay.mKeysByUsageCode) {
253 mKeysByUsageCode.insert_or_assign(it.first, it.second);
Jeff Brown5912f952013-07-01 19:10:31 -0700254 }
Philip Junker90bc9492021-12-10 18:39:42 +0100255 mLayoutOverlayApplied = true;
Jeff Brown5912f952013-07-01 19:10:31 -0700256}
257
Vaibhav Devmurari23e8ae92022-12-29 12:07:56 +0000258void KeyCharacterMap::clearLayoutOverlay() {
259 if (mLayoutOverlayApplied) {
260 reloadBaseFromFile();
261 mLayoutOverlayApplied = false;
262 }
263}
264
Michael Wright102936e2020-11-04 03:44:27 +0000265KeyCharacterMap::KeyboardType KeyCharacterMap::getKeyboardType() const {
Jeff Brown5912f952013-07-01 19:10:31 -0700266 return mType;
267}
268
Chris Ye3a1e4462020-08-12 10:13:15 -0700269const std::string KeyCharacterMap::getLoadFileName() const {
270 return mLoadFileName;
271}
272
Jeff Brown5912f952013-07-01 19:10:31 -0700273char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const {
274 char16_t result = 0;
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700275 const Key* key = getKey(keyCode);
276 if (key != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700277 result = key->label;
278 }
279#if DEBUG_MAPPING
280 ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result);
281#endif
282 return result;
283}
284
285char16_t KeyCharacterMap::getNumber(int32_t keyCode) const {
286 char16_t result = 0;
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700287 const Key* key = getKey(keyCode);
288 if (key != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700289 result = key->number;
290 }
291#if DEBUG_MAPPING
292 ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result);
293#endif
294 return result;
295}
296
297char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
298 char16_t result = 0;
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700299 const Behavior* behavior = getKeyBehavior(keyCode, metaState);
300 if (behavior != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700301 result = behavior->character;
302 }
303#if DEBUG_MAPPING
304 ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result);
305#endif
306 return result;
307}
308
309bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState,
310 FallbackAction* outFallbackAction) const {
311 outFallbackAction->keyCode = 0;
312 outFallbackAction->metaState = 0;
313
314 bool result = false;
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700315 const Behavior* behavior = getKeyBehavior(keyCode, metaState);
316 if (behavior != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700317 if (behavior->fallbackKeyCode) {
318 outFallbackAction->keyCode = behavior->fallbackKeyCode;
319 outFallbackAction->metaState = metaState & ~behavior->metaState;
320 result = true;
321 }
322 }
323#if DEBUG_MAPPING
324 ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, "
325 "fallback keyCode=%d, fallback metaState=0x%08x.",
326 keyCode, metaState, result ? "true" : "false",
327 outFallbackAction->keyCode, outFallbackAction->metaState);
328#endif
329 return result;
330}
331
332char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars,
333 int32_t metaState) const {
334 char16_t result = 0;
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700335 const Key* key = getKey(keyCode);
336 if (key != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700337 // Try to find the most general behavior that maps to this character.
338 // For example, the base key behavior will usually be last in the list.
339 // However, if we find a perfect meta state match for one behavior then use that one.
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700340 for (const Behavior& behavior : key->behaviors) {
341 if (behavior.character) {
Jeff Brown5912f952013-07-01 19:10:31 -0700342 for (size_t i = 0; i < numChars; i++) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700343 if (behavior.character == chars[i]) {
344 result = behavior.character;
345 if ((behavior.metaState & metaState) == behavior.metaState) {
Jeff Brown5912f952013-07-01 19:10:31 -0700346 goto ExactMatch;
347 }
348 break;
349 }
350 }
351 }
352 }
353 ExactMatch: ;
354 }
355#if DEBUG_MAPPING
356 ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.",
357 keyCode, toString(chars, numChars).string(), metaState, result);
358#endif
359 return result;
360}
361
362bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
363 Vector<KeyEvent>& outEvents) const {
364 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
365
366 for (size_t i = 0; i < numChars; i++) {
367 int32_t keyCode, metaState;
368 char16_t ch = chars[i];
369 if (!findKey(ch, &keyCode, &metaState)) {
370#if DEBUG_MAPPING
371 ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.",
372 deviceId, toString(chars, numChars).string(), ch);
373#endif
374 return false;
375 }
376
377 int32_t currentMetaState = 0;
378 addMetaKeys(outEvents, deviceId, metaState, true, now, &currentMetaState);
379 addKey(outEvents, deviceId, keyCode, currentMetaState, true, now);
380 addKey(outEvents, deviceId, keyCode, currentMetaState, false, now);
381 addMetaKeys(outEvents, deviceId, metaState, false, now, &currentMetaState);
382 }
383#if DEBUG_MAPPING
384 ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.",
385 deviceId, toString(chars, numChars).string(), int32_t(outEvents.size()));
386 for (size_t i = 0; i < outEvents.size(); i++) {
387 ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.",
388 outEvents[i].getKeyCode(), outEvents[i].getMetaState(),
389 outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up");
390 }
391#endif
392 return true;
393}
394
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000395void KeyCharacterMap::addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode) {
396 if (fromKeyCode == toKeyCode) {
397 mKeyRemapping.erase(fromKeyCode);
398#if DEBUG_MAPPING
399 ALOGD("addKeyRemapping: Cleared remapping forKeyCode=%d ~ Result Successful.", fromKeyCode);
400#endif
401 return;
402 }
403 mKeyRemapping.insert_or_assign(fromKeyCode, toKeyCode);
404#if DEBUG_MAPPING
405 ALOGD("addKeyRemapping: fromKeyCode=%d, toKeyCode=%d ~ Result Successful.", fromKeyCode,
406 toKeyCode);
407#endif
408}
409
Jeff Brown5912f952013-07-01 19:10:31 -0700410status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
411 if (usageCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000412 const auto it = mKeysByUsageCode.find(usageCode);
413 if (it != mKeysByUsageCode.end()) {
414 *outKeyCode = it->second;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700415#if DEBUG_MAPPING
416 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
417 scanCode, usageCode, *outKeyCode);
418#endif
Jeff Brown5912f952013-07-01 19:10:31 -0700419 return OK;
420 }
421 }
422 if (scanCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000423 const auto it = mKeysByScanCode.find(scanCode);
424 if (it != mKeysByScanCode.end()) {
425 *outKeyCode = it->second;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700426#if DEBUG_MAPPING
427 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
428 scanCode, usageCode, *outKeyCode);
429#endif
Jeff Brown5912f952013-07-01 19:10:31 -0700430 return OK;
431 }
432 }
433
434#if DEBUG_MAPPING
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700435 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700436#endif
437 *outKeyCode = AKEYCODE_UNKNOWN;
438 return NAME_NOT_FOUND;
439}
440
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000441int32_t KeyCharacterMap::applyKeyRemapping(int32_t fromKeyCode) const {
442 int32_t toKeyCode = fromKeyCode;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700443
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000444 const auto it = mKeyRemapping.find(fromKeyCode);
445 if (it != mKeyRemapping.end()) {
446 toKeyCode = it->second;
447 }
448#if DEBUG_MAPPING
449 ALOGD("applyKeyRemapping: keyCode=%d ~ replacement keyCode=%d.", fromKeyCode, toKeyCode);
450#endif
451 return toKeyCode;
452}
453
454std::pair<int32_t, int32_t> KeyCharacterMap::applyKeyBehavior(int32_t fromKeyCode,
455 int32_t fromMetaState) const {
456 int32_t toKeyCode = fromKeyCode;
457 int32_t toMetaState = fromMetaState;
458
459 const Behavior* behavior = getKeyBehavior(fromKeyCode, fromMetaState);
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700460 if (behavior != nullptr) {
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700461 if (behavior->replacementKeyCode) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000462 toKeyCode = behavior->replacementKeyCode;
463 toMetaState = fromMetaState & ~behavior->metaState;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700464 // Reset dependent meta states.
465 if (behavior->metaState & AMETA_ALT_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000466 toMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700467 }
468 if (behavior->metaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000469 toMetaState &= ~AMETA_ALT_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700470 }
471 if (behavior->metaState & AMETA_CTRL_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000472 toMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700473 }
474 if (behavior->metaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000475 toMetaState &= ~AMETA_CTRL_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700476 }
477 if (behavior->metaState & AMETA_SHIFT_ON) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000478 toMetaState &= ~(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700479 }
480 if (behavior->metaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000481 toMetaState &= ~AMETA_SHIFT_ON;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700482 }
483 // ... and put universal bits back if needed
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000484 toMetaState = normalizeMetaState(toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700485 }
486 }
487
488#if DEBUG_MAPPING
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000489 ALOGD("applyKeyBehavior: keyCode=%d, metaState=0x%08x ~ "
490 "replacement keyCode=%d, replacement metaState=0x%08x.",
491 fromKeyCode, fromMetaState, toKeyCode, toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700492#endif
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000493 return std::make_pair(toKeyCode, toMetaState);
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700494}
495
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700496const KeyCharacterMap::Key* KeyCharacterMap::getKey(int32_t keyCode) const {
Jeff Brown5912f952013-07-01 19:10:31 -0700497 ssize_t index = mKeys.indexOfKey(keyCode);
498 if (index >= 0) {
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700499 return mKeys.valueAt(index);
Jeff Brown5912f952013-07-01 19:10:31 -0700500 }
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700501 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700502}
503
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700504const KeyCharacterMap::Behavior* KeyCharacterMap::getKeyBehavior(int32_t keyCode,
505 int32_t metaState) const {
Siarhei Vishniakou0bae1a02023-04-17 09:00:59 -0700506 const Key* key = getKey(keyCode);
507 if (key != nullptr) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700508 for (const Behavior& behavior : key->behaviors) {
509 if (matchesMetaState(metaState, behavior.metaState)) {
510 return &behavior;
Jeff Brown5912f952013-07-01 19:10:31 -0700511 }
Jeff Brown5912f952013-07-01 19:10:31 -0700512 }
513 }
Siarhei Vishniakou12300c12022-08-05 12:30:36 -0700514 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700515}
516
517bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
518 // Behavior must have at least the set of meta states specified.
519 // And if the key event has CTRL, ALT or META then the behavior must exactly
520 // match those, taking into account that a behavior can specify that it handles
521 // one, both or either of a left/right modifier pair.
522 if ((eventMetaState & behaviorMetaState) == behaviorMetaState) {
523 const int32_t EXACT_META_STATES =
524 AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON
525 | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON
526 | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON;
527 int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES;
528 if (behaviorMetaState & AMETA_CTRL_ON) {
529 unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
530 } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
531 unmatchedMetaState &= ~AMETA_CTRL_ON;
532 }
533 if (behaviorMetaState & AMETA_ALT_ON) {
534 unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
535 } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
536 unmatchedMetaState &= ~AMETA_ALT_ON;
537 }
538 if (behaviorMetaState & AMETA_META_ON) {
539 unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
540 } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
541 unmatchedMetaState &= ~AMETA_META_ON;
542 }
543 return !unmatchedMetaState;
544 }
545 return false;
546}
547
548bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
549 if (!ch) {
550 return false;
551 }
552
553 for (size_t i = 0; i < mKeys.size(); i++) {
554 const Key* key = mKeys.valueAt(i);
555
556 // Try to find the most general behavior that maps to this character.
557 // For example, the base key behavior will usually be last in the list.
Yi Kong5bed83b2018-07-17 12:53:47 -0700558 const Behavior* found = nullptr;
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700559 for (const Behavior& behavior : key->behaviors) {
560 if (behavior.character == ch) {
561 found = &behavior;
Jeff Brown5912f952013-07-01 19:10:31 -0700562 }
563 }
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700564 if (found != nullptr) {
Jeff Brown5912f952013-07-01 19:10:31 -0700565 *outKeyCode = mKeys.keyAt(i);
566 *outMetaState = found->metaState;
567 return true;
568 }
569 }
570 return false;
571}
572
573void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents,
574 int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
575 outEvents.push();
576 KeyEvent& event = outEvents.editTop();
Garfield Tan4cc839f2020-01-24 11:26:14 -0800577 event.initialize(InputEvent::nextId(), deviceId, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
578 INVALID_HMAC, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 0, keyCode,
579 0, metaState, 0, time, time);
Jeff Brown5912f952013-07-01 19:10:31 -0700580}
581
582void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
583 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
584 int32_t* currentMetaState) {
585 // Add and remove meta keys symmetrically.
586 if (down) {
587 addLockedMetaKey(outEvents, deviceId, metaState, time,
588 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
589 addLockedMetaKey(outEvents, deviceId, metaState, time,
590 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
591 addLockedMetaKey(outEvents, deviceId, metaState, time,
592 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
593
594 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
595 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
596 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
597 AMETA_SHIFT_ON, currentMetaState);
598 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
599 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
600 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
601 AMETA_ALT_ON, currentMetaState);
602 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
603 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
604 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
605 AMETA_CTRL_ON, currentMetaState);
606 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
607 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
608 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
609 AMETA_META_ON, currentMetaState);
610
611 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
612 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
613 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
614 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
615 } else {
616 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
617 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
618 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
619 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
620
621 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
622 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
623 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
624 AMETA_META_ON, currentMetaState);
625 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
626 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
627 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
628 AMETA_CTRL_ON, currentMetaState);
629 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
630 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
631 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
632 AMETA_ALT_ON, currentMetaState);
633 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
634 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
635 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
636 AMETA_SHIFT_ON, currentMetaState);
637
638 addLockedMetaKey(outEvents, deviceId, metaState, time,
639 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
640 addLockedMetaKey(outEvents, deviceId, metaState, time,
641 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
642 addLockedMetaKey(outEvents, deviceId, metaState, time,
643 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
644 }
645}
646
647bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
648 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
649 int32_t keyCode, int32_t keyMetaState,
650 int32_t* currentMetaState) {
651 if ((metaState & keyMetaState) == keyMetaState) {
652 *currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
653 addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
654 return true;
655 }
656 return false;
657}
658
659void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
660 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
661 int32_t leftKeyCode, int32_t leftKeyMetaState,
662 int32_t rightKeyCode, int32_t rightKeyMetaState,
663 int32_t eitherKeyMetaState,
664 int32_t* currentMetaState) {
665 bool specific = false;
666 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
667 leftKeyCode, leftKeyMetaState, currentMetaState);
668 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
669 rightKeyCode, rightKeyMetaState, currentMetaState);
670
671 if (!specific) {
672 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
673 leftKeyCode, eitherKeyMetaState, currentMetaState);
674 }
675}
676
677void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
678 int32_t deviceId, int32_t metaState, nsecs_t time,
679 int32_t keyCode, int32_t keyMetaState,
680 int32_t* currentMetaState) {
681 if ((metaState & keyMetaState) == keyMetaState) {
682 *currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
683 addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
684 *currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
685 addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
686 }
687}
688
Brett Chabotfaa986c2020-11-04 17:39:36 -0800689#ifdef __linux__
Chris Ye3a1e4462020-08-12 10:13:15 -0700690std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
691 if (parcel == nullptr) {
692 ALOGE("%s: Null parcel", __func__);
693 return nullptr;
694 }
Philip Junker90bc9492021-12-10 18:39:42 +0100695 std::string loadFileName = parcel->readCString();
696 std::shared_ptr<KeyCharacterMap> map =
697 std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(loadFileName));
Michael Wright102936e2020-11-04 03:44:27 +0000698 map->mType = static_cast<KeyCharacterMap::KeyboardType>(parcel->readInt32());
Philip Junker90bc9492021-12-10 18:39:42 +0100699 map->mLayoutOverlayApplied = parcel->readBool();
Jeff Brown5912f952013-07-01 19:10:31 -0700700 size_t numKeys = parcel->readInt32();
701 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700702 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700703 }
Michael Wright4c971c02015-10-21 14:38:03 +0100704 if (numKeys > MAX_KEYS) {
Ian Pedowitzd57d9b92016-02-19 08:34:43 +0000705 ALOGE("Too many keys in KeyCharacterMap (%zu > %d)", numKeys, MAX_KEYS);
Yi Kong5bed83b2018-07-17 12:53:47 -0700706 return nullptr;
Michael Wright4c971c02015-10-21 14:38:03 +0100707 }
Jeff Brown5912f952013-07-01 19:10:31 -0700708
709 for (size_t i = 0; i < numKeys; i++) {
710 int32_t keyCode = parcel->readInt32();
711 char16_t label = parcel->readInt32();
712 char16_t number = parcel->readInt32();
713 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700714 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700715 }
716
717 Key* key = new Key();
718 key->label = label;
719 key->number = number;
720 map->mKeys.add(keyCode, key);
721
Jeff Brown5912f952013-07-01 19:10:31 -0700722 while (parcel->readInt32()) {
723 int32_t metaState = parcel->readInt32();
724 char16_t character = parcel->readInt32();
725 int32_t fallbackKeyCode = parcel->readInt32();
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700726 int32_t replacementKeyCode = parcel->readInt32();
Jeff Brown5912f952013-07-01 19:10:31 -0700727 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700728 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700729 }
730
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700731 key->behaviors.push_back({
732 .metaState = metaState,
733 .character = character,
734 .fallbackKeyCode = fallbackKeyCode,
735 .replacementKeyCode = replacementKeyCode,
736 });
Jeff Brown5912f952013-07-01 19:10:31 -0700737 }
738
739 if (parcel->errorCheck()) {
Yi Kong5bed83b2018-07-17 12:53:47 -0700740 return nullptr;
Jeff Brown5912f952013-07-01 19:10:31 -0700741 }
742 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000743 size_t numKeyRemapping = parcel->readInt32();
744 if (parcel->errorCheck()) {
745 return nullptr;
746 }
747 for (size_t i = 0; i < numKeyRemapping; i++) {
748 int32_t key = parcel->readInt32();
749 int32_t value = parcel->readInt32();
750 map->mKeyRemapping.insert_or_assign(key, value);
751 if (parcel->errorCheck()) {
752 return nullptr;
753 }
754 }
Philip Junker90bc9492021-12-10 18:39:42 +0100755 size_t numKeysByScanCode = parcel->readInt32();
756 if (parcel->errorCheck()) {
757 return nullptr;
758 }
759 for (size_t i = 0; i < numKeysByScanCode; i++) {
760 int32_t key = parcel->readInt32();
761 int32_t value = parcel->readInt32();
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000762 map->mKeysByScanCode.insert_or_assign(key, value);
Philip Junker90bc9492021-12-10 18:39:42 +0100763 if (parcel->errorCheck()) {
764 return nullptr;
765 }
766 }
767 size_t numKeysByUsageCode = parcel->readInt32();
768 if (parcel->errorCheck()) {
769 return nullptr;
770 }
771 for (size_t i = 0; i < numKeysByUsageCode; i++) {
772 int32_t key = parcel->readInt32();
773 int32_t value = parcel->readInt32();
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000774 map->mKeysByUsageCode.insert_or_assign(key, value);
Philip Junker90bc9492021-12-10 18:39:42 +0100775 if (parcel->errorCheck()) {
776 return nullptr;
777 }
778 }
Jeff Brown5912f952013-07-01 19:10:31 -0700779 return map;
780}
781
782void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
Chris Ye3a1e4462020-08-12 10:13:15 -0700783 if (parcel == nullptr) {
784 ALOGE("%s: Null parcel", __func__);
785 return;
786 }
Philip Junker90bc9492021-12-10 18:39:42 +0100787 parcel->writeCString(mLoadFileName.c_str());
Michael Wright102936e2020-11-04 03:44:27 +0000788 parcel->writeInt32(static_cast<int32_t>(mType));
Philip Junker90bc9492021-12-10 18:39:42 +0100789 parcel->writeBool(mLayoutOverlayApplied);
Jeff Brown5912f952013-07-01 19:10:31 -0700790
791 size_t numKeys = mKeys.size();
792 parcel->writeInt32(numKeys);
793 for (size_t i = 0; i < numKeys; i++) {
794 int32_t keyCode = mKeys.keyAt(i);
795 const Key* key = mKeys.valueAt(i);
796 parcel->writeInt32(keyCode);
797 parcel->writeInt32(key->label);
798 parcel->writeInt32(key->number);
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700799 for (const Behavior& behavior : key->behaviors) {
Jeff Brown5912f952013-07-01 19:10:31 -0700800 parcel->writeInt32(1);
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700801 parcel->writeInt32(behavior.metaState);
802 parcel->writeInt32(behavior.character);
803 parcel->writeInt32(behavior.fallbackKeyCode);
804 parcel->writeInt32(behavior.replacementKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -0700805 }
806 parcel->writeInt32(0);
807 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000808 size_t numKeyRemapping = mKeyRemapping.size();
809 parcel->writeInt32(numKeyRemapping);
810 for (auto const& [fromAndroidKeyCode, toAndroidKeyCode] : mKeyRemapping) {
811 parcel->writeInt32(fromAndroidKeyCode);
812 parcel->writeInt32(toAndroidKeyCode);
813 }
Philip Junker90bc9492021-12-10 18:39:42 +0100814 size_t numKeysByScanCode = mKeysByScanCode.size();
815 parcel->writeInt32(numKeysByScanCode);
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000816 for (auto const& [fromScanCode, toAndroidKeyCode] : mKeysByScanCode) {
817 parcel->writeInt32(fromScanCode);
818 parcel->writeInt32(toAndroidKeyCode);
Philip Junker90bc9492021-12-10 18:39:42 +0100819 }
820 size_t numKeysByUsageCode = mKeysByUsageCode.size();
821 parcel->writeInt32(numKeysByUsageCode);
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000822 for (auto const& [fromUsageCode, toAndroidKeyCode] : mKeysByUsageCode) {
823 parcel->writeInt32(fromUsageCode);
824 parcel->writeInt32(toAndroidKeyCode);
Philip Junker90bc9492021-12-10 18:39:42 +0100825 }
Jeff Brown5912f952013-07-01 19:10:31 -0700826}
Brett Chabotfaa986c2020-11-04 17:39:36 -0800827#endif // __linux__
Jeff Brown5912f952013-07-01 19:10:31 -0700828
829// --- KeyCharacterMap::Key ---
830
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700831KeyCharacterMap::Key::Key() : label(0), number(0) {}
Jeff Brown5912f952013-07-01 19:10:31 -0700832
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -0700833KeyCharacterMap::Key::Key(const Key& other)
834 : label(other.label), number(other.number), behaviors(other.behaviors) {}
Jeff Brown5912f952013-07-01 19:10:31 -0700835
836// --- KeyCharacterMap::Parser ---
837
838KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
839 mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
840}
841
842KeyCharacterMap::Parser::~Parser() {
843}
844
845status_t KeyCharacterMap::Parser::parse() {
846 while (!mTokenizer->isEof()) {
847#if DEBUG_PARSER
848 ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
849 mTokenizer->peekRemainderOfLine().string());
850#endif
851
852 mTokenizer->skipDelimiters(WHITESPACE);
853
854 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
855 switch (mState) {
856 case STATE_TOP: {
857 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
858 if (keywordToken == "type") {
859 mTokenizer->skipDelimiters(WHITESPACE);
860 status_t status = parseType();
861 if (status) return status;
862 } else if (keywordToken == "map") {
863 mTokenizer->skipDelimiters(WHITESPACE);
864 status_t status = parseMap();
865 if (status) return status;
866 } else if (keywordToken == "key") {
867 mTokenizer->skipDelimiters(WHITESPACE);
868 status_t status = parseKey();
869 if (status) return status;
870 } else {
871 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
872 keywordToken.string());
873 return BAD_VALUE;
874 }
875 break;
876 }
877
878 case STATE_KEY: {
879 status_t status = parseKeyProperty();
880 if (status) return status;
881 break;
882 }
883 }
884
885 mTokenizer->skipDelimiters(WHITESPACE);
886 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
887 ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
888 mTokenizer->getLocation().string(),
889 mTokenizer->peekRemainderOfLine().string());
890 return BAD_VALUE;
891 }
892 }
893
894 mTokenizer->nextLine();
895 }
896
897 if (mState != STATE_TOP) {
898 ALOGE("%s: Unterminated key description at end of file.",
899 mTokenizer->getLocation().string());
900 return BAD_VALUE;
901 }
902
Michael Wright102936e2020-11-04 03:44:27 +0000903 if (mMap->mType == KeyboardType::UNKNOWN) {
Jeff Brown5912f952013-07-01 19:10:31 -0700904 ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
905 mTokenizer->getLocation().string());
906 return BAD_VALUE;
907 }
908
Michael Wright102936e2020-11-04 03:44:27 +0000909 if (mFormat == Format::BASE) {
910 if (mMap->mType == KeyboardType::OVERLAY) {
Jeff Brown5912f952013-07-01 19:10:31 -0700911 ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
912 mTokenizer->getLocation().string());
913 return BAD_VALUE;
914 }
Michael Wright102936e2020-11-04 03:44:27 +0000915 } else if (mFormat == Format::OVERLAY) {
916 if (mMap->mType != KeyboardType::OVERLAY) {
Jeff Brown5912f952013-07-01 19:10:31 -0700917 ALOGE("%s: Overlay keyboard layout missing required keyboard "
918 "'type OVERLAY' declaration.",
919 mTokenizer->getLocation().string());
920 return BAD_VALUE;
921 }
922 }
923
924 return NO_ERROR;
925}
926
927status_t KeyCharacterMap::Parser::parseType() {
Michael Wright102936e2020-11-04 03:44:27 +0000928 if (mMap->mType != KeyboardType::UNKNOWN) {
Jeff Brown5912f952013-07-01 19:10:31 -0700929 ALOGE("%s: Duplicate keyboard 'type' declaration.",
930 mTokenizer->getLocation().string());
931 return BAD_VALUE;
932 }
933
934 KeyboardType type;
935 String8 typeToken = mTokenizer->nextToken(WHITESPACE);
936 if (typeToken == "NUMERIC") {
Michael Wright102936e2020-11-04 03:44:27 +0000937 type = KeyboardType::NUMERIC;
Jeff Brown5912f952013-07-01 19:10:31 -0700938 } else if (typeToken == "PREDICTIVE") {
Michael Wright102936e2020-11-04 03:44:27 +0000939 type = KeyboardType::PREDICTIVE;
Jeff Brown5912f952013-07-01 19:10:31 -0700940 } else if (typeToken == "ALPHA") {
Michael Wright102936e2020-11-04 03:44:27 +0000941 type = KeyboardType::ALPHA;
Jeff Brown5912f952013-07-01 19:10:31 -0700942 } else if (typeToken == "FULL") {
Michael Wright102936e2020-11-04 03:44:27 +0000943 type = KeyboardType::FULL;
Jeff Brown5912f952013-07-01 19:10:31 -0700944 } else if (typeToken == "SPECIAL_FUNCTION") {
Siarhei Vishniakou61da25a2018-02-15 21:04:49 -0600945 ALOGW("The SPECIAL_FUNCTION type is now declared in the device's IDC file, please set "
946 "the property 'keyboard.specialFunction' to '1' there instead.");
947 // TODO: return BAD_VALUE here in Q
Michael Wright102936e2020-11-04 03:44:27 +0000948 type = KeyboardType::SPECIAL_FUNCTION;
Jeff Brown5912f952013-07-01 19:10:31 -0700949 } else if (typeToken == "OVERLAY") {
Michael Wright102936e2020-11-04 03:44:27 +0000950 type = KeyboardType::OVERLAY;
Jeff Brown5912f952013-07-01 19:10:31 -0700951 } else {
952 ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(),
953 typeToken.string());
954 return BAD_VALUE;
955 }
956
957#if DEBUG_PARSER
958 ALOGD("Parsed type: type=%d.", type);
959#endif
960 mMap->mType = type;
961 return NO_ERROR;
962}
963
964status_t KeyCharacterMap::Parser::parseMap() {
965 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
966 if (keywordToken == "key") {
967 mTokenizer->skipDelimiters(WHITESPACE);
968 return parseMapKey();
969 }
970 ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(),
971 keywordToken.string());
972 return BAD_VALUE;
973}
974
975status_t KeyCharacterMap::Parser::parseMapKey() {
976 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
977 bool mapUsage = false;
978 if (codeToken == "usage") {
979 mapUsage = true;
980 mTokenizer->skipDelimiters(WHITESPACE);
981 codeToken = mTokenizer->nextToken(WHITESPACE);
982 }
983
984 char* end;
985 int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
986 if (*end) {
987 ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
988 mapUsage ? "usage" : "scan code", codeToken.string());
989 return BAD_VALUE;
990 }
Vaibhav Devmuraricbba14c2022-10-10 16:54:49 +0000991 std::map<int32_t, int32_t>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
992 const auto it = map.find(code);
993 if (it != map.end()) {
Jeff Brown5912f952013-07-01 19:10:31 -0700994 ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
995 mapUsage ? "usage" : "scan code", codeToken.string());
996 return BAD_VALUE;
997 }
998
999 mTokenizer->skipDelimiters(WHITESPACE);
1000 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001001 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -07001002 if (!keyCode) {
1003 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
1004 keyCodeToken.string());
1005 return BAD_VALUE;
1006 }
1007
1008#if DEBUG_PARSER
1009 ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
1010 mapUsage ? "usage" : "scan code", code, keyCode);
1011#endif
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001012 map.insert_or_assign(code, *keyCode);
Jeff Brown5912f952013-07-01 19:10:31 -07001013 return NO_ERROR;
1014}
1015
1016status_t KeyCharacterMap::Parser::parseKey() {
1017 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001018 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
Jeff Brown5912f952013-07-01 19:10:31 -07001019 if (!keyCode) {
1020 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
1021 keyCodeToken.string());
1022 return BAD_VALUE;
1023 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001024 if (mMap->mKeys.indexOfKey(*keyCode) >= 0) {
Jeff Brown5912f952013-07-01 19:10:31 -07001025 ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(),
1026 keyCodeToken.string());
1027 return BAD_VALUE;
1028 }
1029
1030 mTokenizer->skipDelimiters(WHITESPACE);
1031 String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
1032 if (openBraceToken != "{") {
1033 ALOGE("%s: Expected '{' after key code label, got '%s'.",
1034 mTokenizer->getLocation().string(), openBraceToken.string());
1035 return BAD_VALUE;
1036 }
1037
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001038 ALOGD_IF(DEBUG_PARSER, "Parsed beginning of key: keyCode=%d.", *keyCode);
1039 mKeyCode = *keyCode;
1040 mMap->mKeys.add(*keyCode, new Key());
Jeff Brown5912f952013-07-01 19:10:31 -07001041 mState = STATE_KEY;
1042 return NO_ERROR;
1043}
1044
1045status_t KeyCharacterMap::Parser::parseKeyProperty() {
1046 Key* key = mMap->mKeys.valueFor(mKeyCode);
1047 String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
1048 if (token == "}") {
1049 mState = STATE_TOP;
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001050 return finishKey(*key);
Jeff Brown5912f952013-07-01 19:10:31 -07001051 }
1052
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -07001053 std::vector<Property> properties;
Jeff Brown5912f952013-07-01 19:10:31 -07001054
1055 // Parse all comma-delimited property names up to the first colon.
1056 for (;;) {
1057 if (token == "label") {
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -07001058 properties.emplace_back(PROPERTY_LABEL);
Jeff Brown5912f952013-07-01 19:10:31 -07001059 } else if (token == "number") {
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -07001060 properties.emplace_back(PROPERTY_NUMBER);
Jeff Brown5912f952013-07-01 19:10:31 -07001061 } else {
1062 int32_t metaState;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001063 status_t status = parseModifier(token.string(), &metaState);
Jeff Brown5912f952013-07-01 19:10:31 -07001064 if (status) {
1065 ALOGE("%s: Expected a property name or modifier, got '%s'.",
1066 mTokenizer->getLocation().string(), token.string());
1067 return status;
1068 }
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -07001069 properties.emplace_back(PROPERTY_META, metaState);
Jeff Brown5912f952013-07-01 19:10:31 -07001070 }
1071
1072 mTokenizer->skipDelimiters(WHITESPACE);
1073 if (!mTokenizer->isEol()) {
1074 char ch = mTokenizer->nextChar();
1075 if (ch == ':') {
1076 break;
1077 } else if (ch == ',') {
1078 mTokenizer->skipDelimiters(WHITESPACE);
1079 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
1080 continue;
1081 }
1082 }
1083
1084 ALOGE("%s: Expected ',' or ':' after property name.",
1085 mTokenizer->getLocation().string());
1086 return BAD_VALUE;
1087 }
1088
1089 // Parse behavior after the colon.
1090 mTokenizer->skipDelimiters(WHITESPACE);
1091
1092 Behavior behavior;
1093 bool haveCharacter = false;
1094 bool haveFallback = false;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001095 bool haveReplacement = false;
Jeff Brown5912f952013-07-01 19:10:31 -07001096
1097 do {
1098 char ch = mTokenizer->peekChar();
1099 if (ch == '\'') {
1100 char16_t character;
1101 status_t status = parseCharacterLiteral(&character);
1102 if (status || !character) {
1103 ALOGE("%s: Invalid character literal for key.",
1104 mTokenizer->getLocation().string());
1105 return BAD_VALUE;
1106 }
1107 if (haveCharacter) {
1108 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
1109 mTokenizer->getLocation().string());
1110 return BAD_VALUE;
1111 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001112 if (haveReplacement) {
1113 ALOGE("%s: Cannot combine character literal with replace action.",
1114 mTokenizer->getLocation().string());
1115 return BAD_VALUE;
1116 }
Jeff Brown5912f952013-07-01 19:10:31 -07001117 behavior.character = character;
1118 haveCharacter = true;
1119 } else {
1120 token = mTokenizer->nextToken(WHITESPACE);
1121 if (token == "none") {
1122 if (haveCharacter) {
1123 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
1124 mTokenizer->getLocation().string());
1125 return BAD_VALUE;
1126 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001127 if (haveReplacement) {
1128 ALOGE("%s: Cannot combine 'none' with replace action.",
1129 mTokenizer->getLocation().string());
1130 return BAD_VALUE;
1131 }
Jeff Brown5912f952013-07-01 19:10:31 -07001132 haveCharacter = true;
1133 } else if (token == "fallback") {
1134 mTokenizer->skipDelimiters(WHITESPACE);
1135 token = mTokenizer->nextToken(WHITESPACE);
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001136 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(token.string());
Jeff Brown5912f952013-07-01 19:10:31 -07001137 if (!keyCode) {
1138 ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
1139 mTokenizer->getLocation().string(),
1140 token.string());
1141 return BAD_VALUE;
1142 }
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001143 if (haveFallback || haveReplacement) {
1144 ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
Jeff Brown5912f952013-07-01 19:10:31 -07001145 mTokenizer->getLocation().string());
1146 return BAD_VALUE;
1147 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001148 behavior.fallbackKeyCode = *keyCode;
Jeff Brown5912f952013-07-01 19:10:31 -07001149 haveFallback = true;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001150 } else if (token == "replace") {
1151 mTokenizer->skipDelimiters(WHITESPACE);
1152 token = mTokenizer->nextToken(WHITESPACE);
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001153 std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(token.string());
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001154 if (!keyCode) {
1155 ALOGE("%s: Invalid key code label for replace, got '%s'.",
1156 mTokenizer->getLocation().string(),
1157 token.string());
1158 return BAD_VALUE;
1159 }
1160 if (haveCharacter) {
1161 ALOGE("%s: Cannot combine character literal with replace action.",
1162 mTokenizer->getLocation().string());
1163 return BAD_VALUE;
1164 }
1165 if (haveFallback || haveReplacement) {
1166 ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
1167 mTokenizer->getLocation().string());
1168 return BAD_VALUE;
1169 }
Siarhei Vishniakou5df34932023-01-23 12:41:01 -08001170 behavior.replacementKeyCode = *keyCode;
Dmitry Torokhov115f93e2015-09-17 18:04:50 -07001171 haveReplacement = true;
1172
Jeff Brown5912f952013-07-01 19:10:31 -07001173 } else {
1174 ALOGE("%s: Expected a key behavior after ':'.",
1175 mTokenizer->getLocation().string());
1176 return BAD_VALUE;
1177 }
1178 }
1179
1180 mTokenizer->skipDelimiters(WHITESPACE);
1181 } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#');
1182
1183 // Add the behavior.
Siarhei Vishniakouedcd0422023-04-17 16:11:22 -07001184 for (const Property& property : properties) {
Jeff Brown5912f952013-07-01 19:10:31 -07001185 switch (property.property) {
1186 case PROPERTY_LABEL:
1187 if (key->label) {
1188 ALOGE("%s: Duplicate label for key.",
1189 mTokenizer->getLocation().string());
1190 return BAD_VALUE;
1191 }
1192 key->label = behavior.character;
1193#if DEBUG_PARSER
1194 ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label);
1195#endif
1196 break;
1197 case PROPERTY_NUMBER:
1198 if (key->number) {
1199 ALOGE("%s: Duplicate number for key.",
1200 mTokenizer->getLocation().string());
1201 return BAD_VALUE;
1202 }
1203 key->number = behavior.character;
1204#if DEBUG_PARSER
1205 ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number);
1206#endif
1207 break;
1208 case PROPERTY_META: {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001209 for (const Behavior& b : key->behaviors) {
1210 if (b.metaState == property.metaState) {
Jeff Brown5912f952013-07-01 19:10:31 -07001211 ALOGE("%s: Duplicate key behavior for modifier.",
1212 mTokenizer->getLocation().string());
1213 return BAD_VALUE;
1214 }
1215 }
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001216 Behavior newBehavior = behavior;
1217 newBehavior.metaState = property.metaState;
1218 key->behaviors.push_front(newBehavior);
1219 ALOGD_IF(DEBUG_PARSER,
1220 "Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
1221 mKeyCode, key->behaviors.front().metaState, key->behaviors.front().character,
1222 key->behaviors.front().fallbackKeyCode,
1223 key->behaviors.front().replacementKeyCode);
Jeff Brown5912f952013-07-01 19:10:31 -07001224 break;
1225 }
1226 }
1227 }
1228 return NO_ERROR;
1229}
1230
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001231status_t KeyCharacterMap::Parser::finishKey(Key& key) {
Jeff Brown5912f952013-07-01 19:10:31 -07001232 // Fill in default number property.
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001233 if (!key.number) {
Jeff Brown5912f952013-07-01 19:10:31 -07001234 char16_t digit = 0;
1235 char16_t symbol = 0;
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001236 for (const Behavior& b : key.behaviors) {
Siarhei Vishniakouaa9e9d22022-08-05 11:13:31 -07001237 char16_t ch = b.character;
Jeff Brown5912f952013-07-01 19:10:31 -07001238 if (ch) {
1239 if (ch >= '0' && ch <= '9') {
1240 digit = ch;
1241 } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
1242 || ch == '-' || ch == '+' || ch == ',' || ch == '.'
1243 || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
1244 symbol = ch;
1245 }
1246 }
1247 }
Siarhei Vishniakou5af28342023-04-17 08:45:31 -07001248 key.number = digit ? digit : symbol;
Jeff Brown5912f952013-07-01 19:10:31 -07001249 }
1250 return NO_ERROR;
1251}
1252
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001253status_t KeyCharacterMap::Parser::parseModifier(const std::string& token, int32_t* outMetaState) {
Jeff Brown5912f952013-07-01 19:10:31 -07001254 if (token == "base") {
1255 *outMetaState = 0;
1256 return NO_ERROR;
1257 }
1258
1259 int32_t combinedMeta = 0;
1260
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001261 const char* str = token.c_str();
Jeff Brown5912f952013-07-01 19:10:31 -07001262 const char* start = str;
1263 for (const char* cur = str; ; cur++) {
1264 char ch = *cur;
1265 if (ch == '+' || ch == '\0') {
1266 size_t len = cur - start;
1267 int32_t metaState = 0;
1268 for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
1269 if (strlen(modifiers[i].label) == len
1270 && strncmp(modifiers[i].label, start, len) == 0) {
1271 metaState = modifiers[i].metaState;
1272 break;
1273 }
1274 }
1275 if (!metaState) {
1276 return BAD_VALUE;
1277 }
1278 if (combinedMeta & metaState) {
1279 ALOGE("%s: Duplicate modifier combination '%s'.",
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +01001280 mTokenizer->getLocation().string(), token.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -07001281 return BAD_VALUE;
1282 }
1283
1284 combinedMeta |= metaState;
1285 start = cur + 1;
1286
1287 if (ch == '\0') {
1288 break;
1289 }
1290 }
1291 }
1292 *outMetaState = combinedMeta;
1293 return NO_ERROR;
1294}
1295
1296status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
1297 char ch = mTokenizer->nextChar();
1298 if (ch != '\'') {
1299 goto Error;
1300 }
1301
1302 ch = mTokenizer->nextChar();
1303 if (ch == '\\') {
1304 // Escape sequence.
1305 ch = mTokenizer->nextChar();
1306 if (ch == 'n') {
1307 *outCharacter = '\n';
1308 } else if (ch == 't') {
1309 *outCharacter = '\t';
1310 } else if (ch == '\\') {
1311 *outCharacter = '\\';
1312 } else if (ch == '\'') {
1313 *outCharacter = '\'';
1314 } else if (ch == '"') {
1315 *outCharacter = '"';
1316 } else if (ch == 'u') {
1317 *outCharacter = 0;
1318 for (int i = 0; i < 4; i++) {
1319 ch = mTokenizer->nextChar();
1320 int digit;
1321 if (ch >= '0' && ch <= '9') {
1322 digit = ch - '0';
1323 } else if (ch >= 'A' && ch <= 'F') {
1324 digit = ch - 'A' + 10;
1325 } else if (ch >= 'a' && ch <= 'f') {
1326 digit = ch - 'a' + 10;
1327 } else {
1328 goto Error;
1329 }
1330 *outCharacter = (*outCharacter << 4) | digit;
1331 }
1332 } else {
1333 goto Error;
1334 }
1335 } else if (ch >= 32 && ch <= 126 && ch != '\'') {
1336 // ASCII literal character.
1337 *outCharacter = ch;
1338 } else {
1339 goto Error;
1340 }
1341
1342 ch = mTokenizer->nextChar();
1343 if (ch != '\'') {
1344 goto Error;
1345 }
1346
1347 // Ensure that we consumed the entire token.
1348 if (mTokenizer->nextToken(WHITESPACE).isEmpty()) {
1349 return NO_ERROR;
1350 }
1351
1352Error:
1353 ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string());
1354 return BAD_VALUE;
1355}
1356
1357} // namespace android