Home | History | Annotate | Download | only in input
      1 /*
      2  * Copyright (C) 2010 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 "VirtualKeyMap"
     18 
     19 #include <stdlib.h>
     20 #include <string.h>
     21 
     22 #include <input/VirtualKeyMap.h>
     23 #include <utils/Log.h>
     24 #include <utils/Errors.h>
     25 #include <utils/Tokenizer.h>
     26 #include <utils/Timers.h>
     27 
     28 // Enables debug output for the parser.
     29 #define DEBUG_PARSER 0
     30 
     31 // Enables debug output for parser performance.
     32 #define DEBUG_PARSER_PERFORMANCE 0
     33 
     34 
     35 namespace android {
     36 
     37 static const char* WHITESPACE = " \t\r";
     38 static const char* WHITESPACE_OR_FIELD_DELIMITER = " \t\r:";
     39 
     40 
     41 // --- VirtualKeyMap ---
     42 
     43 VirtualKeyMap::VirtualKeyMap() {
     44 }
     45 
     46 VirtualKeyMap::~VirtualKeyMap() {
     47 }
     48 
     49 status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) {
     50     *outMap = NULL;
     51 
     52     Tokenizer* tokenizer;
     53     status_t status = Tokenizer::open(filename, &tokenizer);
     54     if (status) {
     55         ALOGE("Error %d opening virtual key map file %s.", status, filename.string());
     56     } else {
     57         VirtualKeyMap* map = new VirtualKeyMap();
     58         if (!map) {
     59             ALOGE("Error allocating virtual key map.");
     60             status = NO_MEMORY;
     61         } else {
     62 #if DEBUG_PARSER_PERFORMANCE
     63             nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
     64 #endif
     65             Parser parser(map, tokenizer);
     66             status = parser.parse();
     67 #if DEBUG_PARSER_PERFORMANCE
     68             nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
     69             ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
     70                     tokenizer->getFilename().string(), tokenizer->getLineNumber(),
     71                     elapsedTime / 1000000.0);
     72 #endif
     73             if (status) {
     74                 delete map;
     75             } else {
     76                 *outMap = map;
     77             }
     78         }
     79         delete tokenizer;
     80     }
     81     return status;
     82 }
     83 
     84 
     85 // --- VirtualKeyMap::Parser ---
     86 
     87 VirtualKeyMap::Parser::Parser(VirtualKeyMap* map, Tokenizer* tokenizer) :
     88         mMap(map), mTokenizer(tokenizer) {
     89 }
     90 
     91 VirtualKeyMap::Parser::~Parser() {
     92 }
     93 
     94 status_t VirtualKeyMap::Parser::parse() {
     95     while (!mTokenizer->isEof()) {
     96 #if DEBUG_PARSER
     97         ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
     98                 mTokenizer->peekRemainderOfLine().string());
     99 #endif
    100 
    101         mTokenizer->skipDelimiters(WHITESPACE);
    102 
    103         if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
    104             // Multiple keys can appear on one line or they can be broken up across multiple lines.
    105             do {
    106                 String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
    107                 if (token != "0x01") {
    108                     ALOGE("%s: Unknown virtual key type, expected 0x01.",
    109                           mTokenizer->getLocation().string());
    110                     return BAD_VALUE;
    111                 }
    112 
    113                 VirtualKeyDefinition defn;
    114                 bool success = parseNextIntField(&defn.scanCode)
    115                         && parseNextIntField(&defn.centerX)
    116                         && parseNextIntField(&defn.centerY)
    117                         && parseNextIntField(&defn.width)
    118                         && parseNextIntField(&defn.height);
    119                 if (!success) {
    120                     ALOGE("%s: Expected 5 colon-delimited integers in virtual key definition.",
    121                           mTokenizer->getLocation().string());
    122                     return BAD_VALUE;
    123                 }
    124 
    125 #if DEBUG_PARSER
    126                 ALOGD("Parsed virtual key: scanCode=%d, centerX=%d, centerY=%d, "
    127                         "width=%d, height=%d",
    128                         defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height);
    129 #endif
    130                 mMap->mVirtualKeys.push(defn);
    131             } while (consumeFieldDelimiterAndSkipWhitespace());
    132 
    133             if (!mTokenizer->isEol()) {
    134                 ALOGE("%s: Expected end of line, got '%s'.",
    135                         mTokenizer->getLocation().string(),
    136                         mTokenizer->peekRemainderOfLine().string());
    137                 return BAD_VALUE;
    138             }
    139         }
    140 
    141         mTokenizer->nextLine();
    142     }
    143 
    144     return NO_ERROR;
    145 }
    146 
    147 bool VirtualKeyMap::Parser::consumeFieldDelimiterAndSkipWhitespace() {
    148     mTokenizer->skipDelimiters(WHITESPACE);
    149     if (mTokenizer->peekChar() == ':') {
    150         mTokenizer->nextChar();
    151         mTokenizer->skipDelimiters(WHITESPACE);
    152         return true;
    153     }
    154     return false;
    155 }
    156 
    157 bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) {
    158     if (!consumeFieldDelimiterAndSkipWhitespace()) {
    159         return false;
    160     }
    161 
    162     String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
    163     char* end;
    164     *outValue = strtol(token.string(), &end, 0);
    165     if (token.isEmpty() || *end != '\0') {
    166         ALOGE("Expected an integer, got '%s'.", token.string());
    167         return false;
    168     }
    169     return true;
    170 }
    171 
    172 } // namespace android
    173