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