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