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 #include <android/keycodes.h> 22 #include <ui/Keyboard.h> 23 #include <ui/KeyCharacterMap.h> 24 #include <utils/Log.h> 25 #include <utils/Errors.h> 26 #include <utils/Tokenizer.h> 27 #include <utils/Timers.h> 28 29 // Enables debug output for the parser. 30 #define DEBUG_PARSER 0 31 32 // Enables debug output for parser performance. 33 #define DEBUG_PARSER_PERFORMANCE 0 34 35 // Enables debug output for mapping. 36 #define DEBUG_MAPPING 0 37 38 39 namespace android { 40 41 static const char* WHITESPACE = " \t\r"; 42 static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:"; 43 44 struct Modifier { 45 const char* label; 46 int32_t metaState; 47 }; 48 static const Modifier modifiers[] = { 49 { "shift", AMETA_SHIFT_ON }, 50 { "lshift", AMETA_SHIFT_LEFT_ON }, 51 { "rshift", AMETA_SHIFT_RIGHT_ON }, 52 { "alt", AMETA_ALT_ON }, 53 { "lalt", AMETA_ALT_LEFT_ON }, 54 { "ralt", AMETA_ALT_RIGHT_ON }, 55 { "ctrl", AMETA_CTRL_ON }, 56 { "lctrl", AMETA_CTRL_LEFT_ON }, 57 { "rctrl", AMETA_CTRL_RIGHT_ON }, 58 { "meta", AMETA_META_ON }, 59 { "lmeta", AMETA_META_LEFT_ON }, 60 { "rmeta", AMETA_META_RIGHT_ON }, 61 { "sym", AMETA_SYM_ON }, 62 { "fn", AMETA_FUNCTION_ON }, 63 { "capslock", AMETA_CAPS_LOCK_ON }, 64 { "numlock", AMETA_NUM_LOCK_ON }, 65 { "scrolllock", AMETA_SCROLL_LOCK_ON }, 66 }; 67 68 #if DEBUG_MAPPING 69 static String8 toString(const char16_t* chars, size_t numChars) { 70 String8 result; 71 for (size_t i = 0; i < numChars; i++) { 72 result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]); 73 } 74 return result; 75 } 76 #endif 77 78 79 // --- KeyCharacterMap --- 80 81 KeyCharacterMap::KeyCharacterMap() : 82 mType(KEYBOARD_TYPE_UNKNOWN) { 83 } 84 85 KeyCharacterMap::~KeyCharacterMap() { 86 for (size_t i = 0; i < mKeys.size(); i++) { 87 Key* key = mKeys.editValueAt(i); 88 delete key; 89 } 90 } 91 92 status_t KeyCharacterMap::load(const String8& filename, KeyCharacterMap** outMap) { 93 *outMap = NULL; 94 95 Tokenizer* tokenizer; 96 status_t status = Tokenizer::open(filename, &tokenizer); 97 if (status) { 98 LOGE("Error %d opening key character map file %s.", status, filename.string()); 99 } else { 100 KeyCharacterMap* map = new KeyCharacterMap(); 101 if (!map) { 102 LOGE("Error allocating key character map."); 103 status = NO_MEMORY; 104 } else { 105 #if DEBUG_PARSER_PERFORMANCE 106 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); 107 #endif 108 Parser parser(map, tokenizer); 109 status = parser.parse(); 110 #if DEBUG_PARSER_PERFORMANCE 111 nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; 112 LOGD("Parsed key character map file '%s' %d lines in %0.3fms.", 113 tokenizer->getFilename().string(), tokenizer->getLineNumber(), 114 elapsedTime / 1000000.0); 115 #endif 116 if (status) { 117 delete map; 118 } else { 119 *outMap = map; 120 } 121 } 122 delete tokenizer; 123 } 124 return status; 125 } 126 127 status_t KeyCharacterMap::loadByDeviceId(int32_t deviceId, KeyCharacterMap** outMap) { 128 *outMap = NULL; 129 130 String8 filename; 131 status_t result = getKeyCharacterMapFile(deviceId, filename); 132 if (!result) { 133 result = load(filename, outMap); 134 } 135 return result; 136 } 137 138 int32_t KeyCharacterMap::getKeyboardType() const { 139 return mType; 140 } 141 142 char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const { 143 char16_t result = 0; 144 const Key* key; 145 if (getKey(keyCode, &key)) { 146 result = key->label; 147 } 148 #if DEBUG_MAPPING 149 LOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result); 150 #endif 151 return result; 152 } 153 154 char16_t KeyCharacterMap::getNumber(int32_t keyCode) const { 155 char16_t result = 0; 156 const Key* key; 157 if (getKey(keyCode, &key)) { 158 result = key->number; 159 } 160 #if DEBUG_MAPPING 161 LOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result); 162 #endif 163 return result; 164 } 165 166 char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const { 167 char16_t result = 0; 168 const Key* key; 169 const Behavior* behavior; 170 if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { 171 result = behavior->character; 172 } 173 #if DEBUG_MAPPING 174 LOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result); 175 #endif 176 return result; 177 } 178 179 bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState, 180 FallbackAction* outFallbackAction) const { 181 outFallbackAction->keyCode = 0; 182 outFallbackAction->metaState = 0; 183 184 bool result = false; 185 const Key* key; 186 const Behavior* behavior; 187 if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { 188 if (behavior->fallbackKeyCode) { 189 outFallbackAction->keyCode = behavior->fallbackKeyCode; 190 outFallbackAction->metaState = metaState & ~behavior->metaState; 191 result = true; 192 } 193 } 194 #if DEBUG_MAPPING 195 LOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, " 196 "fallback keyCode=%d, fallback metaState=0x%08x.", 197 keyCode, metaState, result ? "true" : "false", 198 outFallbackAction->keyCode, outFallbackAction->metaState); 199 #endif 200 return result; 201 } 202 203 char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars, 204 int32_t metaState) const { 205 char16_t result = 0; 206 const Key* key; 207 if (getKey(keyCode, &key)) { 208 // Try to find the most general behavior that maps to this character. 209 // For example, the base key behavior will usually be last in the list. 210 // However, if we find a perfect meta state match for one behavior then use that one. 211 for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { 212 if (behavior->character) { 213 for (size_t i = 0; i < numChars; i++) { 214 if (behavior->character == chars[i]) { 215 result = behavior->character; 216 if ((behavior->metaState & metaState) == behavior->metaState) { 217 goto ExactMatch; 218 } 219 break; 220 } 221 } 222 } 223 } 224 ExactMatch: ; 225 } 226 #if DEBUG_MAPPING 227 LOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.", 228 keyCode, toString(chars, numChars).string(), metaState, result); 229 #endif 230 return result; 231 } 232 233 bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars, 234 Vector<KeyEvent>& outEvents) const { 235 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); 236 237 for (size_t i = 0; i < numChars; i++) { 238 int32_t keyCode, metaState; 239 char16_t ch = chars[i]; 240 if (!findKey(ch, &keyCode, &metaState)) { 241 #if DEBUG_MAPPING 242 LOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.", 243 deviceId, toString(chars, numChars).string(), ch); 244 #endif 245 return false; 246 } 247 248 int32_t currentMetaState = 0; 249 addMetaKeys(outEvents, deviceId, metaState, true, now, ¤tMetaState); 250 addKey(outEvents, deviceId, keyCode, currentMetaState, true, now); 251 addKey(outEvents, deviceId, keyCode, currentMetaState, false, now); 252 addMetaKeys(outEvents, deviceId, metaState, false, now, ¤tMetaState); 253 } 254 #if DEBUG_MAPPING 255 LOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", 256 deviceId, toString(chars, numChars).string(), int32_t(outEvents.size())); 257 for (size_t i = 0; i < outEvents.size(); i++) { 258 LOGD(" Key: keyCode=%d, metaState=0x%08x, %s.", 259 outEvents[i].getKeyCode(), outEvents[i].getMetaState(), 260 outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up"); 261 } 262 #endif 263 return true; 264 } 265 266 bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const { 267 ssize_t index = mKeys.indexOfKey(keyCode); 268 if (index >= 0) { 269 *outKey = mKeys.valueAt(index); 270 return true; 271 } 272 return false; 273 } 274 275 bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState, 276 const Key** outKey, const Behavior** outBehavior) const { 277 const Key* key; 278 if (getKey(keyCode, &key)) { 279 const Behavior* behavior = key->firstBehavior; 280 while (behavior) { 281 if ((behavior->metaState & metaState) == behavior->metaState) { 282 *outKey = key; 283 *outBehavior = behavior; 284 return true; 285 } 286 behavior = behavior->next; 287 } 288 } 289 return false; 290 } 291 292 bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const { 293 if (!ch) { 294 return false; 295 } 296 297 for (size_t i = 0; i < mKeys.size(); i++) { 298 const Key* key = mKeys.valueAt(i); 299 300 // Try to find the most general behavior that maps to this character. 301 // For example, the base key behavior will usually be last in the list. 302 const Behavior* found = NULL; 303 for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { 304 if (behavior->character == ch) { 305 found = behavior; 306 } 307 } 308 if (found) { 309 *outKeyCode = mKeys.keyAt(i); 310 *outMetaState = found->metaState; 311 return true; 312 } 313 } 314 return false; 315 } 316 317 void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents, 318 int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) { 319 outEvents.push(); 320 KeyEvent& event = outEvents.editTop(); 321 event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD, 322 down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 323 0, keyCode, 0, metaState, 0, time, time); 324 } 325 326 void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents, 327 int32_t deviceId, int32_t metaState, bool down, nsecs_t time, 328 int32_t* currentMetaState) { 329 // Add and remove meta keys symmetrically. 330 if (down) { 331 addLockedMetaKey(outEvents, deviceId, metaState, time, 332 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState); 333 addLockedMetaKey(outEvents, deviceId, metaState, time, 334 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState); 335 addLockedMetaKey(outEvents, deviceId, metaState, time, 336 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState); 337 338 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, 339 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON, 340 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON, 341 AMETA_SHIFT_ON, currentMetaState); 342 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, 343 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON, 344 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON, 345 AMETA_ALT_ON, currentMetaState); 346 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, 347 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON, 348 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON, 349 AMETA_CTRL_ON, currentMetaState); 350 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, 351 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON, 352 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON, 353 AMETA_META_ON, currentMetaState); 354 355 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, 356 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState); 357 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, 358 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState); 359 } else { 360 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, 361 AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState); 362 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, 363 AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState); 364 365 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, 366 AKEYCODE_META_LEFT, AMETA_META_LEFT_ON, 367 AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON, 368 AMETA_META_ON, currentMetaState); 369 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, 370 AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON, 371 AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON, 372 AMETA_CTRL_ON, currentMetaState); 373 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, 374 AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON, 375 AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON, 376 AMETA_ALT_ON, currentMetaState); 377 addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, 378 AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON, 379 AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON, 380 AMETA_SHIFT_ON, currentMetaState); 381 382 addLockedMetaKey(outEvents, deviceId, metaState, time, 383 AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState); 384 addLockedMetaKey(outEvents, deviceId, metaState, time, 385 AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState); 386 addLockedMetaKey(outEvents, deviceId, metaState, time, 387 AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState); 388 } 389 } 390 391 bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents, 392 int32_t deviceId, int32_t metaState, bool down, nsecs_t time, 393 int32_t keyCode, int32_t keyMetaState, 394 int32_t* currentMetaState) { 395 if ((metaState & keyMetaState) == keyMetaState) { 396 *currentMetaState = updateMetaState(keyCode, down, *currentMetaState); 397 addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time); 398 return true; 399 } 400 return false; 401 } 402 403 void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents, 404 int32_t deviceId, int32_t metaState, bool down, nsecs_t time, 405 int32_t leftKeyCode, int32_t leftKeyMetaState, 406 int32_t rightKeyCode, int32_t rightKeyMetaState, 407 int32_t eitherKeyMetaState, 408 int32_t* currentMetaState) { 409 bool specific = false; 410 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, 411 leftKeyCode, leftKeyMetaState, currentMetaState); 412 specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, 413 rightKeyCode, rightKeyMetaState, currentMetaState); 414 415 if (!specific) { 416 addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, 417 leftKeyCode, eitherKeyMetaState, currentMetaState); 418 } 419 } 420 421 void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents, 422 int32_t deviceId, int32_t metaState, nsecs_t time, 423 int32_t keyCode, int32_t keyMetaState, 424 int32_t* currentMetaState) { 425 if ((metaState & keyMetaState) == keyMetaState) { 426 *currentMetaState = updateMetaState(keyCode, true, *currentMetaState); 427 addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time); 428 *currentMetaState = updateMetaState(keyCode, false, *currentMetaState); 429 addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time); 430 } 431 } 432 433 434 // --- KeyCharacterMap::Key --- 435 436 KeyCharacterMap::Key::Key() : 437 label(0), number(0), firstBehavior(NULL) { 438 } 439 440 KeyCharacterMap::Key::~Key() { 441 Behavior* behavior = firstBehavior; 442 while (behavior) { 443 Behavior* next = behavior->next; 444 delete behavior; 445 behavior = next; 446 } 447 } 448 449 450 // --- KeyCharacterMap::Behavior --- 451 452 KeyCharacterMap::Behavior::Behavior() : 453 next(NULL), metaState(0), character(0), fallbackKeyCode(0) { 454 } 455 456 457 // --- KeyCharacterMap::Parser --- 458 459 KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer) : 460 mMap(map), mTokenizer(tokenizer), mState(STATE_TOP) { 461 } 462 463 KeyCharacterMap::Parser::~Parser() { 464 } 465 466 status_t KeyCharacterMap::Parser::parse() { 467 while (!mTokenizer->isEof()) { 468 #if DEBUG_PARSER 469 LOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), 470 mTokenizer->peekRemainderOfLine().string()); 471 #endif 472 473 mTokenizer->skipDelimiters(WHITESPACE); 474 475 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { 476 switch (mState) { 477 case STATE_TOP: { 478 String8 keywordToken = mTokenizer->nextToken(WHITESPACE); 479 if (keywordToken == "type") { 480 mTokenizer->skipDelimiters(WHITESPACE); 481 status_t status = parseType(); 482 if (status) return status; 483 } else if (keywordToken == "key") { 484 mTokenizer->skipDelimiters(WHITESPACE); 485 status_t status = parseKey(); 486 if (status) return status; 487 } else { 488 LOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), 489 keywordToken.string()); 490 return BAD_VALUE; 491 } 492 break; 493 } 494 495 case STATE_KEY: { 496 status_t status = parseKeyProperty(); 497 if (status) return status; 498 break; 499 } 500 } 501 502 mTokenizer->skipDelimiters(WHITESPACE); 503 if (!mTokenizer->isEol()) { 504 LOGE("%s: Expected end of line, got '%s'.", 505 mTokenizer->getLocation().string(), 506 mTokenizer->peekRemainderOfLine().string()); 507 return BAD_VALUE; 508 } 509 } 510 511 mTokenizer->nextLine(); 512 } 513 514 if (mState != STATE_TOP) { 515 LOGE("%s: Unterminated key description at end of file.", 516 mTokenizer->getLocation().string()); 517 return BAD_VALUE; 518 } 519 520 if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) { 521 LOGE("%s: Missing required keyboard 'type' declaration.", 522 mTokenizer->getLocation().string()); 523 return BAD_VALUE; 524 } 525 526 return NO_ERROR; 527 } 528 529 status_t KeyCharacterMap::Parser::parseType() { 530 if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) { 531 LOGE("%s: Duplicate keyboard 'type' declaration.", 532 mTokenizer->getLocation().string()); 533 return BAD_VALUE; 534 } 535 536 KeyboardType type; 537 String8 typeToken = mTokenizer->nextToken(WHITESPACE); 538 if (typeToken == "NUMERIC") { 539 type = KEYBOARD_TYPE_NUMERIC; 540 } else if (typeToken == "PREDICTIVE") { 541 type = KEYBOARD_TYPE_PREDICTIVE; 542 } else if (typeToken == "ALPHA") { 543 type = KEYBOARD_TYPE_ALPHA; 544 } else if (typeToken == "FULL") { 545 type = KEYBOARD_TYPE_FULL; 546 } else if (typeToken == "SPECIAL_FUNCTION") { 547 type = KEYBOARD_TYPE_SPECIAL_FUNCTION; 548 } else { 549 LOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(), 550 typeToken.string()); 551 return BAD_VALUE; 552 } 553 554 #if DEBUG_PARSER 555 LOGD("Parsed type: type=%d.", type); 556 #endif 557 mMap->mType = type; 558 return NO_ERROR; 559 } 560 561 status_t KeyCharacterMap::Parser::parseKey() { 562 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); 563 int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); 564 if (!keyCode) { 565 LOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), 566 keyCodeToken.string()); 567 return BAD_VALUE; 568 } 569 if (mMap->mKeys.indexOfKey(keyCode) >= 0) { 570 LOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(), 571 keyCodeToken.string()); 572 return BAD_VALUE; 573 } 574 575 mTokenizer->skipDelimiters(WHITESPACE); 576 String8 openBraceToken = mTokenizer->nextToken(WHITESPACE); 577 if (openBraceToken != "{") { 578 LOGE("%s: Expected '{' after key code label, got '%s'.", 579 mTokenizer->getLocation().string(), openBraceToken.string()); 580 return BAD_VALUE; 581 } 582 583 #if DEBUG_PARSER 584 LOGD("Parsed beginning of key: keyCode=%d.", keyCode); 585 #endif 586 mKeyCode = keyCode; 587 mMap->mKeys.add(keyCode, new Key()); 588 mState = STATE_KEY; 589 return NO_ERROR; 590 } 591 592 status_t KeyCharacterMap::Parser::parseKeyProperty() { 593 String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); 594 if (token == "}") { 595 mState = STATE_TOP; 596 return NO_ERROR; 597 } 598 599 Vector<Property> properties; 600 601 // Parse all comma-delimited property names up to the first colon. 602 for (;;) { 603 if (token == "label") { 604 properties.add(Property(PROPERTY_LABEL)); 605 } else if (token == "number") { 606 properties.add(Property(PROPERTY_NUMBER)); 607 } else { 608 int32_t metaState; 609 status_t status = parseModifier(token, &metaState); 610 if (status) { 611 LOGE("%s: Expected a property name or modifier, got '%s'.", 612 mTokenizer->getLocation().string(), token.string()); 613 return status; 614 } 615 properties.add(Property(PROPERTY_META, metaState)); 616 } 617 618 mTokenizer->skipDelimiters(WHITESPACE); 619 if (!mTokenizer->isEol()) { 620 char ch = mTokenizer->nextChar(); 621 if (ch == ':') { 622 break; 623 } else if (ch == ',') { 624 mTokenizer->skipDelimiters(WHITESPACE); 625 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); 626 continue; 627 } 628 } 629 630 LOGE("%s: Expected ',' or ':' after property name.", 631 mTokenizer->getLocation().string()); 632 return BAD_VALUE; 633 } 634 635 // Parse behavior after the colon. 636 mTokenizer->skipDelimiters(WHITESPACE); 637 638 Behavior behavior; 639 bool haveCharacter = false; 640 bool haveFallback = false; 641 642 do { 643 char ch = mTokenizer->peekChar(); 644 if (ch == '\'') { 645 char16_t character; 646 status_t status = parseCharacterLiteral(&character); 647 if (status || !character) { 648 LOGE("%s: Invalid character literal for key.", 649 mTokenizer->getLocation().string()); 650 return BAD_VALUE; 651 } 652 if (haveCharacter) { 653 LOGE("%s: Cannot combine multiple character literals or 'none'.", 654 mTokenizer->getLocation().string()); 655 return BAD_VALUE; 656 } 657 behavior.character = character; 658 haveCharacter = true; 659 } else { 660 token = mTokenizer->nextToken(WHITESPACE); 661 if (token == "none") { 662 if (haveCharacter) { 663 LOGE("%s: Cannot combine multiple character literals or 'none'.", 664 mTokenizer->getLocation().string()); 665 return BAD_VALUE; 666 } 667 haveCharacter = true; 668 } else if (token == "fallback") { 669 mTokenizer->skipDelimiters(WHITESPACE); 670 token = mTokenizer->nextToken(WHITESPACE); 671 int32_t keyCode = getKeyCodeByLabel(token.string()); 672 if (!keyCode) { 673 LOGE("%s: Invalid key code label for fallback behavior, got '%s'.", 674 mTokenizer->getLocation().string(), 675 token.string()); 676 return BAD_VALUE; 677 } 678 if (haveFallback) { 679 LOGE("%s: Cannot combine multiple fallback key codes.", 680 mTokenizer->getLocation().string()); 681 return BAD_VALUE; 682 } 683 behavior.fallbackKeyCode = keyCode; 684 haveFallback = true; 685 } else { 686 LOGE("%s: Expected a key behavior after ':'.", 687 mTokenizer->getLocation().string()); 688 return BAD_VALUE; 689 } 690 } 691 692 mTokenizer->skipDelimiters(WHITESPACE); 693 } while (!mTokenizer->isEol()); 694 695 // Add the behavior. 696 Key* key = mMap->mKeys.valueFor(mKeyCode); 697 for (size_t i = 0; i < properties.size(); i++) { 698 const Property& property = properties.itemAt(i); 699 switch (property.property) { 700 case PROPERTY_LABEL: 701 if (key->label) { 702 LOGE("%s: Duplicate label for key.", 703 mTokenizer->getLocation().string()); 704 return BAD_VALUE; 705 } 706 key->label = behavior.character; 707 #if DEBUG_PARSER 708 LOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label); 709 #endif 710 break; 711 case PROPERTY_NUMBER: 712 if (key->number) { 713 LOGE("%s: Duplicate number for key.", 714 mTokenizer->getLocation().string()); 715 return BAD_VALUE; 716 } 717 key->number = behavior.character; 718 #if DEBUG_PARSER 719 LOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number); 720 #endif 721 break; 722 case PROPERTY_META: { 723 for (Behavior* b = key->firstBehavior; b; b = b->next) { 724 if (b->metaState == property.metaState) { 725 LOGE("%s: Duplicate key behavior for modifier.", 726 mTokenizer->getLocation().string()); 727 return BAD_VALUE; 728 } 729 } 730 Behavior* newBehavior = new Behavior(behavior); 731 newBehavior->metaState = property.metaState; 732 newBehavior->next = key->firstBehavior; 733 key->firstBehavior = newBehavior; 734 #if DEBUG_PARSER 735 LOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d.", mKeyCode, 736 newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode); 737 #endif 738 break; 739 } 740 } 741 } 742 return NO_ERROR; 743 } 744 745 status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) { 746 if (token == "base") { 747 *outMetaState = 0; 748 return NO_ERROR; 749 } 750 751 int32_t combinedMeta = 0; 752 753 const char* str = token.string(); 754 const char* start = str; 755 for (const char* cur = str; ; cur++) { 756 char ch = *cur; 757 if (ch == '+' || ch == '\0') { 758 size_t len = cur - start; 759 int32_t metaState = 0; 760 for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) { 761 if (strlen(modifiers[i].label) == len 762 && strncmp(modifiers[i].label, start, len) == 0) { 763 metaState = modifiers[i].metaState; 764 break; 765 } 766 } 767 if (!metaState) { 768 return BAD_VALUE; 769 } 770 if (combinedMeta & metaState) { 771 LOGE("%s: Duplicate modifier combination '%s'.", 772 mTokenizer->getLocation().string(), token.string()); 773 return BAD_VALUE; 774 } 775 776 combinedMeta |= metaState; 777 start = cur + 1; 778 779 if (ch == '\0') { 780 break; 781 } 782 } 783 } 784 *outMetaState = combinedMeta; 785 return NO_ERROR; 786 } 787 788 status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) { 789 char ch = mTokenizer->nextChar(); 790 if (ch != '\'') { 791 goto Error; 792 } 793 794 ch = mTokenizer->nextChar(); 795 if (ch == '\\') { 796 // Escape sequence. 797 ch = mTokenizer->nextChar(); 798 if (ch == 'n') { 799 *outCharacter = '\n'; 800 } else if (ch == 't') { 801 *outCharacter = '\t'; 802 } else if (ch == '\\') { 803 *outCharacter = '\\'; 804 } else if (ch == '\'') { 805 *outCharacter = '\''; 806 } else if (ch == '"') { 807 *outCharacter = '"'; 808 } else if (ch == 'u') { 809 *outCharacter = 0; 810 for (int i = 0; i < 4; i++) { 811 ch = mTokenizer->nextChar(); 812 int digit; 813 if (ch >= '0' && ch <= '9') { 814 digit = ch - '0'; 815 } else if (ch >= 'A' && ch <= 'F') { 816 digit = ch - 'A' + 10; 817 } else if (ch >= 'a' && ch <= 'f') { 818 digit = ch - 'a' + 10; 819 } else { 820 goto Error; 821 } 822 *outCharacter = (*outCharacter << 4) | digit; 823 } 824 } else { 825 goto Error; 826 } 827 } else if (ch >= 32 && ch <= 126 && ch != '\'') { 828 // ASCII literal character. 829 *outCharacter = ch; 830 } else { 831 goto Error; 832 } 833 834 ch = mTokenizer->nextChar(); 835 if (ch != '\'') { 836 goto Error; 837 } 838 839 // Ensure that we consumed the entire token. 840 if (mTokenizer->nextToken(WHITESPACE).isEmpty()) { 841 return NO_ERROR; 842 } 843 844 Error: 845 LOGE("%s: Malformed character literal.", mTokenizer->getLocation().string()); 846 return BAD_VALUE; 847 } 848 849 } // namespace android 850