KeyLayoutMap.cpp revision 74bdd2e7ceabd3c9e74ccf7c2e6bd3dae27ca497
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 21#include <android/keycodes.h> 22#include <input/Keyboard.h> 23#include <input/KeyLayoutMap.h> 24#include <utils/Log.h> 25#include <utils/Errors.h> 26#include <utils/Tokenizer.h> 27#include <utils/Timers.h> 28 29// Enables debug output for the parser. 30#define DEBUG_PARSER 0 31 32// Enables debug output for parser performance. 33#define DEBUG_PARSER_PERFORMANCE 0 34 35// Enables debug output for mapping. 36#define DEBUG_MAPPING 0 37 38 39namespace android { 40 41static const char* WHITESPACE = " \t\r"; 42 43// --- KeyLayoutMap --- 44 45KeyLayoutMap::KeyLayoutMap() { 46} 47 48KeyLayoutMap::~KeyLayoutMap() { 49} 50 51status_t KeyLayoutMap::load(const String8& filename, sp<KeyLayoutMap>* outMap) { 52 outMap->clear(); 53 54 Tokenizer* tokenizer; 55 status_t status = Tokenizer::open(filename, &tokenizer); 56 if (status) { 57 ALOGE("Error %d opening key layout map file %s.", status, filename.string()); 58 } else { 59 sp<KeyLayoutMap> map = new KeyLayoutMap(); 60 if (!map.get()) { 61 ALOGE("Error allocating key layout map."); 62 status = NO_MEMORY; 63 } else { 64#if DEBUG_PARSER_PERFORMANCE 65 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); 66#endif 67 Parser parser(map.get(), tokenizer); 68 status = parser.parse(); 69#if DEBUG_PARSER_PERFORMANCE 70 nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; 71 ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.", 72 tokenizer->getFilename().string(), tokenizer->getLineNumber(), 73 elapsedTime / 1000000.0); 74#endif 75 if (!status) { 76 *outMap = map; 77 } 78 } 79 delete tokenizer; 80 } 81 return status; 82} 83 84status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t usageCode, 85 int32_t* outKeyCode, uint32_t* outFlags) const { 86 const Key* key = getKey(scanCode, usageCode); 87 if (!key) { 88#if DEBUG_MAPPING 89 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode); 90#endif 91 *outKeyCode = AKEYCODE_UNKNOWN; 92 *outFlags = 0; 93 return NAME_NOT_FOUND; 94 } 95 96 *outKeyCode = key->keyCode; 97 *outFlags = key->flags; 98 99#if DEBUG_MAPPING 100 ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.", 101 scanCode, usageCode, *outKeyCode, *outFlags); 102#endif 103 return NO_ERROR; 104} 105 106const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const { 107 if (usageCode) { 108 ssize_t index = mKeysByUsageCode.indexOfKey(usageCode); 109 if (index >= 0) { 110 return &mKeysByUsageCode.valueAt(index); 111 } 112 } 113 if (scanCode) { 114 ssize_t index = mKeysByScanCode.indexOfKey(scanCode); 115 if (index >= 0) { 116 return &mKeysByScanCode.valueAt(index); 117 } 118 } 119 return NULL; 120} 121 122status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const { 123 const size_t N = mKeysByScanCode.size(); 124 for (size_t i=0; i<N; i++) { 125 if (mKeysByScanCode.valueAt(i).keyCode == keyCode) { 126 outScanCodes->add(mKeysByScanCode.keyAt(i)); 127 } 128 } 129 return NO_ERROR; 130} 131 132status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const { 133 ssize_t index = mAxes.indexOfKey(scanCode); 134 if (index < 0) { 135#if DEBUG_MAPPING 136 ALOGD("mapAxis: scanCode=%d ~ Failed.", scanCode); 137#endif 138 return NAME_NOT_FOUND; 139 } 140 141 *outAxisInfo = mAxes.valueAt(index); 142 143#if DEBUG_MAPPING 144 ALOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, " 145 "splitValue=%d, flatOverride=%d.", 146 scanCode, 147 outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis, 148 outAxisInfo->splitValue, outAxisInfo->flatOverride); 149#endif 150 return NO_ERROR; 151} 152 153status_t KeyLayoutMap::findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const { 154 const size_t N = mLedsByScanCode.size(); 155 for (size_t i = 0; i < N; i++) { 156 if (mLedsByScanCode.valueAt(i).ledCode == ledCode) { 157 *outScanCode = mLedsByScanCode.keyAt(i); 158#if DEBUG_MAPPING 159 ALOGD("findScanCodeForLed: ledCode=%d, scanCode=%d.", ledCode, *outScanCode); 160#endif 161 return NO_ERROR; 162 } 163 } 164#if DEBUG_MAPPING 165 ALOGD("findScanCodeForLed: ledCode=%d ~ Not found.", ledCode); 166#endif 167 return NAME_NOT_FOUND; 168} 169 170status_t KeyLayoutMap::findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const { 171 const size_t N = mLedsByUsageCode.size(); 172 for (size_t i = 0; i < N; i++) { 173 if (mLedsByUsageCode.valueAt(i).ledCode == ledCode) { 174 *outUsageCode = mLedsByUsageCode.keyAt(i); 175#if DEBUG_MAPPING 176 ALOGD("findUsageForLed: ledCode=%d, usage=%x.", ledCode, *outUsageCode); 177#endif 178 return NO_ERROR; 179 } 180 } 181#if DEBUG_MAPPING 182 ALOGD("findUsageForLed: ledCode=%d ~ Not found.", ledCode); 183#endif 184 return NAME_NOT_FOUND; 185} 186 187 188// --- KeyLayoutMap::Parser --- 189 190KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) : 191 mMap(map), mTokenizer(tokenizer) { 192} 193 194KeyLayoutMap::Parser::~Parser() { 195} 196 197status_t KeyLayoutMap::Parser::parse() { 198 while (!mTokenizer->isEof()) { 199#if DEBUG_PARSER 200 ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), 201 mTokenizer->peekRemainderOfLine().string()); 202#endif 203 204 mTokenizer->skipDelimiters(WHITESPACE); 205 206 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { 207 String8 keywordToken = mTokenizer->nextToken(WHITESPACE); 208 if (keywordToken == "key") { 209 mTokenizer->skipDelimiters(WHITESPACE); 210 status_t status = parseKey(); 211 if (status) return status; 212 } else if (keywordToken == "axis") { 213 mTokenizer->skipDelimiters(WHITESPACE); 214 status_t status = parseAxis(); 215 if (status) return status; 216 } else if (keywordToken == "led") { 217 mTokenizer->skipDelimiters(WHITESPACE); 218 status_t status = parseLed(); 219 if (status) return status; 220 } else { 221 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), 222 keywordToken.string()); 223 return BAD_VALUE; 224 } 225 226 mTokenizer->skipDelimiters(WHITESPACE); 227 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { 228 ALOGE("%s: Expected end of line or trailing comment, got '%s'.", 229 mTokenizer->getLocation().string(), 230 mTokenizer->peekRemainderOfLine().string()); 231 return BAD_VALUE; 232 } 233 } 234 235 mTokenizer->nextLine(); 236 } 237 return NO_ERROR; 238} 239 240status_t KeyLayoutMap::Parser::parseKey() { 241 String8 codeToken = mTokenizer->nextToken(WHITESPACE); 242 bool mapUsage = false; 243 if (codeToken == "usage") { 244 mapUsage = true; 245 mTokenizer->skipDelimiters(WHITESPACE); 246 codeToken = mTokenizer->nextToken(WHITESPACE); 247 } 248 249 char* end; 250 int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); 251 if (*end) { 252 ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), 253 mapUsage ? "usage" : "scan code", codeToken.string()); 254 return BAD_VALUE; 255 } 256 KeyedVector<int32_t, Key>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; 257 if (map.indexOfKey(code) >= 0) { 258 ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), 259 mapUsage ? "usage" : "scan code", codeToken.string()); 260 return BAD_VALUE; 261 } 262 263 mTokenizer->skipDelimiters(WHITESPACE); 264 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); 265 int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); 266 if (!keyCode) { 267 ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), 268 keyCodeToken.string()); 269 return BAD_VALUE; 270 } 271 272 uint32_t flags = 0; 273 for (;;) { 274 mTokenizer->skipDelimiters(WHITESPACE); 275 if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break; 276 277 String8 flagToken = mTokenizer->nextToken(WHITESPACE); 278 uint32_t flag = getKeyFlagByLabel(flagToken.string()); 279 if (!flag) { 280 ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(), 281 flagToken.string()); 282 return BAD_VALUE; 283 } 284 if (flags & flag) { 285 ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(), 286 flagToken.string()); 287 return BAD_VALUE; 288 } 289 flags |= flag; 290 } 291 292#if DEBUG_PARSER 293 ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.", 294 mapUsage ? "usage" : "scan code", code, keyCode, flags); 295#endif 296 Key key; 297 key.keyCode = keyCode; 298 key.flags = flags; 299 map.add(code, key); 300 return NO_ERROR; 301} 302 303status_t KeyLayoutMap::Parser::parseAxis() { 304 String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE); 305 char* end; 306 int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0)); 307 if (*end) { 308 ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(), 309 scanCodeToken.string()); 310 return BAD_VALUE; 311 } 312 if (mMap->mAxes.indexOfKey(scanCode) >= 0) { 313 ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(), 314 scanCodeToken.string()); 315 return BAD_VALUE; 316 } 317 318 AxisInfo axisInfo; 319 320 mTokenizer->skipDelimiters(WHITESPACE); 321 String8 token = mTokenizer->nextToken(WHITESPACE); 322 if (token == "invert") { 323 axisInfo.mode = AxisInfo::MODE_INVERT; 324 325 mTokenizer->skipDelimiters(WHITESPACE); 326 String8 axisToken = mTokenizer->nextToken(WHITESPACE); 327 axisInfo.axis = getAxisByLabel(axisToken.string()); 328 if (axisInfo.axis < 0) { 329 ALOGE("%s: Expected inverted axis label, got '%s'.", 330 mTokenizer->getLocation().string(), axisToken.string()); 331 return BAD_VALUE; 332 } 333 } else if (token == "split") { 334 axisInfo.mode = AxisInfo::MODE_SPLIT; 335 336 mTokenizer->skipDelimiters(WHITESPACE); 337 String8 splitToken = mTokenizer->nextToken(WHITESPACE); 338 axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0)); 339 if (*end) { 340 ALOGE("%s: Expected split value, got '%s'.", 341 mTokenizer->getLocation().string(), splitToken.string()); 342 return BAD_VALUE; 343 } 344 345 mTokenizer->skipDelimiters(WHITESPACE); 346 String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE); 347 axisInfo.axis = getAxisByLabel(lowAxisToken.string()); 348 if (axisInfo.axis < 0) { 349 ALOGE("%s: Expected low axis label, got '%s'.", 350 mTokenizer->getLocation().string(), lowAxisToken.string()); 351 return BAD_VALUE; 352 } 353 354 mTokenizer->skipDelimiters(WHITESPACE); 355 String8 highAxisToken = mTokenizer->nextToken(WHITESPACE); 356 axisInfo.highAxis = getAxisByLabel(highAxisToken.string()); 357 if (axisInfo.highAxis < 0) { 358 ALOGE("%s: Expected high axis label, got '%s'.", 359 mTokenizer->getLocation().string(), highAxisToken.string()); 360 return BAD_VALUE; 361 } 362 } else { 363 axisInfo.axis = getAxisByLabel(token.string()); 364 if (axisInfo.axis < 0) { 365 ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.", 366 mTokenizer->getLocation().string(), token.string()); 367 return BAD_VALUE; 368 } 369 } 370 371 for (;;) { 372 mTokenizer->skipDelimiters(WHITESPACE); 373 if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') { 374 break; 375 } 376 String8 keywordToken = mTokenizer->nextToken(WHITESPACE); 377 if (keywordToken == "flat") { 378 mTokenizer->skipDelimiters(WHITESPACE); 379 String8 flatToken = mTokenizer->nextToken(WHITESPACE); 380 axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0)); 381 if (*end) { 382 ALOGE("%s: Expected flat value, got '%s'.", 383 mTokenizer->getLocation().string(), flatToken.string()); 384 return BAD_VALUE; 385 } 386 } else { 387 ALOGE("%s: Expected keyword 'flat', got '%s'.", 388 mTokenizer->getLocation().string(), keywordToken.string()); 389 return BAD_VALUE; 390 } 391 } 392 393#if DEBUG_PARSER 394 ALOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, " 395 "splitValue=%d, flatOverride=%d.", 396 scanCode, 397 axisInfo.mode, axisInfo.axis, axisInfo.highAxis, 398 axisInfo.splitValue, axisInfo.flatOverride); 399#endif 400 mMap->mAxes.add(scanCode, axisInfo); 401 return NO_ERROR; 402} 403 404status_t KeyLayoutMap::Parser::parseLed() { 405 String8 codeToken = mTokenizer->nextToken(WHITESPACE); 406 bool mapUsage = false; 407 if (codeToken == "usage") { 408 mapUsage = true; 409 mTokenizer->skipDelimiters(WHITESPACE); 410 codeToken = mTokenizer->nextToken(WHITESPACE); 411 } 412 char* end; 413 int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); 414 if (*end) { 415 ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().string(), 416 mapUsage ? "usage" : "scan code", codeToken.string()); 417 return BAD_VALUE; 418 } 419 420 KeyedVector<int32_t, Led>& map = mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode; 421 if (map.indexOfKey(code) >= 0) { 422 ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(), 423 mapUsage ? "usage" : "scan code", codeToken.string()); 424 return BAD_VALUE; 425 } 426 427 mTokenizer->skipDelimiters(WHITESPACE); 428 String8 ledCodeToken = mTokenizer->nextToken(WHITESPACE); 429 int32_t ledCode = getLedByLabel(ledCodeToken.string()); 430 if (ledCode < 0) { 431 ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().string(), 432 ledCodeToken.string()); 433 return BAD_VALUE; 434 } 435 436#if DEBUG_PARSER 437 ALOGD("Parsed led %s: code=%d, ledCode=%d.", 438 mapUsage ? "usage" : "scan code", code, ledCode); 439#endif 440 441 Led led; 442 led.ledCode = ledCode; 443 map.add(code, led); 444 return NO_ERROR; 445} 446}; 447