1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/gonk/libui/KeyCharacterMap.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1153 @@ 1.4 +/* 1.5 + * Copyright (C) 2008 The Android Open Source Project 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * Unless required by applicable law or agreed to in writing, software 1.14 + * distributed under the License is distributed on an "AS IS" BASIS, 1.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.16 + * See the License for the specific language governing permissions and 1.17 + * limitations under the License. 1.18 + */ 1.19 + 1.20 +#define LOG_TAG "KeyCharacterMap" 1.21 +#include "cutils_log.h" 1.22 + 1.23 +#include <stdlib.h> 1.24 +#include <string.h> 1.25 +#include "android_keycodes.h" 1.26 +#include "Keyboard.h" 1.27 +#include "KeyCharacterMap.h" 1.28 + 1.29 +#if HAVE_ANDROID_OS 1.30 +#include <binder/Parcel.h> 1.31 +#endif 1.32 + 1.33 +#include <utils/Errors.h> 1.34 +#include "Tokenizer.h" 1.35 +#include <utils/Timers.h> 1.36 + 1.37 +// Enables debug output for the parser. 1.38 +#define DEBUG_PARSER 0 1.39 + 1.40 +// Enables debug output for parser performance. 1.41 +#define DEBUG_PARSER_PERFORMANCE 0 1.42 + 1.43 +// Enables debug output for mapping. 1.44 +#define DEBUG_MAPPING 0 1.45 + 1.46 + 1.47 +namespace android { 1.48 + 1.49 +static const char* WHITESPACE = " \t\r"; 1.50 +static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:"; 1.51 + 1.52 +struct Modifier { 1.53 + const char* label; 1.54 + int32_t metaState; 1.55 +}; 1.56 +static const Modifier modifiers[] = { 1.57 + { "shift", AMETA_SHIFT_ON }, 1.58 + { "lshift", AMETA_SHIFT_LEFT_ON }, 1.59 + { "rshift", AMETA_SHIFT_RIGHT_ON }, 1.60 + { "alt", AMETA_ALT_ON }, 1.61 + { "lalt", AMETA_ALT_LEFT_ON }, 1.62 + { "ralt", AMETA_ALT_RIGHT_ON }, 1.63 + { "ctrl", AMETA_CTRL_ON }, 1.64 + { "lctrl", AMETA_CTRL_LEFT_ON }, 1.65 + { "rctrl", AMETA_CTRL_RIGHT_ON }, 1.66 + { "meta", AMETA_META_ON }, 1.67 + { "lmeta", AMETA_META_LEFT_ON }, 1.68 + { "rmeta", AMETA_META_RIGHT_ON }, 1.69 + { "sym", AMETA_SYM_ON }, 1.70 + { "fn", AMETA_FUNCTION_ON }, 1.71 + { "capslock", AMETA_CAPS_LOCK_ON }, 1.72 + { "numlock", AMETA_NUM_LOCK_ON }, 1.73 + { "scrolllock", AMETA_SCROLL_LOCK_ON }, 1.74 +}; 1.75 + 1.76 +#if DEBUG_MAPPING 1.77 +static String8 toString(const char16_t* chars, size_t numChars) { 1.78 + String8 result; 1.79 + for (size_t i = 0; i < numChars; i++) { 1.80 + result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]); 1.81 + } 1.82 + return result; 1.83 +} 1.84 +#endif 1.85 + 1.86 + 1.87 +// --- KeyCharacterMap --- 1.88 + 1.89 +sp<KeyCharacterMap> KeyCharacterMap::sEmpty = new KeyCharacterMap(); 1.90 + 1.91 +KeyCharacterMap::KeyCharacterMap() : 1.92 + mType(KEYBOARD_TYPE_UNKNOWN) { 1.93 +} 1.94 + 1.95 +KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) : 1.96 + RefBase(), mType(other.mType), mKeysByScanCode(other.mKeysByScanCode), 1.97 + mKeysByUsageCode(other.mKeysByUsageCode) { 1.98 + for (size_t i = 0; i < other.mKeys.size(); i++) { 1.99 + mKeys.add(other.mKeys.keyAt(i), new Key(*other.mKeys.valueAt(i))); 1.100 + } 1.101 +} 1.102 + 1.103 +KeyCharacterMap::~KeyCharacterMap() { 1.104 + for (size_t i = 0; i < mKeys.size(); i++) { 1.105 + Key* key = mKeys.editValueAt(i); 1.106 + delete key; 1.107 + } 1.108 +} 1.109 + 1.110 +status_t KeyCharacterMap::load(const String8& filename, 1.111 + Format format, sp<KeyCharacterMap>* outMap) { 1.112 + outMap->clear(); 1.113 + 1.114 + Tokenizer* tokenizer; 1.115 + status_t status = Tokenizer::open(filename, &tokenizer); 1.116 + if (status) { 1.117 + ALOGE("Error %d opening key character map file %s.", status, filename.string()); 1.118 + } else { 1.119 + status = load(tokenizer, format, outMap); 1.120 + delete tokenizer; 1.121 + } 1.122 + return status; 1.123 +} 1.124 + 1.125 +status_t KeyCharacterMap::loadContents(const String8& filename, const char* contents, 1.126 + Format format, sp<KeyCharacterMap>* outMap) { 1.127 + outMap->clear(); 1.128 + 1.129 + Tokenizer* tokenizer; 1.130 + status_t status = Tokenizer::fromContents(filename, contents, &tokenizer); 1.131 + if (status) { 1.132 + ALOGE("Error %d opening key character map.", status); 1.133 + } else { 1.134 + status = load(tokenizer, format, outMap); 1.135 + delete tokenizer; 1.136 + } 1.137 + return status; 1.138 +} 1.139 + 1.140 +status_t KeyCharacterMap::load(Tokenizer* tokenizer, 1.141 + Format format, sp<KeyCharacterMap>* outMap) { 1.142 + status_t status = OK; 1.143 + sp<KeyCharacterMap> map = new KeyCharacterMap(); 1.144 + if (!map.get()) { 1.145 + ALOGE("Error allocating key character map."); 1.146 + status = NO_MEMORY; 1.147 + } else { 1.148 +#if DEBUG_PARSER_PERFORMANCE 1.149 + nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); 1.150 +#endif 1.151 + Parser parser(map.get(), tokenizer, format); 1.152 + status = parser.parse(); 1.153 +#if DEBUG_PARSER_PERFORMANCE 1.154 + nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; 1.155 + ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.", 1.156 + tokenizer->getFilename().string(), tokenizer->getLineNumber(), 1.157 + elapsedTime / 1000000.0); 1.158 +#endif 1.159 + if (!status) { 1.160 + *outMap = map; 1.161 + } 1.162 + } 1.163 + return status; 1.164 +} 1.165 + 1.166 +sp<KeyCharacterMap> KeyCharacterMap::combine(const sp<KeyCharacterMap>& base, 1.167 + const sp<KeyCharacterMap>& overlay) { 1.168 + if (overlay == NULL) { 1.169 + return base; 1.170 + } 1.171 + if (base == NULL) { 1.172 + return overlay; 1.173 + } 1.174 + 1.175 + sp<KeyCharacterMap> map = new KeyCharacterMap(*base.get()); 1.176 + for (size_t i = 0; i < overlay->mKeys.size(); i++) { 1.177 + int32_t keyCode = overlay->mKeys.keyAt(i); 1.178 + Key* key = overlay->mKeys.valueAt(i); 1.179 + ssize_t oldIndex = map->mKeys.indexOfKey(keyCode); 1.180 + if (oldIndex >= 0) { 1.181 + delete map->mKeys.valueAt(oldIndex); 1.182 + map->mKeys.editValueAt(oldIndex) = new Key(*key); 1.183 + } else { 1.184 + map->mKeys.add(keyCode, new Key(*key)); 1.185 + } 1.186 + } 1.187 + 1.188 + for (size_t i = 0; i < overlay->mKeysByScanCode.size(); i++) { 1.189 + map->mKeysByScanCode.replaceValueFor(overlay->mKeysByScanCode.keyAt(i), 1.190 + overlay->mKeysByScanCode.valueAt(i)); 1.191 + } 1.192 + 1.193 + for (size_t i = 0; i < overlay->mKeysByUsageCode.size(); i++) { 1.194 + map->mKeysByUsageCode.replaceValueFor(overlay->mKeysByUsageCode.keyAt(i), 1.195 + overlay->mKeysByUsageCode.valueAt(i)); 1.196 + } 1.197 + return map; 1.198 +} 1.199 + 1.200 +sp<KeyCharacterMap> KeyCharacterMap::empty() { 1.201 + return sEmpty; 1.202 +} 1.203 + 1.204 +int32_t KeyCharacterMap::getKeyboardType() const { 1.205 + return mType; 1.206 +} 1.207 + 1.208 +char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const { 1.209 + char16_t result = 0; 1.210 + const Key* key; 1.211 + if (getKey(keyCode, &key)) { 1.212 + result = key->label; 1.213 + } 1.214 +#if DEBUG_MAPPING 1.215 + ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result); 1.216 +#endif 1.217 + return result; 1.218 +} 1.219 + 1.220 +char16_t KeyCharacterMap::getNumber(int32_t keyCode) const { 1.221 + char16_t result = 0; 1.222 + const Key* key; 1.223 + if (getKey(keyCode, &key)) { 1.224 + result = key->number; 1.225 + } 1.226 +#if DEBUG_MAPPING 1.227 + ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result); 1.228 +#endif 1.229 + return result; 1.230 +} 1.231 + 1.232 +char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const { 1.233 + char16_t result = 0; 1.234 + const Key* key; 1.235 + const Behavior* behavior; 1.236 + if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { 1.237 + result = behavior->character; 1.238 + } 1.239 +#if DEBUG_MAPPING 1.240 + ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result); 1.241 +#endif 1.242 + return result; 1.243 +} 1.244 + 1.245 +bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState, 1.246 + FallbackAction* outFallbackAction) const { 1.247 + outFallbackAction->keyCode = 0; 1.248 + outFallbackAction->metaState = 0; 1.249 + 1.250 + bool result = false; 1.251 + const Key* key; 1.252 + const Behavior* behavior; 1.253 + if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { 1.254 + if (behavior->fallbackKeyCode) { 1.255 + outFallbackAction->keyCode = behavior->fallbackKeyCode; 1.256 + outFallbackAction->metaState = metaState & ~behavior->metaState; 1.257 + result = true; 1.258 + } 1.259 + } 1.260 +#if DEBUG_MAPPING 1.261 + ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, " 1.262 + "fallback keyCode=%d, fallback metaState=0x%08x.", 1.263 + keyCode, metaState, result ? "true" : "false", 1.264 + outFallbackAction->keyCode, outFallbackAction->metaState); 1.265 +#endif 1.266 + return result; 1.267 +} 1.268 + 1.269 +char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars, 1.270 + int32_t metaState) const { 1.271 + char16_t result = 0; 1.272 + const Key* key; 1.273 + if (getKey(keyCode, &key)) { 1.274 + // Try to find the most general behavior that maps to this character. 1.275 + // For example, the base key behavior will usually be last in the list. 1.276 + // However, if we find a perfect meta state match for one behavior then use that one. 1.277 + for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { 1.278 + if (behavior->character) { 1.279 + for (size_t i = 0; i < numChars; i++) { 1.280 + if (behavior->character == chars[i]) { 1.281 + result = behavior->character; 1.282 + if ((behavior->metaState & metaState) == behavior->metaState) { 1.283 + goto ExactMatch; 1.284 + } 1.285 + break; 1.286 + } 1.287 + } 1.288 + } 1.289 + } 1.290 + ExactMatch: ; 1.291 + } 1.292 +#if DEBUG_MAPPING 1.293 + ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.", 1.294 + keyCode, toString(chars, numChars).string(), metaState, result); 1.295 +#endif 1.296 + return result; 1.297 +} 1.298 + 1.299 +bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars, 1.300 + Vector<KeyEvent>& outEvents) const { 1.301 + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); 1.302 + 1.303 + for (size_t i = 0; i < numChars; i++) { 1.304 + int32_t keyCode, metaState; 1.305 + char16_t ch = chars[i]; 1.306 + if (!findKey(ch, &keyCode, &metaState)) { 1.307 +#if DEBUG_MAPPING 1.308 + ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.", 1.309 + deviceId, toString(chars, numChars).string(), ch); 1.310 +#endif 1.311 + return false; 1.312 + } 1.313 + 1.314 + int32_t currentMetaState = 0; 1.315 + addMetaKeys(outEvents, deviceId, metaState, true, now, ¤tMetaState); 1.316 + addKey(outEvents, deviceId, keyCode, currentMetaState, true, now); 1.317 + addKey(outEvents, deviceId, keyCode, currentMetaState, false, now); 1.318 + addMetaKeys(outEvents, deviceId, metaState, false, now, ¤tMetaState); 1.319 + } 1.320 +#if DEBUG_MAPPING 1.321 + ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", 1.322 + deviceId, toString(chars, numChars).string(), int32_t(outEvents.size())); 1.323 + for (size_t i = 0; i < outEvents.size(); i++) { 1.324 + ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.", 1.325 + outEvents[i].getKeyCode(), outEvents[i].getMetaState(), 1.326 + outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up"); 1.327 + } 1.328 +#endif 1.329 + return true; 1.330 +} 1.331 + 1.332 +status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const { 1.333 + if (usageCode) { 1.334 + ssize_t index = mKeysByUsageCode.indexOfKey(usageCode); 1.335 + if (index >= 0) { 1.336 +#if DEBUG_MAPPING 1.337 + ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.", 1.338 + scanCode, usageCode, *outKeyCode); 1.339 +#endif 1.340 + *outKeyCode = mKeysByUsageCode.valueAt(index); 1.341 + return OK; 1.342 + } 1.343 + } 1.344 + if (scanCode) { 1.345 + ssize_t index = mKeysByScanCode.indexOfKey(scanCode); 1.346 + if (index >= 0) { 1.347 +#if DEBUG_MAPPING 1.348 + ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.", 1.349 + scanCode, usageCode, *outKeyCode); 1.350 +#endif 1.351 + *outKeyCode = mKeysByScanCode.valueAt(index); 1.352 + return OK; 1.353 + } 1.354 + } 1.355 + 1.356 +#if DEBUG_MAPPING 1.357 + ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode); 1.358 +#endif 1.359 + *outKeyCode = AKEYCODE_UNKNOWN; 1.360 + return NAME_NOT_FOUND; 1.361 +} 1.362 + 1.363 +bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const { 1.364 + ssize_t index = mKeys.indexOfKey(keyCode); 1.365 + if (index >= 0) { 1.366 + *outKey = mKeys.valueAt(index); 1.367 + return true; 1.368 + } 1.369 + return false; 1.370 +} 1.371 + 1.372 +bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState, 1.373 + const Key** outKey, const Behavior** outBehavior) const { 1.374 + const Key* key; 1.375 + if (getKey(keyCode, &key)) { 1.376 + const Behavior* behavior = key->firstBehavior; 1.377 + while (behavior) { 1.378 + if (matchesMetaState(metaState, behavior->metaState)) { 1.379 + *outKey = key; 1.380 + *outBehavior = behavior; 1.381 + return true; 1.382 + } 1.383 + behavior = behavior->next; 1.384 + } 1.385 + } 1.386 + return false; 1.387 +} 1.388 + 1.389 +bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) { 1.390 + // Behavior must have at least the set of meta states specified. 1.391 + // And if the key event has CTRL, ALT or META then the behavior must exactly 1.392 + // match those, taking into account that a behavior can specify that it handles 1.393 + // one, both or either of a left/right modifier pair. 1.394 + if ((eventMetaState & behaviorMetaState) == behaviorMetaState) { 1.395 + const int32_t EXACT_META_STATES = 1.396 + AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON 1.397 + | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON 1.398 + | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON; 1.399 + int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES; 1.400 + if (behaviorMetaState & AMETA_CTRL_ON) { 1.401 + unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON); 1.402 + } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) { 1.403 + unmatchedMetaState &= ~AMETA_CTRL_ON; 1.404 + } 1.405 + if (behaviorMetaState & AMETA_ALT_ON) { 1.406 + unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON); 1.407 + } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) { 1.408 + unmatchedMetaState &= ~AMETA_ALT_ON; 1.409 + } 1.410 + if (behaviorMetaState & AMETA_META_ON) { 1.411 + unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON); 1.412 + } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) { 1.413 + unmatchedMetaState &= ~AMETA_META_ON; 1.414 + } 1.415 + return !unmatchedMetaState; 1.416 + } 1.417 + return false; 1.418 +} 1.419 + 1.420 +bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const { 1.421 + if (!ch) { 1.422 + return false; 1.423 + } 1.424 + 1.425 + for (size_t i = 0; i < mKeys.size(); i++) { 1.426 + const Key* key = mKeys.valueAt(i); 1.427 + 1.428 + // Try to find the most general behavior that maps to this character. 1.429 + // For example, the base key behavior will usually be last in the list. 1.430 + const Behavior* found = NULL; 1.431 + for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { 1.432 + if (behavior->character == ch) { 1.433 + found = behavior; 1.434 + } 1.435 + } 1.436 + if (found) { 1.437 + *outKeyCode = mKeys.keyAt(i); 1.438 + *outMetaState = found->metaState; 1.439 + return true; 1.440 + } 1.441 + } 1.442 + return false; 1.443 +} 1.444 + 1.445 +void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents, 1.446 + int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) { 1.447 + outEvents.push(); 1.448 + KeyEvent& event = outEvents.editTop(); 1.449 + event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD, 1.450 + down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 1.451 + 0, keyCode, 0, metaState, 0, time, time); 1.452 +} 1.453 + 1.454 +void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents, 1.455 + int32_t deviceId, int32_t metaState, bool down, nsecs_t time, 1.456 + int32_t* currentMetaState) { 1.457 + // Add and remove meta keys symmetrically. 1.458 + if (down) { 1.459 + addLockedMetaKey(outEvents, deviceId, metaState, time, 1.460 + AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState); 1.461 + addLockedMetaKey(outEvents, deviceId, metaState, time, 1.462 + AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState); 1.463 + addLockedMetaKey(outEvents, deviceId, metaState, time, 1.464 + AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState); 1.465 + 1.466 + addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, 1.467 + AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON, 1.468 + AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON, 1.469 + AMETA_SHIFT_ON, currentMetaState); 1.470 + addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, 1.471 + AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON, 1.472 + AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON, 1.473 + AMETA_ALT_ON, currentMetaState); 1.474 + addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, 1.475 + AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON, 1.476 + AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON, 1.477 + AMETA_CTRL_ON, currentMetaState); 1.478 + addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, 1.479 + AKEYCODE_META_LEFT, AMETA_META_LEFT_ON, 1.480 + AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON, 1.481 + AMETA_META_ON, currentMetaState); 1.482 + 1.483 + addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, 1.484 + AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState); 1.485 + addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, 1.486 + AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState); 1.487 + } else { 1.488 + addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, 1.489 + AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState); 1.490 + addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, 1.491 + AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState); 1.492 + 1.493 + addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, 1.494 + AKEYCODE_META_LEFT, AMETA_META_LEFT_ON, 1.495 + AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON, 1.496 + AMETA_META_ON, currentMetaState); 1.497 + addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, 1.498 + AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON, 1.499 + AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON, 1.500 + AMETA_CTRL_ON, currentMetaState); 1.501 + addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, 1.502 + AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON, 1.503 + AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON, 1.504 + AMETA_ALT_ON, currentMetaState); 1.505 + addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, 1.506 + AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON, 1.507 + AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON, 1.508 + AMETA_SHIFT_ON, currentMetaState); 1.509 + 1.510 + addLockedMetaKey(outEvents, deviceId, metaState, time, 1.511 + AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState); 1.512 + addLockedMetaKey(outEvents, deviceId, metaState, time, 1.513 + AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState); 1.514 + addLockedMetaKey(outEvents, deviceId, metaState, time, 1.515 + AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState); 1.516 + } 1.517 +} 1.518 + 1.519 +bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents, 1.520 + int32_t deviceId, int32_t metaState, bool down, nsecs_t time, 1.521 + int32_t keyCode, int32_t keyMetaState, 1.522 + int32_t* currentMetaState) { 1.523 + if ((metaState & keyMetaState) == keyMetaState) { 1.524 + *currentMetaState = updateMetaState(keyCode, down, *currentMetaState); 1.525 + addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time); 1.526 + return true; 1.527 + } 1.528 + return false; 1.529 +} 1.530 + 1.531 +void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents, 1.532 + int32_t deviceId, int32_t metaState, bool down, nsecs_t time, 1.533 + int32_t leftKeyCode, int32_t leftKeyMetaState, 1.534 + int32_t rightKeyCode, int32_t rightKeyMetaState, 1.535 + int32_t eitherKeyMetaState, 1.536 + int32_t* currentMetaState) { 1.537 + bool specific = false; 1.538 + specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, 1.539 + leftKeyCode, leftKeyMetaState, currentMetaState); 1.540 + specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, 1.541 + rightKeyCode, rightKeyMetaState, currentMetaState); 1.542 + 1.543 + if (!specific) { 1.544 + addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, 1.545 + leftKeyCode, eitherKeyMetaState, currentMetaState); 1.546 + } 1.547 +} 1.548 + 1.549 +void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents, 1.550 + int32_t deviceId, int32_t metaState, nsecs_t time, 1.551 + int32_t keyCode, int32_t keyMetaState, 1.552 + int32_t* currentMetaState) { 1.553 + if ((metaState & keyMetaState) == keyMetaState) { 1.554 + *currentMetaState = updateMetaState(keyCode, true, *currentMetaState); 1.555 + addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time); 1.556 + *currentMetaState = updateMetaState(keyCode, false, *currentMetaState); 1.557 + addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time); 1.558 + } 1.559 +} 1.560 + 1.561 +#if HAVE_ANDROID_OS 1.562 +sp<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) { 1.563 + sp<KeyCharacterMap> map = new KeyCharacterMap(); 1.564 + map->mType = parcel->readInt32(); 1.565 + size_t numKeys = parcel->readInt32(); 1.566 + if (parcel->errorCheck()) { 1.567 + return NULL; 1.568 + } 1.569 + 1.570 + for (size_t i = 0; i < numKeys; i++) { 1.571 + int32_t keyCode = parcel->readInt32(); 1.572 + char16_t label = parcel->readInt32(); 1.573 + char16_t number = parcel->readInt32(); 1.574 + if (parcel->errorCheck()) { 1.575 + return NULL; 1.576 + } 1.577 + 1.578 + Key* key = new Key(); 1.579 + key->label = label; 1.580 + key->number = number; 1.581 + map->mKeys.add(keyCode, key); 1.582 + 1.583 + Behavior* lastBehavior = NULL; 1.584 + while (parcel->readInt32()) { 1.585 + int32_t metaState = parcel->readInt32(); 1.586 + char16_t character = parcel->readInt32(); 1.587 + int32_t fallbackKeyCode = parcel->readInt32(); 1.588 + if (parcel->errorCheck()) { 1.589 + return NULL; 1.590 + } 1.591 + 1.592 + Behavior* behavior = new Behavior(); 1.593 + behavior->metaState = metaState; 1.594 + behavior->character = character; 1.595 + behavior->fallbackKeyCode = fallbackKeyCode; 1.596 + if (lastBehavior) { 1.597 + lastBehavior->next = behavior; 1.598 + } else { 1.599 + key->firstBehavior = behavior; 1.600 + } 1.601 + lastBehavior = behavior; 1.602 + } 1.603 + 1.604 + if (parcel->errorCheck()) { 1.605 + return NULL; 1.606 + } 1.607 + } 1.608 + return map; 1.609 +} 1.610 + 1.611 +void KeyCharacterMap::writeToParcel(Parcel* parcel) const { 1.612 + parcel->writeInt32(mType); 1.613 + 1.614 + size_t numKeys = mKeys.size(); 1.615 + parcel->writeInt32(numKeys); 1.616 + for (size_t i = 0; i < numKeys; i++) { 1.617 + int32_t keyCode = mKeys.keyAt(i); 1.618 + const Key* key = mKeys.valueAt(i); 1.619 + parcel->writeInt32(keyCode); 1.620 + parcel->writeInt32(key->label); 1.621 + parcel->writeInt32(key->number); 1.622 + for (const Behavior* behavior = key->firstBehavior; behavior != NULL; 1.623 + behavior = behavior->next) { 1.624 + parcel->writeInt32(1); 1.625 + parcel->writeInt32(behavior->metaState); 1.626 + parcel->writeInt32(behavior->character); 1.627 + parcel->writeInt32(behavior->fallbackKeyCode); 1.628 + } 1.629 + parcel->writeInt32(0); 1.630 + } 1.631 +} 1.632 +#endif 1.633 + 1.634 + 1.635 +// --- KeyCharacterMap::Key --- 1.636 + 1.637 +KeyCharacterMap::Key::Key() : 1.638 + label(0), number(0), firstBehavior(NULL) { 1.639 +} 1.640 + 1.641 +KeyCharacterMap::Key::Key(const Key& other) : 1.642 + label(other.label), number(other.number), 1.643 + firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) { 1.644 +} 1.645 + 1.646 +KeyCharacterMap::Key::~Key() { 1.647 + Behavior* behavior = firstBehavior; 1.648 + while (behavior) { 1.649 + Behavior* next = behavior->next; 1.650 + delete behavior; 1.651 + behavior = next; 1.652 + } 1.653 +} 1.654 + 1.655 + 1.656 +// --- KeyCharacterMap::Behavior --- 1.657 + 1.658 +KeyCharacterMap::Behavior::Behavior() : 1.659 + next(NULL), metaState(0), character(0), fallbackKeyCode(0) { 1.660 +} 1.661 + 1.662 +KeyCharacterMap::Behavior::Behavior(const Behavior& other) : 1.663 + next(other.next ? new Behavior(*other.next) : NULL), 1.664 + metaState(other.metaState), character(other.character), 1.665 + fallbackKeyCode(other.fallbackKeyCode) { 1.666 +} 1.667 + 1.668 + 1.669 +// --- KeyCharacterMap::Parser --- 1.670 + 1.671 +KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) : 1.672 + mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) { 1.673 +} 1.674 + 1.675 +KeyCharacterMap::Parser::~Parser() { 1.676 +} 1.677 + 1.678 +status_t KeyCharacterMap::Parser::parse() { 1.679 + while (!mTokenizer->isEof()) { 1.680 +#if DEBUG_PARSER 1.681 + ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), 1.682 + mTokenizer->peekRemainderOfLine().string()); 1.683 +#endif 1.684 + 1.685 + mTokenizer->skipDelimiters(WHITESPACE); 1.686 + 1.687 + if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { 1.688 + switch (mState) { 1.689 + case STATE_TOP: { 1.690 + String8 keywordToken = mTokenizer->nextToken(WHITESPACE); 1.691 + if (keywordToken == "type") { 1.692 + mTokenizer->skipDelimiters(WHITESPACE); 1.693 + status_t status = parseType(); 1.694 + if (status) return status; 1.695 + } else if (keywordToken == "map") { 1.696 + mTokenizer->skipDelimiters(WHITESPACE); 1.697 + status_t status = parseMap(); 1.698 + if (status) return status; 1.699 + } else if (keywordToken == "key") { 1.700 + mTokenizer->skipDelimiters(WHITESPACE); 1.701 + status_t status = parseKey(); 1.702 + if (status) return status; 1.703 + } else { 1.704 + ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), 1.705 + keywordToken.string()); 1.706 + return BAD_VALUE; 1.707 + } 1.708 + break; 1.709 + } 1.710 + 1.711 + case STATE_KEY: { 1.712 + status_t status = parseKeyProperty(); 1.713 + if (status) return status; 1.714 + break; 1.715 + } 1.716 + } 1.717 + 1.718 + mTokenizer->skipDelimiters(WHITESPACE); 1.719 + if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { 1.720 + ALOGE("%s: Expected end of line or trailing comment, got '%s'.", 1.721 + mTokenizer->getLocation().string(), 1.722 + mTokenizer->peekRemainderOfLine().string()); 1.723 + return BAD_VALUE; 1.724 + } 1.725 + } 1.726 + 1.727 + mTokenizer->nextLine(); 1.728 + } 1.729 + 1.730 + if (mState != STATE_TOP) { 1.731 + ALOGE("%s: Unterminated key description at end of file.", 1.732 + mTokenizer->getLocation().string()); 1.733 + return BAD_VALUE; 1.734 + } 1.735 + 1.736 + if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) { 1.737 + ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.", 1.738 + mTokenizer->getLocation().string()); 1.739 + return BAD_VALUE; 1.740 + } 1.741 + 1.742 + if (mFormat == FORMAT_BASE) { 1.743 + if (mMap->mType == KEYBOARD_TYPE_OVERLAY) { 1.744 + ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.", 1.745 + mTokenizer->getLocation().string()); 1.746 + return BAD_VALUE; 1.747 + } 1.748 + } else if (mFormat == FORMAT_OVERLAY) { 1.749 + if (mMap->mType != KEYBOARD_TYPE_OVERLAY) { 1.750 + ALOGE("%s: Overlay keyboard layout missing required keyboard " 1.751 + "'type OVERLAY' declaration.", 1.752 + mTokenizer->getLocation().string()); 1.753 + return BAD_VALUE; 1.754 + } 1.755 + } 1.756 + 1.757 + return NO_ERROR; 1.758 +} 1.759 + 1.760 +status_t KeyCharacterMap::Parser::parseType() { 1.761 + if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) { 1.762 + ALOGE("%s: Duplicate keyboard 'type' declaration.", 1.763 + mTokenizer->getLocation().string()); 1.764 + return BAD_VALUE; 1.765 + } 1.766 + 1.767 + KeyboardType type; 1.768 + String8 typeToken = mTokenizer->nextToken(WHITESPACE); 1.769 + if (typeToken == "NUMERIC") { 1.770 + type = KEYBOARD_TYPE_NUMERIC; 1.771 + } else if (typeToken == "PREDICTIVE") { 1.772 + type = KEYBOARD_TYPE_PREDICTIVE; 1.773 + } else if (typeToken == "ALPHA") { 1.774 + type = KEYBOARD_TYPE_ALPHA; 1.775 + } else if (typeToken == "FULL") { 1.776 + type = KEYBOARD_TYPE_FULL; 1.777 + } else if (typeToken == "SPECIAL_FUNCTION") { 1.778 + type = KEYBOARD_TYPE_SPECIAL_FUNCTION; 1.779 + } else if (typeToken == "OVERLAY") { 1.780 + type = KEYBOARD_TYPE_OVERLAY; 1.781 + } else { 1.782 + ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(), 1.783 + typeToken.string()); 1.784 + return BAD_VALUE; 1.785 + } 1.786 + 1.787 +#if DEBUG_PARSER 1.788 + ALOGD("Parsed type: type=%d.", type); 1.789 +#endif 1.790 + mMap->mType = type; 1.791 + return NO_ERROR; 1.792 +} 1.793 + 1.794 +status_t KeyCharacterMap::Parser::parseMap() { 1.795 + String8 keywordToken = mTokenizer->nextToken(WHITESPACE); 1.796 + if (keywordToken == "key") { 1.797 + mTokenizer->skipDelimiters(WHITESPACE); 1.798 + return parseMapKey(); 1.799 + } 1.800 + ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(), 1.801 + keywordToken.string()); 1.802 + return BAD_VALUE; 1.803 +} 1.804 + 1.805 +status_t KeyCharacterMap::Parser::parseMapKey() { 1.806 + String8 codeToken = mTokenizer->nextToken(WHITESPACE); 1.807 + bool mapUsage = false; 1.808 + if (codeToken == "usage") { 1.809 + mapUsage = true; 1.810 + mTokenizer->skipDelimiters(WHITESPACE); 1.811 + codeToken = mTokenizer->nextToken(WHITESPACE); 1.812 + } 1.813 + 1.814 + char* end; 1.815 + int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); 1.816 + if (*end) { 1.817 + ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), 1.818 + mapUsage ? "usage" : "scan code", codeToken.string()); 1.819 + return BAD_VALUE; 1.820 + } 1.821 + KeyedVector<int32_t, int32_t>& map = 1.822 + mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; 1.823 + if (map.indexOfKey(code) >= 0) { 1.824 + ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), 1.825 + mapUsage ? "usage" : "scan code", codeToken.string()); 1.826 + return BAD_VALUE; 1.827 + } 1.828 + 1.829 + mTokenizer->skipDelimiters(WHITESPACE); 1.830 + String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); 1.831 + int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); 1.832 + if (!keyCode) { 1.833 + ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), 1.834 + keyCodeToken.string()); 1.835 + return BAD_VALUE; 1.836 + } 1.837 + 1.838 +#if DEBUG_PARSER 1.839 + ALOGD("Parsed map key %s: code=%d, keyCode=%d.", 1.840 + mapUsage ? "usage" : "scan code", code, keyCode); 1.841 +#endif 1.842 + map.add(code, keyCode); 1.843 + return NO_ERROR; 1.844 +} 1.845 + 1.846 +status_t KeyCharacterMap::Parser::parseKey() { 1.847 + String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); 1.848 + int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); 1.849 + if (!keyCode) { 1.850 + ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), 1.851 + keyCodeToken.string()); 1.852 + return BAD_VALUE; 1.853 + } 1.854 + if (mMap->mKeys.indexOfKey(keyCode) >= 0) { 1.855 + ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(), 1.856 + keyCodeToken.string()); 1.857 + return BAD_VALUE; 1.858 + } 1.859 + 1.860 + mTokenizer->skipDelimiters(WHITESPACE); 1.861 + String8 openBraceToken = mTokenizer->nextToken(WHITESPACE); 1.862 + if (openBraceToken != "{") { 1.863 + ALOGE("%s: Expected '{' after key code label, got '%s'.", 1.864 + mTokenizer->getLocation().string(), openBraceToken.string()); 1.865 + return BAD_VALUE; 1.866 + } 1.867 + 1.868 +#if DEBUG_PARSER 1.869 + ALOGD("Parsed beginning of key: keyCode=%d.", keyCode); 1.870 +#endif 1.871 + mKeyCode = keyCode; 1.872 + mMap->mKeys.add(keyCode, new Key()); 1.873 + mState = STATE_KEY; 1.874 + return NO_ERROR; 1.875 +} 1.876 + 1.877 +status_t KeyCharacterMap::Parser::parseKeyProperty() { 1.878 + Key* key = mMap->mKeys.valueFor(mKeyCode); 1.879 + String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); 1.880 + if (token == "}") { 1.881 + mState = STATE_TOP; 1.882 + return finishKey(key); 1.883 + } 1.884 + 1.885 + Vector<Property> properties; 1.886 + 1.887 + // Parse all comma-delimited property names up to the first colon. 1.888 + for (;;) { 1.889 + if (token == "label") { 1.890 + properties.add(Property(PROPERTY_LABEL)); 1.891 + } else if (token == "number") { 1.892 + properties.add(Property(PROPERTY_NUMBER)); 1.893 + } else { 1.894 + int32_t metaState; 1.895 + status_t status = parseModifier(token, &metaState); 1.896 + if (status) { 1.897 + ALOGE("%s: Expected a property name or modifier, got '%s'.", 1.898 + mTokenizer->getLocation().string(), token.string()); 1.899 + return status; 1.900 + } 1.901 + properties.add(Property(PROPERTY_META, metaState)); 1.902 + } 1.903 + 1.904 + mTokenizer->skipDelimiters(WHITESPACE); 1.905 + if (!mTokenizer->isEol()) { 1.906 + char ch = mTokenizer->nextChar(); 1.907 + if (ch == ':') { 1.908 + break; 1.909 + } else if (ch == ',') { 1.910 + mTokenizer->skipDelimiters(WHITESPACE); 1.911 + token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); 1.912 + continue; 1.913 + } 1.914 + } 1.915 + 1.916 + ALOGE("%s: Expected ',' or ':' after property name.", 1.917 + mTokenizer->getLocation().string()); 1.918 + return BAD_VALUE; 1.919 + } 1.920 + 1.921 + // Parse behavior after the colon. 1.922 + mTokenizer->skipDelimiters(WHITESPACE); 1.923 + 1.924 + Behavior behavior; 1.925 + bool haveCharacter = false; 1.926 + bool haveFallback = false; 1.927 + 1.928 + do { 1.929 + char ch = mTokenizer->peekChar(); 1.930 + if (ch == '\'') { 1.931 + char16_t character; 1.932 + status_t status = parseCharacterLiteral(&character); 1.933 + if (status || !character) { 1.934 + ALOGE("%s: Invalid character literal for key.", 1.935 + mTokenizer->getLocation().string()); 1.936 + return BAD_VALUE; 1.937 + } 1.938 + if (haveCharacter) { 1.939 + ALOGE("%s: Cannot combine multiple character literals or 'none'.", 1.940 + mTokenizer->getLocation().string()); 1.941 + return BAD_VALUE; 1.942 + } 1.943 + behavior.character = character; 1.944 + haveCharacter = true; 1.945 + } else { 1.946 + token = mTokenizer->nextToken(WHITESPACE); 1.947 + if (token == "none") { 1.948 + if (haveCharacter) { 1.949 + ALOGE("%s: Cannot combine multiple character literals or 'none'.", 1.950 + mTokenizer->getLocation().string()); 1.951 + return BAD_VALUE; 1.952 + } 1.953 + haveCharacter = true; 1.954 + } else if (token == "fallback") { 1.955 + mTokenizer->skipDelimiters(WHITESPACE); 1.956 + token = mTokenizer->nextToken(WHITESPACE); 1.957 + int32_t keyCode = getKeyCodeByLabel(token.string()); 1.958 + if (!keyCode) { 1.959 + ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.", 1.960 + mTokenizer->getLocation().string(), 1.961 + token.string()); 1.962 + return BAD_VALUE; 1.963 + } 1.964 + if (haveFallback) { 1.965 + ALOGE("%s: Cannot combine multiple fallback key codes.", 1.966 + mTokenizer->getLocation().string()); 1.967 + return BAD_VALUE; 1.968 + } 1.969 + behavior.fallbackKeyCode = keyCode; 1.970 + haveFallback = true; 1.971 + } else { 1.972 + ALOGE("%s: Expected a key behavior after ':'.", 1.973 + mTokenizer->getLocation().string()); 1.974 + return BAD_VALUE; 1.975 + } 1.976 + } 1.977 + 1.978 + mTokenizer->skipDelimiters(WHITESPACE); 1.979 + } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#'); 1.980 + 1.981 + // Add the behavior. 1.982 + for (size_t i = 0; i < properties.size(); i++) { 1.983 + const Property& property = properties.itemAt(i); 1.984 + switch (property.property) { 1.985 + case PROPERTY_LABEL: 1.986 + if (key->label) { 1.987 + ALOGE("%s: Duplicate label for key.", 1.988 + mTokenizer->getLocation().string()); 1.989 + return BAD_VALUE; 1.990 + } 1.991 + key->label = behavior.character; 1.992 +#if DEBUG_PARSER 1.993 + ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label); 1.994 +#endif 1.995 + break; 1.996 + case PROPERTY_NUMBER: 1.997 + if (key->number) { 1.998 + ALOGE("%s: Duplicate number for key.", 1.999 + mTokenizer->getLocation().string()); 1.1000 + return BAD_VALUE; 1.1001 + } 1.1002 + key->number = behavior.character; 1.1003 +#if DEBUG_PARSER 1.1004 + ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number); 1.1005 +#endif 1.1006 + break; 1.1007 + case PROPERTY_META: { 1.1008 + for (Behavior* b = key->firstBehavior; b; b = b->next) { 1.1009 + if (b->metaState == property.metaState) { 1.1010 + ALOGE("%s: Duplicate key behavior for modifier.", 1.1011 + mTokenizer->getLocation().string()); 1.1012 + return BAD_VALUE; 1.1013 + } 1.1014 + } 1.1015 + Behavior* newBehavior = new Behavior(behavior); 1.1016 + newBehavior->metaState = property.metaState; 1.1017 + newBehavior->next = key->firstBehavior; 1.1018 + key->firstBehavior = newBehavior; 1.1019 +#if DEBUG_PARSER 1.1020 + ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d.", mKeyCode, 1.1021 + newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode); 1.1022 +#endif 1.1023 + break; 1.1024 + } 1.1025 + } 1.1026 + } 1.1027 + return NO_ERROR; 1.1028 +} 1.1029 + 1.1030 +status_t KeyCharacterMap::Parser::finishKey(Key* key) { 1.1031 + // Fill in default number property. 1.1032 + if (!key->number) { 1.1033 + char16_t digit = 0; 1.1034 + char16_t symbol = 0; 1.1035 + for (Behavior* b = key->firstBehavior; b; b = b->next) { 1.1036 + char16_t ch = b->character; 1.1037 + if (ch) { 1.1038 + if (ch >= '0' && ch <= '9') { 1.1039 + digit = ch; 1.1040 + } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*' 1.1041 + || ch == '-' || ch == '+' || ch == ',' || ch == '.' 1.1042 + || ch == '\'' || ch == ':' || ch == ';' || ch == '/') { 1.1043 + symbol = ch; 1.1044 + } 1.1045 + } 1.1046 + } 1.1047 + key->number = digit ? digit : symbol; 1.1048 + } 1.1049 + return NO_ERROR; 1.1050 +} 1.1051 + 1.1052 +status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) { 1.1053 + if (token == "base") { 1.1054 + *outMetaState = 0; 1.1055 + return NO_ERROR; 1.1056 + } 1.1057 + 1.1058 + int32_t combinedMeta = 0; 1.1059 + 1.1060 + const char* str = token.string(); 1.1061 + const char* start = str; 1.1062 + for (const char* cur = str; ; cur++) { 1.1063 + char ch = *cur; 1.1064 + if (ch == '+' || ch == '\0') { 1.1065 + size_t len = cur - start; 1.1066 + int32_t metaState = 0; 1.1067 + for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) { 1.1068 + if (strlen(modifiers[i].label) == len 1.1069 + && strncmp(modifiers[i].label, start, len) == 0) { 1.1070 + metaState = modifiers[i].metaState; 1.1071 + break; 1.1072 + } 1.1073 + } 1.1074 + if (!metaState) { 1.1075 + return BAD_VALUE; 1.1076 + } 1.1077 + if (combinedMeta & metaState) { 1.1078 + ALOGE("%s: Duplicate modifier combination '%s'.", 1.1079 + mTokenizer->getLocation().string(), token.string()); 1.1080 + return BAD_VALUE; 1.1081 + } 1.1082 + 1.1083 + combinedMeta |= metaState; 1.1084 + start = cur + 1; 1.1085 + 1.1086 + if (ch == '\0') { 1.1087 + break; 1.1088 + } 1.1089 + } 1.1090 + } 1.1091 + *outMetaState = combinedMeta; 1.1092 + return NO_ERROR; 1.1093 +} 1.1094 + 1.1095 +status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) { 1.1096 + char ch = mTokenizer->nextChar(); 1.1097 + if (ch != '\'') { 1.1098 + goto Error; 1.1099 + } 1.1100 + 1.1101 + ch = mTokenizer->nextChar(); 1.1102 + if (ch == '\\') { 1.1103 + // Escape sequence. 1.1104 + ch = mTokenizer->nextChar(); 1.1105 + if (ch == 'n') { 1.1106 + *outCharacter = '\n'; 1.1107 + } else if (ch == 't') { 1.1108 + *outCharacter = '\t'; 1.1109 + } else if (ch == '\\') { 1.1110 + *outCharacter = '\\'; 1.1111 + } else if (ch == '\'') { 1.1112 + *outCharacter = '\''; 1.1113 + } else if (ch == '"') { 1.1114 + *outCharacter = '"'; 1.1115 + } else if (ch == 'u') { 1.1116 + *outCharacter = 0; 1.1117 + for (int i = 0; i < 4; i++) { 1.1118 + ch = mTokenizer->nextChar(); 1.1119 + int digit; 1.1120 + if (ch >= '0' && ch <= '9') { 1.1121 + digit = ch - '0'; 1.1122 + } else if (ch >= 'A' && ch <= 'F') { 1.1123 + digit = ch - 'A' + 10; 1.1124 + } else if (ch >= 'a' && ch <= 'f') { 1.1125 + digit = ch - 'a' + 10; 1.1126 + } else { 1.1127 + goto Error; 1.1128 + } 1.1129 + *outCharacter = (*outCharacter << 4) | digit; 1.1130 + } 1.1131 + } else { 1.1132 + goto Error; 1.1133 + } 1.1134 + } else if (ch >= 32 && ch <= 126 && ch != '\'') { 1.1135 + // ASCII literal character. 1.1136 + *outCharacter = ch; 1.1137 + } else { 1.1138 + goto Error; 1.1139 + } 1.1140 + 1.1141 + ch = mTokenizer->nextChar(); 1.1142 + if (ch != '\'') { 1.1143 + goto Error; 1.1144 + } 1.1145 + 1.1146 + // Ensure that we consumed the entire token. 1.1147 + if (mTokenizer->nextToken(WHITESPACE).isEmpty()) { 1.1148 + return NO_ERROR; 1.1149 + } 1.1150 + 1.1151 +Error: 1.1152 + ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string()); 1.1153 + return BAD_VALUE; 1.1154 +} 1.1155 + 1.1156 +} // namespace android