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