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 <androidfw/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 34namespace android { 35 36static const char* WHITESPACE = " \t\r"; 37static const char* WHITESPACE_OR_FIELD_DELIMITER = " \t\r:"; 38 39 40// --- VirtualKeyMap --- 41 42VirtualKeyMap::VirtualKeyMap() { 43} 44 45VirtualKeyMap::~VirtualKeyMap() { 46} 47 48status_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 ALOGE("Error %d opening virtual key map file %s.", status, filename.string()); 55 } else { 56 VirtualKeyMap* map = new VirtualKeyMap(); 57 if (!map) { 58 ALOGE("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 ALOGD("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 86VirtualKeyMap::Parser::Parser(VirtualKeyMap* map, Tokenizer* tokenizer) : 87 mMap(map), mTokenizer(tokenizer) { 88} 89 90VirtualKeyMap::Parser::~Parser() { 91} 92 93status_t VirtualKeyMap::Parser::parse() { 94 while (!mTokenizer->isEof()) { 95#if DEBUG_PARSER 96 ALOGD("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 ALOGE("%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 ALOGE("%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 ALOGD("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 ALOGE("%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 146bool 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 156bool 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 ALOGE("Expected an integer, got '%s'.", token.string()); 166 return false; 167 } 168 return true; 169} 170 171} // namespace android 172