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