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