VirtualKeyMap.cpp revision 5912f95d26f77d2b6df13e1f2672e48e3f9b871c
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 35namespace android { 36 37static const char* WHITESPACE = " \t\r"; 38static const char* WHITESPACE_OR_FIELD_DELIMITER = " \t\r:"; 39 40 41// --- VirtualKeyMap --- 42 43VirtualKeyMap::VirtualKeyMap() { 44} 45 46VirtualKeyMap::~VirtualKeyMap() { 47} 48 49status_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 87VirtualKeyMap::Parser::Parser(VirtualKeyMap* map, Tokenizer* tokenizer) : 88 mMap(map), mTokenizer(tokenizer) { 89} 90 91VirtualKeyMap::Parser::~Parser() { 92} 93 94status_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 147bool 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 157bool 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