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