1 /* 2 * Copyright (C) 2008 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 "KeyLayoutMap" 18 19 #include <stdlib.h> 20 #include <android/keycodes.h> 21 #include <ui/Keyboard.h> 22 #include <ui/KeyLayoutMap.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 // Enables debug output for mapping. 35 #define DEBUG_MAPPING 0 36 37 38 namespace android { 39 40 static const char* WHITESPACE = " \t\r"; 41 42 // --- KeyLayoutMap --- 43 44 KeyLayoutMap::KeyLayoutMap() { 45 } 46 47 KeyLayoutMap::~KeyLayoutMap() { 48 } 49 50 status_t KeyLayoutMap::load(const String8& filename, KeyLayoutMap** outMap) { 51 *outMap = NULL; 52 53 Tokenizer* tokenizer; 54 status_t status = Tokenizer::open(filename, &tokenizer); 55 if (status) { 56 LOGE("Error %d opening key layout map file %s.", status, filename.string()); 57 } else { 58 KeyLayoutMap* map = new KeyLayoutMap(); 59 if (!map) { 60 LOGE("Error allocating key layout map."); 61 status = NO_MEMORY; 62 } else { 63 #if DEBUG_PARSER_PERFORMANCE 64 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); 65 #endif 66 Parser parser(map, tokenizer); 67 status = parser.parse(); 68 #if DEBUG_PARSER_PERFORMANCE 69 nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; 70 LOGD("Parsed key layout map file '%s' %d lines in %0.3fms.", 71 tokenizer->getFilename().string(), tokenizer->getLineNumber(), 72 elapsedTime / 1000000.0); 73 #endif 74 if (status) { 75 delete map; 76 } else { 77 *outMap = map; 78 } 79 } 80 delete tokenizer; 81 } 82 return status; 83 } 84 85 status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const { 86 ssize_t index = mKeys.indexOfKey(scanCode); 87 if (index < 0) { 88 #if DEBUG_MAPPING 89 LOGD("mapKey: scanCode=%d ~ Failed.", scanCode); 90 #endif 91 *keyCode = AKEYCODE_UNKNOWN; 92 *flags = 0; 93 return NAME_NOT_FOUND; 94 } 95 96 const Key& k = mKeys.valueAt(index); 97 *keyCode = k.keyCode; 98 *flags = k.flags; 99 100 #if DEBUG_MAPPING 101 LOGD("mapKey: scanCode=%d ~ Result keyCode=%d, flags=0x%08x.", scanCode, *keyCode, *flags); 102 #endif 103 return NO_ERROR; 104 } 105 106 status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const { 107 const size_t N = mKeys.size(); 108 for (size_t i=0; i<N; i++) { 109 if (mKeys.valueAt(i).keyCode == keyCode) { 110 outScanCodes->add(mKeys.keyAt(i)); 111 } 112 } 113 return NO_ERROR; 114 } 115 116 status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const { 117 ssize_t index = mAxes.indexOfKey(scanCode); 118 if (index < 0) { 119 #if DEBUG_MAPPING 120 LOGD("mapAxis: scanCode=%d ~ Failed.", scanCode); 121 #endif 122 return NAME_NOT_FOUND; 123 } 124 125 *outAxisInfo = mAxes.valueAt(index); 126 127 #if DEBUG_MAPPING 128 LOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, " 129 "splitValue=%d, flatOverride=%d.", 130 scanCode, 131 outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis, 132 outAxisInfo->splitValue, outAxisInfo->flatOverride); 133 #endif 134 return NO_ERROR; 135 } 136 137 138 // --- KeyLayoutMap::Parser --- 139 140 KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) : 141 mMap(map), mTokenizer(tokenizer) { 142 } 143 144 KeyLayoutMap::Parser::~Parser() { 145 } 146 147 status_t KeyLayoutMap::Parser::parse() { 148 while (!mTokenizer->isEof()) { 149 #if DEBUG_PARSER 150 LOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), 151 mTokenizer->peekRemainderOfLine().string()); 152 #endif 153 154 mTokenizer->skipDelimiters(WHITESPACE); 155 156 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { 157 String8 keywordToken = mTokenizer->nextToken(WHITESPACE); 158 if (keywordToken == "key") { 159 mTokenizer->skipDelimiters(WHITESPACE); 160 status_t status = parseKey(); 161 if (status) return status; 162 } else if (keywordToken == "axis") { 163 mTokenizer->skipDelimiters(WHITESPACE); 164 status_t status = parseAxis(); 165 if (status) return status; 166 } else { 167 LOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), 168 keywordToken.string()); 169 return BAD_VALUE; 170 } 171 172 mTokenizer->skipDelimiters(WHITESPACE); 173 if (!mTokenizer->isEol()) { 174 LOGE("%s: Expected end of line, got '%s'.", 175 mTokenizer->getLocation().string(), 176 mTokenizer->peekRemainderOfLine().string()); 177 return BAD_VALUE; 178 } 179 } 180 181 mTokenizer->nextLine(); 182 } 183 return NO_ERROR; 184 } 185 186 status_t KeyLayoutMap::Parser::parseKey() { 187 String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE); 188 char* end; 189 int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0)); 190 if (*end) { 191 LOGE("%s: Expected key scan code number, got '%s'.", mTokenizer->getLocation().string(), 192 scanCodeToken.string()); 193 return BAD_VALUE; 194 } 195 if (mMap->mKeys.indexOfKey(scanCode) >= 0) { 196 LOGE("%s: Duplicate entry for key scan code '%s'.", mTokenizer->getLocation().string(), 197 scanCodeToken.string()); 198 return BAD_VALUE; 199 } 200 201 mTokenizer->skipDelimiters(WHITESPACE); 202 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); 203 int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); 204 if (!keyCode) { 205 LOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), 206 keyCodeToken.string()); 207 return BAD_VALUE; 208 } 209 210 uint32_t flags = 0; 211 for (;;) { 212 mTokenizer->skipDelimiters(WHITESPACE); 213 if (mTokenizer->isEol()) break; 214 215 String8 flagToken = mTokenizer->nextToken(WHITESPACE); 216 uint32_t flag = getKeyFlagByLabel(flagToken.string()); 217 if (!flag) { 218 LOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(), 219 flagToken.string()); 220 return BAD_VALUE; 221 } 222 if (flags & flag) { 223 LOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(), 224 flagToken.string()); 225 return BAD_VALUE; 226 } 227 flags |= flag; 228 } 229 230 #if DEBUG_PARSER 231 LOGD("Parsed key: scanCode=%d, keyCode=%d, flags=0x%08x.", scanCode, keyCode, flags); 232 #endif 233 Key key; 234 key.keyCode = keyCode; 235 key.flags = flags; 236 mMap->mKeys.add(scanCode, key); 237 return NO_ERROR; 238 } 239 240 status_t KeyLayoutMap::Parser::parseAxis() { 241 String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE); 242 char* end; 243 int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0)); 244 if (*end) { 245 LOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(), 246 scanCodeToken.string()); 247 return BAD_VALUE; 248 } 249 if (mMap->mAxes.indexOfKey(scanCode) >= 0) { 250 LOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(), 251 scanCodeToken.string()); 252 return BAD_VALUE; 253 } 254 255 AxisInfo axisInfo; 256 257 mTokenizer->skipDelimiters(WHITESPACE); 258 String8 token = mTokenizer->nextToken(WHITESPACE); 259 if (token == "invert") { 260 axisInfo.mode = AxisInfo::MODE_INVERT; 261 262 mTokenizer->skipDelimiters(WHITESPACE); 263 String8 axisToken = mTokenizer->nextToken(WHITESPACE); 264 axisInfo.axis = getAxisByLabel(axisToken.string()); 265 if (axisInfo.axis < 0) { 266 LOGE("%s: Expected inverted axis label, got '%s'.", 267 mTokenizer->getLocation().string(), axisToken.string()); 268 return BAD_VALUE; 269 } 270 } else if (token == "split") { 271 axisInfo.mode = AxisInfo::MODE_SPLIT; 272 273 mTokenizer->skipDelimiters(WHITESPACE); 274 String8 splitToken = mTokenizer->nextToken(WHITESPACE); 275 axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0)); 276 if (*end) { 277 LOGE("%s: Expected split value, got '%s'.", 278 mTokenizer->getLocation().string(), splitToken.string()); 279 return BAD_VALUE; 280 } 281 282 mTokenizer->skipDelimiters(WHITESPACE); 283 String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE); 284 axisInfo.axis = getAxisByLabel(lowAxisToken.string()); 285 if (axisInfo.axis < 0) { 286 LOGE("%s: Expected low axis label, got '%s'.", 287 mTokenizer->getLocation().string(), lowAxisToken.string()); 288 return BAD_VALUE; 289 } 290 291 mTokenizer->skipDelimiters(WHITESPACE); 292 String8 highAxisToken = mTokenizer->nextToken(WHITESPACE); 293 axisInfo.highAxis = getAxisByLabel(highAxisToken.string()); 294 if (axisInfo.highAxis < 0) { 295 LOGE("%s: Expected high axis label, got '%s'.", 296 mTokenizer->getLocation().string(), highAxisToken.string()); 297 return BAD_VALUE; 298 } 299 } else { 300 axisInfo.axis = getAxisByLabel(token.string()); 301 if (axisInfo.axis < 0) { 302 LOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.", 303 mTokenizer->getLocation().string(), token.string()); 304 return BAD_VALUE; 305 } 306 } 307 308 for (;;) { 309 mTokenizer->skipDelimiters(WHITESPACE); 310 if (mTokenizer->isEol()) { 311 break; 312 } 313 String8 keywordToken = mTokenizer->nextToken(WHITESPACE); 314 if (keywordToken == "flat") { 315 mTokenizer->skipDelimiters(WHITESPACE); 316 String8 flatToken = mTokenizer->nextToken(WHITESPACE); 317 axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0)); 318 if (*end) { 319 LOGE("%s: Expected flat value, got '%s'.", 320 mTokenizer->getLocation().string(), flatToken.string()); 321 return BAD_VALUE; 322 } 323 } else { 324 LOGE("%s: Expected keyword 'flat', got '%s'.", 325 mTokenizer->getLocation().string(), keywordToken.string()); 326 return BAD_VALUE; 327 } 328 } 329 330 #if DEBUG_PARSER 331 LOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, " 332 "splitValue=%d, flatOverride=%d.", 333 scanCode, 334 axisInfo.mode, axisInfo.axis, axisInfo.highAxis, 335 axisInfo.splitValue, axisInfo.flatOverride); 336 #endif 337 mMap->mAxes.add(scanCode, axisInfo); 338 return NO_ERROR; 339 } 340 341 }; 342