widget/gonk/libui/KeyCharacterMap.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*
michael@0 2 * Copyright (C) 2008 The Android Open Source Project
michael@0 3 *
michael@0 4 * Licensed under the Apache License, Version 2.0 (the "License");
michael@0 5 * you may not use this file except in compliance with the License.
michael@0 6 * You may obtain a copy of the License at
michael@0 7 *
michael@0 8 * http://www.apache.org/licenses/LICENSE-2.0
michael@0 9 *
michael@0 10 * Unless required by applicable law or agreed to in writing, software
michael@0 11 * distributed under the License is distributed on an "AS IS" BASIS,
michael@0 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 13 * See the License for the specific language governing permissions and
michael@0 14 * limitations under the License.
michael@0 15 */
michael@0 16
michael@0 17 #define LOG_TAG "KeyCharacterMap"
michael@0 18 #include "cutils_log.h"
michael@0 19
michael@0 20 #include <stdlib.h>
michael@0 21 #include <string.h>
michael@0 22 #include "android_keycodes.h"
michael@0 23 #include "Keyboard.h"
michael@0 24 #include "KeyCharacterMap.h"
michael@0 25
michael@0 26 #if HAVE_ANDROID_OS
michael@0 27 #include <binder/Parcel.h>
michael@0 28 #endif
michael@0 29
michael@0 30 #include <utils/Errors.h>
michael@0 31 #include "Tokenizer.h"
michael@0 32 #include <utils/Timers.h>
michael@0 33
michael@0 34 // Enables debug output for the parser.
michael@0 35 #define DEBUG_PARSER 0
michael@0 36
michael@0 37 // Enables debug output for parser performance.
michael@0 38 #define DEBUG_PARSER_PERFORMANCE 0
michael@0 39
michael@0 40 // Enables debug output for mapping.
michael@0 41 #define DEBUG_MAPPING 0
michael@0 42
michael@0 43
michael@0 44 namespace android {
michael@0 45
michael@0 46 static const char* WHITESPACE = " \t\r";
michael@0 47 static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:";
michael@0 48
michael@0 49 struct Modifier {
michael@0 50 const char* label;
michael@0 51 int32_t metaState;
michael@0 52 };
michael@0 53 static const Modifier modifiers[] = {
michael@0 54 { "shift", AMETA_SHIFT_ON },
michael@0 55 { "lshift", AMETA_SHIFT_LEFT_ON },
michael@0 56 { "rshift", AMETA_SHIFT_RIGHT_ON },
michael@0 57 { "alt", AMETA_ALT_ON },
michael@0 58 { "lalt", AMETA_ALT_LEFT_ON },
michael@0 59 { "ralt", AMETA_ALT_RIGHT_ON },
michael@0 60 { "ctrl", AMETA_CTRL_ON },
michael@0 61 { "lctrl", AMETA_CTRL_LEFT_ON },
michael@0 62 { "rctrl", AMETA_CTRL_RIGHT_ON },
michael@0 63 { "meta", AMETA_META_ON },
michael@0 64 { "lmeta", AMETA_META_LEFT_ON },
michael@0 65 { "rmeta", AMETA_META_RIGHT_ON },
michael@0 66 { "sym", AMETA_SYM_ON },
michael@0 67 { "fn", AMETA_FUNCTION_ON },
michael@0 68 { "capslock", AMETA_CAPS_LOCK_ON },
michael@0 69 { "numlock", AMETA_NUM_LOCK_ON },
michael@0 70 { "scrolllock", AMETA_SCROLL_LOCK_ON },
michael@0 71 };
michael@0 72
michael@0 73 #if DEBUG_MAPPING
michael@0 74 static String8 toString(const char16_t* chars, size_t numChars) {
michael@0 75 String8 result;
michael@0 76 for (size_t i = 0; i < numChars; i++) {
michael@0 77 result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]);
michael@0 78 }
michael@0 79 return result;
michael@0 80 }
michael@0 81 #endif
michael@0 82
michael@0 83
michael@0 84 // --- KeyCharacterMap ---
michael@0 85
michael@0 86 sp<KeyCharacterMap> KeyCharacterMap::sEmpty = new KeyCharacterMap();
michael@0 87
michael@0 88 KeyCharacterMap::KeyCharacterMap() :
michael@0 89 mType(KEYBOARD_TYPE_UNKNOWN) {
michael@0 90 }
michael@0 91
michael@0 92 KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) :
michael@0 93 RefBase(), mType(other.mType), mKeysByScanCode(other.mKeysByScanCode),
michael@0 94 mKeysByUsageCode(other.mKeysByUsageCode) {
michael@0 95 for (size_t i = 0; i < other.mKeys.size(); i++) {
michael@0 96 mKeys.add(other.mKeys.keyAt(i), new Key(*other.mKeys.valueAt(i)));
michael@0 97 }
michael@0 98 }
michael@0 99
michael@0 100 KeyCharacterMap::~KeyCharacterMap() {
michael@0 101 for (size_t i = 0; i < mKeys.size(); i++) {
michael@0 102 Key* key = mKeys.editValueAt(i);
michael@0 103 delete key;
michael@0 104 }
michael@0 105 }
michael@0 106
michael@0 107 status_t KeyCharacterMap::load(const String8& filename,
michael@0 108 Format format, sp<KeyCharacterMap>* outMap) {
michael@0 109 outMap->clear();
michael@0 110
michael@0 111 Tokenizer* tokenizer;
michael@0 112 status_t status = Tokenizer::open(filename, &tokenizer);
michael@0 113 if (status) {
michael@0 114 ALOGE("Error %d opening key character map file %s.", status, filename.string());
michael@0 115 } else {
michael@0 116 status = load(tokenizer, format, outMap);
michael@0 117 delete tokenizer;
michael@0 118 }
michael@0 119 return status;
michael@0 120 }
michael@0 121
michael@0 122 status_t KeyCharacterMap::loadContents(const String8& filename, const char* contents,
michael@0 123 Format format, sp<KeyCharacterMap>* outMap) {
michael@0 124 outMap->clear();
michael@0 125
michael@0 126 Tokenizer* tokenizer;
michael@0 127 status_t status = Tokenizer::fromContents(filename, contents, &tokenizer);
michael@0 128 if (status) {
michael@0 129 ALOGE("Error %d opening key character map.", status);
michael@0 130 } else {
michael@0 131 status = load(tokenizer, format, outMap);
michael@0 132 delete tokenizer;
michael@0 133 }
michael@0 134 return status;
michael@0 135 }
michael@0 136
michael@0 137 status_t KeyCharacterMap::load(Tokenizer* tokenizer,
michael@0 138 Format format, sp<KeyCharacterMap>* outMap) {
michael@0 139 status_t status = OK;
michael@0 140 sp<KeyCharacterMap> map = new KeyCharacterMap();
michael@0 141 if (!map.get()) {
michael@0 142 ALOGE("Error allocating key character map.");
michael@0 143 status = NO_MEMORY;
michael@0 144 } else {
michael@0 145 #if DEBUG_PARSER_PERFORMANCE
michael@0 146 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
michael@0 147 #endif
michael@0 148 Parser parser(map.get(), tokenizer, format);
michael@0 149 status = parser.parse();
michael@0 150 #if DEBUG_PARSER_PERFORMANCE
michael@0 151 nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
michael@0 152 ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
michael@0 153 tokenizer->getFilename().string(), tokenizer->getLineNumber(),
michael@0 154 elapsedTime / 1000000.0);
michael@0 155 #endif
michael@0 156 if (!status) {
michael@0 157 *outMap = map;
michael@0 158 }
michael@0 159 }
michael@0 160 return status;
michael@0 161 }
michael@0 162
michael@0 163 sp<KeyCharacterMap> KeyCharacterMap::combine(const sp<KeyCharacterMap>& base,
michael@0 164 const sp<KeyCharacterMap>& overlay) {
michael@0 165 if (overlay == NULL) {
michael@0 166 return base;
michael@0 167 }
michael@0 168 if (base == NULL) {
michael@0 169 return overlay;
michael@0 170 }
michael@0 171
michael@0 172 sp<KeyCharacterMap> map = new KeyCharacterMap(*base.get());
michael@0 173 for (size_t i = 0; i < overlay->mKeys.size(); i++) {
michael@0 174 int32_t keyCode = overlay->mKeys.keyAt(i);
michael@0 175 Key* key = overlay->mKeys.valueAt(i);
michael@0 176 ssize_t oldIndex = map->mKeys.indexOfKey(keyCode);
michael@0 177 if (oldIndex >= 0) {
michael@0 178 delete map->mKeys.valueAt(oldIndex);
michael@0 179 map->mKeys.editValueAt(oldIndex) = new Key(*key);
michael@0 180 } else {
michael@0 181 map->mKeys.add(keyCode, new Key(*key));
michael@0 182 }
michael@0 183 }
michael@0 184
michael@0 185 for (size_t i = 0; i < overlay->mKeysByScanCode.size(); i++) {
michael@0 186 map->mKeysByScanCode.replaceValueFor(overlay->mKeysByScanCode.keyAt(i),
michael@0 187 overlay->mKeysByScanCode.valueAt(i));
michael@0 188 }
michael@0 189
michael@0 190 for (size_t i = 0; i < overlay->mKeysByUsageCode.size(); i++) {
michael@0 191 map->mKeysByUsageCode.replaceValueFor(overlay->mKeysByUsageCode.keyAt(i),
michael@0 192 overlay->mKeysByUsageCode.valueAt(i));
michael@0 193 }
michael@0 194 return map;
michael@0 195 }
michael@0 196
michael@0 197 sp<KeyCharacterMap> KeyCharacterMap::empty() {
michael@0 198 return sEmpty;
michael@0 199 }
michael@0 200
michael@0 201 int32_t KeyCharacterMap::getKeyboardType() const {
michael@0 202 return mType;
michael@0 203 }
michael@0 204
michael@0 205 char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const {
michael@0 206 char16_t result = 0;
michael@0 207 const Key* key;
michael@0 208 if (getKey(keyCode, &key)) {
michael@0 209 result = key->label;
michael@0 210 }
michael@0 211 #if DEBUG_MAPPING
michael@0 212 ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result);
michael@0 213 #endif
michael@0 214 return result;
michael@0 215 }
michael@0 216
michael@0 217 char16_t KeyCharacterMap::getNumber(int32_t keyCode) const {
michael@0 218 char16_t result = 0;
michael@0 219 const Key* key;
michael@0 220 if (getKey(keyCode, &key)) {
michael@0 221 result = key->number;
michael@0 222 }
michael@0 223 #if DEBUG_MAPPING
michael@0 224 ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result);
michael@0 225 #endif
michael@0 226 return result;
michael@0 227 }
michael@0 228
michael@0 229 char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
michael@0 230 char16_t result = 0;
michael@0 231 const Key* key;
michael@0 232 const Behavior* behavior;
michael@0 233 if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
michael@0 234 result = behavior->character;
michael@0 235 }
michael@0 236 #if DEBUG_MAPPING
michael@0 237 ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result);
michael@0 238 #endif
michael@0 239 return result;
michael@0 240 }
michael@0 241
michael@0 242 bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState,
michael@0 243 FallbackAction* outFallbackAction) const {
michael@0 244 outFallbackAction->keyCode = 0;
michael@0 245 outFallbackAction->metaState = 0;
michael@0 246
michael@0 247 bool result = false;
michael@0 248 const Key* key;
michael@0 249 const Behavior* behavior;
michael@0 250 if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
michael@0 251 if (behavior->fallbackKeyCode) {
michael@0 252 outFallbackAction->keyCode = behavior->fallbackKeyCode;
michael@0 253 outFallbackAction->metaState = metaState & ~behavior->metaState;
michael@0 254 result = true;
michael@0 255 }
michael@0 256 }
michael@0 257 #if DEBUG_MAPPING
michael@0 258 ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, "
michael@0 259 "fallback keyCode=%d, fallback metaState=0x%08x.",
michael@0 260 keyCode, metaState, result ? "true" : "false",
michael@0 261 outFallbackAction->keyCode, outFallbackAction->metaState);
michael@0 262 #endif
michael@0 263 return result;
michael@0 264 }
michael@0 265
michael@0 266 char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars,
michael@0 267 int32_t metaState) const {
michael@0 268 char16_t result = 0;
michael@0 269 const Key* key;
michael@0 270 if (getKey(keyCode, &key)) {
michael@0 271 // Try to find the most general behavior that maps to this character.
michael@0 272 // For example, the base key behavior will usually be last in the list.
michael@0 273 // However, if we find a perfect meta state match for one behavior then use that one.
michael@0 274 for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
michael@0 275 if (behavior->character) {
michael@0 276 for (size_t i = 0; i < numChars; i++) {
michael@0 277 if (behavior->character == chars[i]) {
michael@0 278 result = behavior->character;
michael@0 279 if ((behavior->metaState & metaState) == behavior->metaState) {
michael@0 280 goto ExactMatch;
michael@0 281 }
michael@0 282 break;
michael@0 283 }
michael@0 284 }
michael@0 285 }
michael@0 286 }
michael@0 287 ExactMatch: ;
michael@0 288 }
michael@0 289 #if DEBUG_MAPPING
michael@0 290 ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.",
michael@0 291 keyCode, toString(chars, numChars).string(), metaState, result);
michael@0 292 #endif
michael@0 293 return result;
michael@0 294 }
michael@0 295
michael@0 296 bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
michael@0 297 Vector<KeyEvent>& outEvents) const {
michael@0 298 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
michael@0 299
michael@0 300 for (size_t i = 0; i < numChars; i++) {
michael@0 301 int32_t keyCode, metaState;
michael@0 302 char16_t ch = chars[i];
michael@0 303 if (!findKey(ch, &keyCode, &metaState)) {
michael@0 304 #if DEBUG_MAPPING
michael@0 305 ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.",
michael@0 306 deviceId, toString(chars, numChars).string(), ch);
michael@0 307 #endif
michael@0 308 return false;
michael@0 309 }
michael@0 310
michael@0 311 int32_t currentMetaState = 0;
michael@0 312 addMetaKeys(outEvents, deviceId, metaState, true, now, &currentMetaState);
michael@0 313 addKey(outEvents, deviceId, keyCode, currentMetaState, true, now);
michael@0 314 addKey(outEvents, deviceId, keyCode, currentMetaState, false, now);
michael@0 315 addMetaKeys(outEvents, deviceId, metaState, false, now, &currentMetaState);
michael@0 316 }
michael@0 317 #if DEBUG_MAPPING
michael@0 318 ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.",
michael@0 319 deviceId, toString(chars, numChars).string(), int32_t(outEvents.size()));
michael@0 320 for (size_t i = 0; i < outEvents.size(); i++) {
michael@0 321 ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.",
michael@0 322 outEvents[i].getKeyCode(), outEvents[i].getMetaState(),
michael@0 323 outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up");
michael@0 324 }
michael@0 325 #endif
michael@0 326 return true;
michael@0 327 }
michael@0 328
michael@0 329 status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
michael@0 330 if (usageCode) {
michael@0 331 ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
michael@0 332 if (index >= 0) {
michael@0 333 #if DEBUG_MAPPING
michael@0 334 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
michael@0 335 scanCode, usageCode, *outKeyCode);
michael@0 336 #endif
michael@0 337 *outKeyCode = mKeysByUsageCode.valueAt(index);
michael@0 338 return OK;
michael@0 339 }
michael@0 340 }
michael@0 341 if (scanCode) {
michael@0 342 ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
michael@0 343 if (index >= 0) {
michael@0 344 #if DEBUG_MAPPING
michael@0 345 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
michael@0 346 scanCode, usageCode, *outKeyCode);
michael@0 347 #endif
michael@0 348 *outKeyCode = mKeysByScanCode.valueAt(index);
michael@0 349 return OK;
michael@0 350 }
michael@0 351 }
michael@0 352
michael@0 353 #if DEBUG_MAPPING
michael@0 354 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
michael@0 355 #endif
michael@0 356 *outKeyCode = AKEYCODE_UNKNOWN;
michael@0 357 return NAME_NOT_FOUND;
michael@0 358 }
michael@0 359
michael@0 360 bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
michael@0 361 ssize_t index = mKeys.indexOfKey(keyCode);
michael@0 362 if (index >= 0) {
michael@0 363 *outKey = mKeys.valueAt(index);
michael@0 364 return true;
michael@0 365 }
michael@0 366 return false;
michael@0 367 }
michael@0 368
michael@0 369 bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState,
michael@0 370 const Key** outKey, const Behavior** outBehavior) const {
michael@0 371 const Key* key;
michael@0 372 if (getKey(keyCode, &key)) {
michael@0 373 const Behavior* behavior = key->firstBehavior;
michael@0 374 while (behavior) {
michael@0 375 if (matchesMetaState(metaState, behavior->metaState)) {
michael@0 376 *outKey = key;
michael@0 377 *outBehavior = behavior;
michael@0 378 return true;
michael@0 379 }
michael@0 380 behavior = behavior->next;
michael@0 381 }
michael@0 382 }
michael@0 383 return false;
michael@0 384 }
michael@0 385
michael@0 386 bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
michael@0 387 // Behavior must have at least the set of meta states specified.
michael@0 388 // And if the key event has CTRL, ALT or META then the behavior must exactly
michael@0 389 // match those, taking into account that a behavior can specify that it handles
michael@0 390 // one, both or either of a left/right modifier pair.
michael@0 391 if ((eventMetaState & behaviorMetaState) == behaviorMetaState) {
michael@0 392 const int32_t EXACT_META_STATES =
michael@0 393 AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON
michael@0 394 | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON
michael@0 395 | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON;
michael@0 396 int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES;
michael@0 397 if (behaviorMetaState & AMETA_CTRL_ON) {
michael@0 398 unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
michael@0 399 } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
michael@0 400 unmatchedMetaState &= ~AMETA_CTRL_ON;
michael@0 401 }
michael@0 402 if (behaviorMetaState & AMETA_ALT_ON) {
michael@0 403 unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
michael@0 404 } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
michael@0 405 unmatchedMetaState &= ~AMETA_ALT_ON;
michael@0 406 }
michael@0 407 if (behaviorMetaState & AMETA_META_ON) {
michael@0 408 unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
michael@0 409 } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
michael@0 410 unmatchedMetaState &= ~AMETA_META_ON;
michael@0 411 }
michael@0 412 return !unmatchedMetaState;
michael@0 413 }
michael@0 414 return false;
michael@0 415 }
michael@0 416
michael@0 417 bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
michael@0 418 if (!ch) {
michael@0 419 return false;
michael@0 420 }
michael@0 421
michael@0 422 for (size_t i = 0; i < mKeys.size(); i++) {
michael@0 423 const Key* key = mKeys.valueAt(i);
michael@0 424
michael@0 425 // Try to find the most general behavior that maps to this character.
michael@0 426 // For example, the base key behavior will usually be last in the list.
michael@0 427 const Behavior* found = NULL;
michael@0 428 for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
michael@0 429 if (behavior->character == ch) {
michael@0 430 found = behavior;
michael@0 431 }
michael@0 432 }
michael@0 433 if (found) {
michael@0 434 *outKeyCode = mKeys.keyAt(i);
michael@0 435 *outMetaState = found->metaState;
michael@0 436 return true;
michael@0 437 }
michael@0 438 }
michael@0 439 return false;
michael@0 440 }
michael@0 441
michael@0 442 void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents,
michael@0 443 int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
michael@0 444 outEvents.push();
michael@0 445 KeyEvent& event = outEvents.editTop();
michael@0 446 event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD,
michael@0 447 down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
michael@0 448 0, keyCode, 0, metaState, 0, time, time);
michael@0 449 }
michael@0 450
michael@0 451 void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
michael@0 452 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
michael@0 453 int32_t* currentMetaState) {
michael@0 454 // Add and remove meta keys symmetrically.
michael@0 455 if (down) {
michael@0 456 addLockedMetaKey(outEvents, deviceId, metaState, time,
michael@0 457 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
michael@0 458 addLockedMetaKey(outEvents, deviceId, metaState, time,
michael@0 459 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
michael@0 460 addLockedMetaKey(outEvents, deviceId, metaState, time,
michael@0 461 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
michael@0 462
michael@0 463 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
michael@0 464 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
michael@0 465 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
michael@0 466 AMETA_SHIFT_ON, currentMetaState);
michael@0 467 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
michael@0 468 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
michael@0 469 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
michael@0 470 AMETA_ALT_ON, currentMetaState);
michael@0 471 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
michael@0 472 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
michael@0 473 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
michael@0 474 AMETA_CTRL_ON, currentMetaState);
michael@0 475 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
michael@0 476 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
michael@0 477 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
michael@0 478 AMETA_META_ON, currentMetaState);
michael@0 479
michael@0 480 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
michael@0 481 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
michael@0 482 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
michael@0 483 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
michael@0 484 } else {
michael@0 485 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
michael@0 486 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
michael@0 487 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
michael@0 488 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
michael@0 489
michael@0 490 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
michael@0 491 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
michael@0 492 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
michael@0 493 AMETA_META_ON, currentMetaState);
michael@0 494 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
michael@0 495 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
michael@0 496 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
michael@0 497 AMETA_CTRL_ON, currentMetaState);
michael@0 498 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
michael@0 499 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
michael@0 500 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
michael@0 501 AMETA_ALT_ON, currentMetaState);
michael@0 502 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
michael@0 503 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
michael@0 504 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
michael@0 505 AMETA_SHIFT_ON, currentMetaState);
michael@0 506
michael@0 507 addLockedMetaKey(outEvents, deviceId, metaState, time,
michael@0 508 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
michael@0 509 addLockedMetaKey(outEvents, deviceId, metaState, time,
michael@0 510 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
michael@0 511 addLockedMetaKey(outEvents, deviceId, metaState, time,
michael@0 512 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
michael@0 513 }
michael@0 514 }
michael@0 515
michael@0 516 bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
michael@0 517 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
michael@0 518 int32_t keyCode, int32_t keyMetaState,
michael@0 519 int32_t* currentMetaState) {
michael@0 520 if ((metaState & keyMetaState) == keyMetaState) {
michael@0 521 *currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
michael@0 522 addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
michael@0 523 return true;
michael@0 524 }
michael@0 525 return false;
michael@0 526 }
michael@0 527
michael@0 528 void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
michael@0 529 int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
michael@0 530 int32_t leftKeyCode, int32_t leftKeyMetaState,
michael@0 531 int32_t rightKeyCode, int32_t rightKeyMetaState,
michael@0 532 int32_t eitherKeyMetaState,
michael@0 533 int32_t* currentMetaState) {
michael@0 534 bool specific = false;
michael@0 535 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
michael@0 536 leftKeyCode, leftKeyMetaState, currentMetaState);
michael@0 537 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
michael@0 538 rightKeyCode, rightKeyMetaState, currentMetaState);
michael@0 539
michael@0 540 if (!specific) {
michael@0 541 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
michael@0 542 leftKeyCode, eitherKeyMetaState, currentMetaState);
michael@0 543 }
michael@0 544 }
michael@0 545
michael@0 546 void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
michael@0 547 int32_t deviceId, int32_t metaState, nsecs_t time,
michael@0 548 int32_t keyCode, int32_t keyMetaState,
michael@0 549 int32_t* currentMetaState) {
michael@0 550 if ((metaState & keyMetaState) == keyMetaState) {
michael@0 551 *currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
michael@0 552 addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
michael@0 553 *currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
michael@0 554 addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
michael@0 555 }
michael@0 556 }
michael@0 557
michael@0 558 #if HAVE_ANDROID_OS
michael@0 559 sp<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
michael@0 560 sp<KeyCharacterMap> map = new KeyCharacterMap();
michael@0 561 map->mType = parcel->readInt32();
michael@0 562 size_t numKeys = parcel->readInt32();
michael@0 563 if (parcel->errorCheck()) {
michael@0 564 return NULL;
michael@0 565 }
michael@0 566
michael@0 567 for (size_t i = 0; i < numKeys; i++) {
michael@0 568 int32_t keyCode = parcel->readInt32();
michael@0 569 char16_t label = parcel->readInt32();
michael@0 570 char16_t number = parcel->readInt32();
michael@0 571 if (parcel->errorCheck()) {
michael@0 572 return NULL;
michael@0 573 }
michael@0 574
michael@0 575 Key* key = new Key();
michael@0 576 key->label = label;
michael@0 577 key->number = number;
michael@0 578 map->mKeys.add(keyCode, key);
michael@0 579
michael@0 580 Behavior* lastBehavior = NULL;
michael@0 581 while (parcel->readInt32()) {
michael@0 582 int32_t metaState = parcel->readInt32();
michael@0 583 char16_t character = parcel->readInt32();
michael@0 584 int32_t fallbackKeyCode = parcel->readInt32();
michael@0 585 if (parcel->errorCheck()) {
michael@0 586 return NULL;
michael@0 587 }
michael@0 588
michael@0 589 Behavior* behavior = new Behavior();
michael@0 590 behavior->metaState = metaState;
michael@0 591 behavior->character = character;
michael@0 592 behavior->fallbackKeyCode = fallbackKeyCode;
michael@0 593 if (lastBehavior) {
michael@0 594 lastBehavior->next = behavior;
michael@0 595 } else {
michael@0 596 key->firstBehavior = behavior;
michael@0 597 }
michael@0 598 lastBehavior = behavior;
michael@0 599 }
michael@0 600
michael@0 601 if (parcel->errorCheck()) {
michael@0 602 return NULL;
michael@0 603 }
michael@0 604 }
michael@0 605 return map;
michael@0 606 }
michael@0 607
michael@0 608 void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
michael@0 609 parcel->writeInt32(mType);
michael@0 610
michael@0 611 size_t numKeys = mKeys.size();
michael@0 612 parcel->writeInt32(numKeys);
michael@0 613 for (size_t i = 0; i < numKeys; i++) {
michael@0 614 int32_t keyCode = mKeys.keyAt(i);
michael@0 615 const Key* key = mKeys.valueAt(i);
michael@0 616 parcel->writeInt32(keyCode);
michael@0 617 parcel->writeInt32(key->label);
michael@0 618 parcel->writeInt32(key->number);
michael@0 619 for (const Behavior* behavior = key->firstBehavior; behavior != NULL;
michael@0 620 behavior = behavior->next) {
michael@0 621 parcel->writeInt32(1);
michael@0 622 parcel->writeInt32(behavior->metaState);
michael@0 623 parcel->writeInt32(behavior->character);
michael@0 624 parcel->writeInt32(behavior->fallbackKeyCode);
michael@0 625 }
michael@0 626 parcel->writeInt32(0);
michael@0 627 }
michael@0 628 }
michael@0 629 #endif
michael@0 630
michael@0 631
michael@0 632 // --- KeyCharacterMap::Key ---
michael@0 633
michael@0 634 KeyCharacterMap::Key::Key() :
michael@0 635 label(0), number(0), firstBehavior(NULL) {
michael@0 636 }
michael@0 637
michael@0 638 KeyCharacterMap::Key::Key(const Key& other) :
michael@0 639 label(other.label), number(other.number),
michael@0 640 firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) {
michael@0 641 }
michael@0 642
michael@0 643 KeyCharacterMap::Key::~Key() {
michael@0 644 Behavior* behavior = firstBehavior;
michael@0 645 while (behavior) {
michael@0 646 Behavior* next = behavior->next;
michael@0 647 delete behavior;
michael@0 648 behavior = next;
michael@0 649 }
michael@0 650 }
michael@0 651
michael@0 652
michael@0 653 // --- KeyCharacterMap::Behavior ---
michael@0 654
michael@0 655 KeyCharacterMap::Behavior::Behavior() :
michael@0 656 next(NULL), metaState(0), character(0), fallbackKeyCode(0) {
michael@0 657 }
michael@0 658
michael@0 659 KeyCharacterMap::Behavior::Behavior(const Behavior& other) :
michael@0 660 next(other.next ? new Behavior(*other.next) : NULL),
michael@0 661 metaState(other.metaState), character(other.character),
michael@0 662 fallbackKeyCode(other.fallbackKeyCode) {
michael@0 663 }
michael@0 664
michael@0 665
michael@0 666 // --- KeyCharacterMap::Parser ---
michael@0 667
michael@0 668 KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
michael@0 669 mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
michael@0 670 }
michael@0 671
michael@0 672 KeyCharacterMap::Parser::~Parser() {
michael@0 673 }
michael@0 674
michael@0 675 status_t KeyCharacterMap::Parser::parse() {
michael@0 676 while (!mTokenizer->isEof()) {
michael@0 677 #if DEBUG_PARSER
michael@0 678 ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
michael@0 679 mTokenizer->peekRemainderOfLine().string());
michael@0 680 #endif
michael@0 681
michael@0 682 mTokenizer->skipDelimiters(WHITESPACE);
michael@0 683
michael@0 684 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
michael@0 685 switch (mState) {
michael@0 686 case STATE_TOP: {
michael@0 687 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
michael@0 688 if (keywordToken == "type") {
michael@0 689 mTokenizer->skipDelimiters(WHITESPACE);
michael@0 690 status_t status = parseType();
michael@0 691 if (status) return status;
michael@0 692 } else if (keywordToken == "map") {
michael@0 693 mTokenizer->skipDelimiters(WHITESPACE);
michael@0 694 status_t status = parseMap();
michael@0 695 if (status) return status;
michael@0 696 } else if (keywordToken == "key") {
michael@0 697 mTokenizer->skipDelimiters(WHITESPACE);
michael@0 698 status_t status = parseKey();
michael@0 699 if (status) return status;
michael@0 700 } else {
michael@0 701 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
michael@0 702 keywordToken.string());
michael@0 703 return BAD_VALUE;
michael@0 704 }
michael@0 705 break;
michael@0 706 }
michael@0 707
michael@0 708 case STATE_KEY: {
michael@0 709 status_t status = parseKeyProperty();
michael@0 710 if (status) return status;
michael@0 711 break;
michael@0 712 }
michael@0 713 }
michael@0 714
michael@0 715 mTokenizer->skipDelimiters(WHITESPACE);
michael@0 716 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
michael@0 717 ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
michael@0 718 mTokenizer->getLocation().string(),
michael@0 719 mTokenizer->peekRemainderOfLine().string());
michael@0 720 return BAD_VALUE;
michael@0 721 }
michael@0 722 }
michael@0 723
michael@0 724 mTokenizer->nextLine();
michael@0 725 }
michael@0 726
michael@0 727 if (mState != STATE_TOP) {
michael@0 728 ALOGE("%s: Unterminated key description at end of file.",
michael@0 729 mTokenizer->getLocation().string());
michael@0 730 return BAD_VALUE;
michael@0 731 }
michael@0 732
michael@0 733 if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
michael@0 734 ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
michael@0 735 mTokenizer->getLocation().string());
michael@0 736 return BAD_VALUE;
michael@0 737 }
michael@0 738
michael@0 739 if (mFormat == FORMAT_BASE) {
michael@0 740 if (mMap->mType == KEYBOARD_TYPE_OVERLAY) {
michael@0 741 ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
michael@0 742 mTokenizer->getLocation().string());
michael@0 743 return BAD_VALUE;
michael@0 744 }
michael@0 745 } else if (mFormat == FORMAT_OVERLAY) {
michael@0 746 if (mMap->mType != KEYBOARD_TYPE_OVERLAY) {
michael@0 747 ALOGE("%s: Overlay keyboard layout missing required keyboard "
michael@0 748 "'type OVERLAY' declaration.",
michael@0 749 mTokenizer->getLocation().string());
michael@0 750 return BAD_VALUE;
michael@0 751 }
michael@0 752 }
michael@0 753
michael@0 754 return NO_ERROR;
michael@0 755 }
michael@0 756
michael@0 757 status_t KeyCharacterMap::Parser::parseType() {
michael@0 758 if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) {
michael@0 759 ALOGE("%s: Duplicate keyboard 'type' declaration.",
michael@0 760 mTokenizer->getLocation().string());
michael@0 761 return BAD_VALUE;
michael@0 762 }
michael@0 763
michael@0 764 KeyboardType type;
michael@0 765 String8 typeToken = mTokenizer->nextToken(WHITESPACE);
michael@0 766 if (typeToken == "NUMERIC") {
michael@0 767 type = KEYBOARD_TYPE_NUMERIC;
michael@0 768 } else if (typeToken == "PREDICTIVE") {
michael@0 769 type = KEYBOARD_TYPE_PREDICTIVE;
michael@0 770 } else if (typeToken == "ALPHA") {
michael@0 771 type = KEYBOARD_TYPE_ALPHA;
michael@0 772 } else if (typeToken == "FULL") {
michael@0 773 type = KEYBOARD_TYPE_FULL;
michael@0 774 } else if (typeToken == "SPECIAL_FUNCTION") {
michael@0 775 type = KEYBOARD_TYPE_SPECIAL_FUNCTION;
michael@0 776 } else if (typeToken == "OVERLAY") {
michael@0 777 type = KEYBOARD_TYPE_OVERLAY;
michael@0 778 } else {
michael@0 779 ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(),
michael@0 780 typeToken.string());
michael@0 781 return BAD_VALUE;
michael@0 782 }
michael@0 783
michael@0 784 #if DEBUG_PARSER
michael@0 785 ALOGD("Parsed type: type=%d.", type);
michael@0 786 #endif
michael@0 787 mMap->mType = type;
michael@0 788 return NO_ERROR;
michael@0 789 }
michael@0 790
michael@0 791 status_t KeyCharacterMap::Parser::parseMap() {
michael@0 792 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
michael@0 793 if (keywordToken == "key") {
michael@0 794 mTokenizer->skipDelimiters(WHITESPACE);
michael@0 795 return parseMapKey();
michael@0 796 }
michael@0 797 ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(),
michael@0 798 keywordToken.string());
michael@0 799 return BAD_VALUE;
michael@0 800 }
michael@0 801
michael@0 802 status_t KeyCharacterMap::Parser::parseMapKey() {
michael@0 803 String8 codeToken = mTokenizer->nextToken(WHITESPACE);
michael@0 804 bool mapUsage = false;
michael@0 805 if (codeToken == "usage") {
michael@0 806 mapUsage = true;
michael@0 807 mTokenizer->skipDelimiters(WHITESPACE);
michael@0 808 codeToken = mTokenizer->nextToken(WHITESPACE);
michael@0 809 }
michael@0 810
michael@0 811 char* end;
michael@0 812 int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
michael@0 813 if (*end) {
michael@0 814 ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
michael@0 815 mapUsage ? "usage" : "scan code", codeToken.string());
michael@0 816 return BAD_VALUE;
michael@0 817 }
michael@0 818 KeyedVector<int32_t, int32_t>& map =
michael@0 819 mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
michael@0 820 if (map.indexOfKey(code) >= 0) {
michael@0 821 ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
michael@0 822 mapUsage ? "usage" : "scan code", codeToken.string());
michael@0 823 return BAD_VALUE;
michael@0 824 }
michael@0 825
michael@0 826 mTokenizer->skipDelimiters(WHITESPACE);
michael@0 827 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
michael@0 828 int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
michael@0 829 if (!keyCode) {
michael@0 830 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
michael@0 831 keyCodeToken.string());
michael@0 832 return BAD_VALUE;
michael@0 833 }
michael@0 834
michael@0 835 #if DEBUG_PARSER
michael@0 836 ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
michael@0 837 mapUsage ? "usage" : "scan code", code, keyCode);
michael@0 838 #endif
michael@0 839 map.add(code, keyCode);
michael@0 840 return NO_ERROR;
michael@0 841 }
michael@0 842
michael@0 843 status_t KeyCharacterMap::Parser::parseKey() {
michael@0 844 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
michael@0 845 int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
michael@0 846 if (!keyCode) {
michael@0 847 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
michael@0 848 keyCodeToken.string());
michael@0 849 return BAD_VALUE;
michael@0 850 }
michael@0 851 if (mMap->mKeys.indexOfKey(keyCode) >= 0) {
michael@0 852 ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(),
michael@0 853 keyCodeToken.string());
michael@0 854 return BAD_VALUE;
michael@0 855 }
michael@0 856
michael@0 857 mTokenizer->skipDelimiters(WHITESPACE);
michael@0 858 String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
michael@0 859 if (openBraceToken != "{") {
michael@0 860 ALOGE("%s: Expected '{' after key code label, got '%s'.",
michael@0 861 mTokenizer->getLocation().string(), openBraceToken.string());
michael@0 862 return BAD_VALUE;
michael@0 863 }
michael@0 864
michael@0 865 #if DEBUG_PARSER
michael@0 866 ALOGD("Parsed beginning of key: keyCode=%d.", keyCode);
michael@0 867 #endif
michael@0 868 mKeyCode = keyCode;
michael@0 869 mMap->mKeys.add(keyCode, new Key());
michael@0 870 mState = STATE_KEY;
michael@0 871 return NO_ERROR;
michael@0 872 }
michael@0 873
michael@0 874 status_t KeyCharacterMap::Parser::parseKeyProperty() {
michael@0 875 Key* key = mMap->mKeys.valueFor(mKeyCode);
michael@0 876 String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
michael@0 877 if (token == "}") {
michael@0 878 mState = STATE_TOP;
michael@0 879 return finishKey(key);
michael@0 880 }
michael@0 881
michael@0 882 Vector<Property> properties;
michael@0 883
michael@0 884 // Parse all comma-delimited property names up to the first colon.
michael@0 885 for (;;) {
michael@0 886 if (token == "label") {
michael@0 887 properties.add(Property(PROPERTY_LABEL));
michael@0 888 } else if (token == "number") {
michael@0 889 properties.add(Property(PROPERTY_NUMBER));
michael@0 890 } else {
michael@0 891 int32_t metaState;
michael@0 892 status_t status = parseModifier(token, &metaState);
michael@0 893 if (status) {
michael@0 894 ALOGE("%s: Expected a property name or modifier, got '%s'.",
michael@0 895 mTokenizer->getLocation().string(), token.string());
michael@0 896 return status;
michael@0 897 }
michael@0 898 properties.add(Property(PROPERTY_META, metaState));
michael@0 899 }
michael@0 900
michael@0 901 mTokenizer->skipDelimiters(WHITESPACE);
michael@0 902 if (!mTokenizer->isEol()) {
michael@0 903 char ch = mTokenizer->nextChar();
michael@0 904 if (ch == ':') {
michael@0 905 break;
michael@0 906 } else if (ch == ',') {
michael@0 907 mTokenizer->skipDelimiters(WHITESPACE);
michael@0 908 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
michael@0 909 continue;
michael@0 910 }
michael@0 911 }
michael@0 912
michael@0 913 ALOGE("%s: Expected ',' or ':' after property name.",
michael@0 914 mTokenizer->getLocation().string());
michael@0 915 return BAD_VALUE;
michael@0 916 }
michael@0 917
michael@0 918 // Parse behavior after the colon.
michael@0 919 mTokenizer->skipDelimiters(WHITESPACE);
michael@0 920
michael@0 921 Behavior behavior;
michael@0 922 bool haveCharacter = false;
michael@0 923 bool haveFallback = false;
michael@0 924
michael@0 925 do {
michael@0 926 char ch = mTokenizer->peekChar();
michael@0 927 if (ch == '\'') {
michael@0 928 char16_t character;
michael@0 929 status_t status = parseCharacterLiteral(&character);
michael@0 930 if (status || !character) {
michael@0 931 ALOGE("%s: Invalid character literal for key.",
michael@0 932 mTokenizer->getLocation().string());
michael@0 933 return BAD_VALUE;
michael@0 934 }
michael@0 935 if (haveCharacter) {
michael@0 936 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
michael@0 937 mTokenizer->getLocation().string());
michael@0 938 return BAD_VALUE;
michael@0 939 }
michael@0 940 behavior.character = character;
michael@0 941 haveCharacter = true;
michael@0 942 } else {
michael@0 943 token = mTokenizer->nextToken(WHITESPACE);
michael@0 944 if (token == "none") {
michael@0 945 if (haveCharacter) {
michael@0 946 ALOGE("%s: Cannot combine multiple character literals or 'none'.",
michael@0 947 mTokenizer->getLocation().string());
michael@0 948 return BAD_VALUE;
michael@0 949 }
michael@0 950 haveCharacter = true;
michael@0 951 } else if (token == "fallback") {
michael@0 952 mTokenizer->skipDelimiters(WHITESPACE);
michael@0 953 token = mTokenizer->nextToken(WHITESPACE);
michael@0 954 int32_t keyCode = getKeyCodeByLabel(token.string());
michael@0 955 if (!keyCode) {
michael@0 956 ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
michael@0 957 mTokenizer->getLocation().string(),
michael@0 958 token.string());
michael@0 959 return BAD_VALUE;
michael@0 960 }
michael@0 961 if (haveFallback) {
michael@0 962 ALOGE("%s: Cannot combine multiple fallback key codes.",
michael@0 963 mTokenizer->getLocation().string());
michael@0 964 return BAD_VALUE;
michael@0 965 }
michael@0 966 behavior.fallbackKeyCode = keyCode;
michael@0 967 haveFallback = true;
michael@0 968 } else {
michael@0 969 ALOGE("%s: Expected a key behavior after ':'.",
michael@0 970 mTokenizer->getLocation().string());
michael@0 971 return BAD_VALUE;
michael@0 972 }
michael@0 973 }
michael@0 974
michael@0 975 mTokenizer->skipDelimiters(WHITESPACE);
michael@0 976 } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#');
michael@0 977
michael@0 978 // Add the behavior.
michael@0 979 for (size_t i = 0; i < properties.size(); i++) {
michael@0 980 const Property& property = properties.itemAt(i);
michael@0 981 switch (property.property) {
michael@0 982 case PROPERTY_LABEL:
michael@0 983 if (key->label) {
michael@0 984 ALOGE("%s: Duplicate label for key.",
michael@0 985 mTokenizer->getLocation().string());
michael@0 986 return BAD_VALUE;
michael@0 987 }
michael@0 988 key->label = behavior.character;
michael@0 989 #if DEBUG_PARSER
michael@0 990 ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label);
michael@0 991 #endif
michael@0 992 break;
michael@0 993 case PROPERTY_NUMBER:
michael@0 994 if (key->number) {
michael@0 995 ALOGE("%s: Duplicate number for key.",
michael@0 996 mTokenizer->getLocation().string());
michael@0 997 return BAD_VALUE;
michael@0 998 }
michael@0 999 key->number = behavior.character;
michael@0 1000 #if DEBUG_PARSER
michael@0 1001 ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number);
michael@0 1002 #endif
michael@0 1003 break;
michael@0 1004 case PROPERTY_META: {
michael@0 1005 for (Behavior* b = key->firstBehavior; b; b = b->next) {
michael@0 1006 if (b->metaState == property.metaState) {
michael@0 1007 ALOGE("%s: Duplicate key behavior for modifier.",
michael@0 1008 mTokenizer->getLocation().string());
michael@0 1009 return BAD_VALUE;
michael@0 1010 }
michael@0 1011 }
michael@0 1012 Behavior* newBehavior = new Behavior(behavior);
michael@0 1013 newBehavior->metaState = property.metaState;
michael@0 1014 newBehavior->next = key->firstBehavior;
michael@0 1015 key->firstBehavior = newBehavior;
michael@0 1016 #if DEBUG_PARSER
michael@0 1017 ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d.", mKeyCode,
michael@0 1018 newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode);
michael@0 1019 #endif
michael@0 1020 break;
michael@0 1021 }
michael@0 1022 }
michael@0 1023 }
michael@0 1024 return NO_ERROR;
michael@0 1025 }
michael@0 1026
michael@0 1027 status_t KeyCharacterMap::Parser::finishKey(Key* key) {
michael@0 1028 // Fill in default number property.
michael@0 1029 if (!key->number) {
michael@0 1030 char16_t digit = 0;
michael@0 1031 char16_t symbol = 0;
michael@0 1032 for (Behavior* b = key->firstBehavior; b; b = b->next) {
michael@0 1033 char16_t ch = b->character;
michael@0 1034 if (ch) {
michael@0 1035 if (ch >= '0' && ch <= '9') {
michael@0 1036 digit = ch;
michael@0 1037 } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
michael@0 1038 || ch == '-' || ch == '+' || ch == ',' || ch == '.'
michael@0 1039 || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
michael@0 1040 symbol = ch;
michael@0 1041 }
michael@0 1042 }
michael@0 1043 }
michael@0 1044 key->number = digit ? digit : symbol;
michael@0 1045 }
michael@0 1046 return NO_ERROR;
michael@0 1047 }
michael@0 1048
michael@0 1049 status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) {
michael@0 1050 if (token == "base") {
michael@0 1051 *outMetaState = 0;
michael@0 1052 return NO_ERROR;
michael@0 1053 }
michael@0 1054
michael@0 1055 int32_t combinedMeta = 0;
michael@0 1056
michael@0 1057 const char* str = token.string();
michael@0 1058 const char* start = str;
michael@0 1059 for (const char* cur = str; ; cur++) {
michael@0 1060 char ch = *cur;
michael@0 1061 if (ch == '+' || ch == '\0') {
michael@0 1062 size_t len = cur - start;
michael@0 1063 int32_t metaState = 0;
michael@0 1064 for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
michael@0 1065 if (strlen(modifiers[i].label) == len
michael@0 1066 && strncmp(modifiers[i].label, start, len) == 0) {
michael@0 1067 metaState = modifiers[i].metaState;
michael@0 1068 break;
michael@0 1069 }
michael@0 1070 }
michael@0 1071 if (!metaState) {
michael@0 1072 return BAD_VALUE;
michael@0 1073 }
michael@0 1074 if (combinedMeta & metaState) {
michael@0 1075 ALOGE("%s: Duplicate modifier combination '%s'.",
michael@0 1076 mTokenizer->getLocation().string(), token.string());
michael@0 1077 return BAD_VALUE;
michael@0 1078 }
michael@0 1079
michael@0 1080 combinedMeta |= metaState;
michael@0 1081 start = cur + 1;
michael@0 1082
michael@0 1083 if (ch == '\0') {
michael@0 1084 break;
michael@0 1085 }
michael@0 1086 }
michael@0 1087 }
michael@0 1088 *outMetaState = combinedMeta;
michael@0 1089 return NO_ERROR;
michael@0 1090 }
michael@0 1091
michael@0 1092 status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
michael@0 1093 char ch = mTokenizer->nextChar();
michael@0 1094 if (ch != '\'') {
michael@0 1095 goto Error;
michael@0 1096 }
michael@0 1097
michael@0 1098 ch = mTokenizer->nextChar();
michael@0 1099 if (ch == '\\') {
michael@0 1100 // Escape sequence.
michael@0 1101 ch = mTokenizer->nextChar();
michael@0 1102 if (ch == 'n') {
michael@0 1103 *outCharacter = '\n';
michael@0 1104 } else if (ch == 't') {
michael@0 1105 *outCharacter = '\t';
michael@0 1106 } else if (ch == '\\') {
michael@0 1107 *outCharacter = '\\';
michael@0 1108 } else if (ch == '\'') {
michael@0 1109 *outCharacter = '\'';
michael@0 1110 } else if (ch == '"') {
michael@0 1111 *outCharacter = '"';
michael@0 1112 } else if (ch == 'u') {
michael@0 1113 *outCharacter = 0;
michael@0 1114 for (int i = 0; i < 4; i++) {
michael@0 1115 ch = mTokenizer->nextChar();
michael@0 1116 int digit;
michael@0 1117 if (ch >= '0' && ch <= '9') {
michael@0 1118 digit = ch - '0';
michael@0 1119 } else if (ch >= 'A' && ch <= 'F') {
michael@0 1120 digit = ch - 'A' + 10;
michael@0 1121 } else if (ch >= 'a' && ch <= 'f') {
michael@0 1122 digit = ch - 'a' + 10;
michael@0 1123 } else {
michael@0 1124 goto Error;
michael@0 1125 }
michael@0 1126 *outCharacter = (*outCharacter << 4) | digit;
michael@0 1127 }
michael@0 1128 } else {
michael@0 1129 goto Error;
michael@0 1130 }
michael@0 1131 } else if (ch >= 32 && ch <= 126 && ch != '\'') {
michael@0 1132 // ASCII literal character.
michael@0 1133 *outCharacter = ch;
michael@0 1134 } else {
michael@0 1135 goto Error;
michael@0 1136 }
michael@0 1137
michael@0 1138 ch = mTokenizer->nextChar();
michael@0 1139 if (ch != '\'') {
michael@0 1140 goto Error;
michael@0 1141 }
michael@0 1142
michael@0 1143 // Ensure that we consumed the entire token.
michael@0 1144 if (mTokenizer->nextToken(WHITESPACE).isEmpty()) {
michael@0 1145 return NO_ERROR;
michael@0 1146 }
michael@0 1147
michael@0 1148 Error:
michael@0 1149 ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string());
michael@0 1150 return BAD_VALUE;
michael@0 1151 }
michael@0 1152
michael@0 1153 } // namespace android

mercurial