1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/gonk/libui/KeyLayoutMap.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,366 @@ 1.4 +/* 1.5 + * Copyright (C) 2008 The Android Open Source Project 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * Unless required by applicable law or agreed to in writing, software 1.14 + * distributed under the License is distributed on an "AS IS" BASIS, 1.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.16 + * See the License for the specific language governing permissions and 1.17 + * limitations under the License. 1.18 + */ 1.19 + 1.20 +#define LOG_TAG "KeyLayoutMap" 1.21 +#include "cutils_log.h" 1.22 + 1.23 +#include <stdlib.h> 1.24 +#include "android_keycodes.h" 1.25 +#include "Keyboard.h" 1.26 +#include "KeyLayoutMap.h" 1.27 +#include <utils/Errors.h> 1.28 +#include "Tokenizer.h" 1.29 +#include <utils/Timers.h> 1.30 + 1.31 +// Enables debug output for the parser. 1.32 +#define DEBUG_PARSER 0 1.33 + 1.34 +// Enables debug output for parser performance. 1.35 +#define DEBUG_PARSER_PERFORMANCE 0 1.36 + 1.37 +// Enables debug output for mapping. 1.38 +#define DEBUG_MAPPING 0 1.39 + 1.40 + 1.41 +namespace android { 1.42 + 1.43 +static const char* WHITESPACE = " \t\r"; 1.44 + 1.45 +// --- KeyLayoutMap --- 1.46 + 1.47 +KeyLayoutMap::KeyLayoutMap() { 1.48 +} 1.49 + 1.50 +KeyLayoutMap::~KeyLayoutMap() { 1.51 +} 1.52 + 1.53 +status_t KeyLayoutMap::load(const String8& filename, sp<KeyLayoutMap>* outMap) { 1.54 + outMap->clear(); 1.55 + 1.56 + Tokenizer* tokenizer; 1.57 + status_t status = Tokenizer::open(filename, &tokenizer); 1.58 + if (status) { 1.59 + ALOGE("Error %d opening key layout map file %s.", status, filename.string()); 1.60 + } else { 1.61 + sp<KeyLayoutMap> map = new KeyLayoutMap(); 1.62 + if (!map.get()) { 1.63 + ALOGE("Error allocating key layout map."); 1.64 + status = NO_MEMORY; 1.65 + } else { 1.66 +#if DEBUG_PARSER_PERFORMANCE 1.67 + nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); 1.68 +#endif 1.69 + Parser parser(map.get(), tokenizer); 1.70 + status = parser.parse(); 1.71 +#if DEBUG_PARSER_PERFORMANCE 1.72 + nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; 1.73 + ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.", 1.74 + tokenizer->getFilename().string(), tokenizer->getLineNumber(), 1.75 + elapsedTime / 1000000.0); 1.76 +#endif 1.77 + if (!status) { 1.78 + *outMap = map; 1.79 + } 1.80 + } 1.81 + delete tokenizer; 1.82 + } 1.83 + return status; 1.84 +} 1.85 + 1.86 +status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t usageCode, 1.87 + int32_t* outKeyCode, uint32_t* outFlags) const { 1.88 + const Key* key = getKey(scanCode, usageCode); 1.89 + if (!key) { 1.90 +#if DEBUG_MAPPING 1.91 + ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode); 1.92 +#endif 1.93 + *outKeyCode = AKEYCODE_UNKNOWN; 1.94 + *outFlags = 0; 1.95 + return NAME_NOT_FOUND; 1.96 + } 1.97 + 1.98 + *outKeyCode = key->keyCode; 1.99 + *outFlags = key->flags; 1.100 + 1.101 +#if DEBUG_MAPPING 1.102 + ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.", 1.103 + scanCode, usageCode, *outKeyCode, *outFlags); 1.104 +#endif 1.105 + return NO_ERROR; 1.106 +} 1.107 + 1.108 +const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const { 1.109 + if (usageCode) { 1.110 + ssize_t index = mKeysByUsageCode.indexOfKey(usageCode); 1.111 + if (index >= 0) { 1.112 + return &mKeysByUsageCode.valueAt(index); 1.113 + } 1.114 + } 1.115 + if (scanCode) { 1.116 + ssize_t index = mKeysByScanCode.indexOfKey(scanCode); 1.117 + if (index >= 0) { 1.118 + return &mKeysByScanCode.valueAt(index); 1.119 + } 1.120 + } 1.121 + return NULL; 1.122 +} 1.123 + 1.124 +status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const { 1.125 + const size_t N = mKeysByScanCode.size(); 1.126 + for (size_t i=0; i<N; i++) { 1.127 + if (mKeysByScanCode.valueAt(i).keyCode == keyCode) { 1.128 + outScanCodes->add(mKeysByScanCode.keyAt(i)); 1.129 + } 1.130 + } 1.131 + return NO_ERROR; 1.132 +} 1.133 + 1.134 +status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const { 1.135 + ssize_t index = mAxes.indexOfKey(scanCode); 1.136 + if (index < 0) { 1.137 +#if DEBUG_MAPPING 1.138 + ALOGD("mapAxis: scanCode=%d ~ Failed.", scanCode); 1.139 +#endif 1.140 + return NAME_NOT_FOUND; 1.141 + } 1.142 + 1.143 + *outAxisInfo = mAxes.valueAt(index); 1.144 + 1.145 +#if DEBUG_MAPPING 1.146 + ALOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, " 1.147 + "splitValue=%d, flatOverride=%d.", 1.148 + scanCode, 1.149 + outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis, 1.150 + outAxisInfo->splitValue, outAxisInfo->flatOverride); 1.151 +#endif 1.152 + return NO_ERROR; 1.153 +} 1.154 + 1.155 + 1.156 +// --- KeyLayoutMap::Parser --- 1.157 + 1.158 +KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) : 1.159 + mMap(map), mTokenizer(tokenizer) { 1.160 +} 1.161 + 1.162 +KeyLayoutMap::Parser::~Parser() { 1.163 +} 1.164 + 1.165 +status_t KeyLayoutMap::Parser::parse() { 1.166 + while (!mTokenizer->isEof()) { 1.167 +#if DEBUG_PARSER 1.168 + ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), 1.169 + mTokenizer->peekRemainderOfLine().string()); 1.170 +#endif 1.171 + 1.172 + mTokenizer->skipDelimiters(WHITESPACE); 1.173 + 1.174 + if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { 1.175 + String8 keywordToken = mTokenizer->nextToken(WHITESPACE); 1.176 + if (keywordToken == "key") { 1.177 + mTokenizer->skipDelimiters(WHITESPACE); 1.178 + status_t status = parseKey(); 1.179 + if (status) return status; 1.180 + } else if (keywordToken == "axis") { 1.181 + mTokenizer->skipDelimiters(WHITESPACE); 1.182 + status_t status = parseAxis(); 1.183 + if (status) return status; 1.184 + } else { 1.185 + ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), 1.186 + keywordToken.string()); 1.187 + return BAD_VALUE; 1.188 + } 1.189 + 1.190 + mTokenizer->skipDelimiters(WHITESPACE); 1.191 + if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { 1.192 + ALOGE("%s: Expected end of line or trailing comment, got '%s'.", 1.193 + mTokenizer->getLocation().string(), 1.194 + mTokenizer->peekRemainderOfLine().string()); 1.195 + return BAD_VALUE; 1.196 + } 1.197 + } 1.198 + 1.199 + mTokenizer->nextLine(); 1.200 + } 1.201 + return NO_ERROR; 1.202 +} 1.203 + 1.204 +status_t KeyLayoutMap::Parser::parseKey() { 1.205 + String8 codeToken = mTokenizer->nextToken(WHITESPACE); 1.206 + bool mapUsage = false; 1.207 + if (codeToken == "usage") { 1.208 + mapUsage = true; 1.209 + mTokenizer->skipDelimiters(WHITESPACE); 1.210 + codeToken = mTokenizer->nextToken(WHITESPACE); 1.211 + } 1.212 + 1.213 + char* end; 1.214 + int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); 1.215 + if (*end) { 1.216 + ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), 1.217 + mapUsage ? "usage" : "scan code", codeToken.string()); 1.218 + return BAD_VALUE; 1.219 + } 1.220 + KeyedVector<int32_t, Key>& map = 1.221 + mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; 1.222 + if (map.indexOfKey(code) >= 0) { 1.223 + ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), 1.224 + mapUsage ? "usage" : "scan code", codeToken.string()); 1.225 + return BAD_VALUE; 1.226 + } 1.227 + 1.228 + mTokenizer->skipDelimiters(WHITESPACE); 1.229 + String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); 1.230 + int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); 1.231 + if (!keyCode) { 1.232 + ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), 1.233 + keyCodeToken.string()); 1.234 + return BAD_VALUE; 1.235 + } 1.236 + 1.237 + uint32_t flags = 0; 1.238 + for (;;) { 1.239 + mTokenizer->skipDelimiters(WHITESPACE); 1.240 + if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break; 1.241 + 1.242 + String8 flagToken = mTokenizer->nextToken(WHITESPACE); 1.243 + uint32_t flag = getKeyFlagByLabel(flagToken.string()); 1.244 + if (!flag) { 1.245 + ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(), 1.246 + flagToken.string()); 1.247 + return BAD_VALUE; 1.248 + } 1.249 + if (flags & flag) { 1.250 + ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(), 1.251 + flagToken.string()); 1.252 + return BAD_VALUE; 1.253 + } 1.254 + flags |= flag; 1.255 + } 1.256 + 1.257 +#if DEBUG_PARSER 1.258 + ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.", 1.259 + mapUsage ? "usage" : "scan code", code, keyCode, flags); 1.260 +#endif 1.261 + Key key; 1.262 + key.keyCode = keyCode; 1.263 + key.flags = flags; 1.264 + map.add(code, key); 1.265 + return NO_ERROR; 1.266 +} 1.267 + 1.268 +status_t KeyLayoutMap::Parser::parseAxis() { 1.269 + String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE); 1.270 + char* end; 1.271 + int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0)); 1.272 + if (*end) { 1.273 + ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(), 1.274 + scanCodeToken.string()); 1.275 + return BAD_VALUE; 1.276 + } 1.277 + if (mMap->mAxes.indexOfKey(scanCode) >= 0) { 1.278 + ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(), 1.279 + scanCodeToken.string()); 1.280 + return BAD_VALUE; 1.281 + } 1.282 + 1.283 + AxisInfo axisInfo; 1.284 + 1.285 + mTokenizer->skipDelimiters(WHITESPACE); 1.286 + String8 token = mTokenizer->nextToken(WHITESPACE); 1.287 + if (token == "invert") { 1.288 + axisInfo.mode = AxisInfo::MODE_INVERT; 1.289 + 1.290 + mTokenizer->skipDelimiters(WHITESPACE); 1.291 + String8 axisToken = mTokenizer->nextToken(WHITESPACE); 1.292 + axisInfo.axis = getAxisByLabel(axisToken.string()); 1.293 + if (axisInfo.axis < 0) { 1.294 + ALOGE("%s: Expected inverted axis label, got '%s'.", 1.295 + mTokenizer->getLocation().string(), axisToken.string()); 1.296 + return BAD_VALUE; 1.297 + } 1.298 + } else if (token == "split") { 1.299 + axisInfo.mode = AxisInfo::MODE_SPLIT; 1.300 + 1.301 + mTokenizer->skipDelimiters(WHITESPACE); 1.302 + String8 splitToken = mTokenizer->nextToken(WHITESPACE); 1.303 + axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0)); 1.304 + if (*end) { 1.305 + ALOGE("%s: Expected split value, got '%s'.", 1.306 + mTokenizer->getLocation().string(), splitToken.string()); 1.307 + return BAD_VALUE; 1.308 + } 1.309 + 1.310 + mTokenizer->skipDelimiters(WHITESPACE); 1.311 + String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE); 1.312 + axisInfo.axis = getAxisByLabel(lowAxisToken.string()); 1.313 + if (axisInfo.axis < 0) { 1.314 + ALOGE("%s: Expected low axis label, got '%s'.", 1.315 + mTokenizer->getLocation().string(), lowAxisToken.string()); 1.316 + return BAD_VALUE; 1.317 + } 1.318 + 1.319 + mTokenizer->skipDelimiters(WHITESPACE); 1.320 + String8 highAxisToken = mTokenizer->nextToken(WHITESPACE); 1.321 + axisInfo.highAxis = getAxisByLabel(highAxisToken.string()); 1.322 + if (axisInfo.highAxis < 0) { 1.323 + ALOGE("%s: Expected high axis label, got '%s'.", 1.324 + mTokenizer->getLocation().string(), highAxisToken.string()); 1.325 + return BAD_VALUE; 1.326 + } 1.327 + } else { 1.328 + axisInfo.axis = getAxisByLabel(token.string()); 1.329 + if (axisInfo.axis < 0) { 1.330 + ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.", 1.331 + mTokenizer->getLocation().string(), token.string()); 1.332 + return BAD_VALUE; 1.333 + } 1.334 + } 1.335 + 1.336 + for (;;) { 1.337 + mTokenizer->skipDelimiters(WHITESPACE); 1.338 + if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') { 1.339 + break; 1.340 + } 1.341 + String8 keywordToken = mTokenizer->nextToken(WHITESPACE); 1.342 + if (keywordToken == "flat") { 1.343 + mTokenizer->skipDelimiters(WHITESPACE); 1.344 + String8 flatToken = mTokenizer->nextToken(WHITESPACE); 1.345 + axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0)); 1.346 + if (*end) { 1.347 + ALOGE("%s: Expected flat value, got '%s'.", 1.348 + mTokenizer->getLocation().string(), flatToken.string()); 1.349 + return BAD_VALUE; 1.350 + } 1.351 + } else { 1.352 + ALOGE("%s: Expected keyword 'flat', got '%s'.", 1.353 + mTokenizer->getLocation().string(), keywordToken.string()); 1.354 + return BAD_VALUE; 1.355 + } 1.356 + } 1.357 + 1.358 +#if DEBUG_PARSER 1.359 + ALOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, " 1.360 + "splitValue=%d, flatOverride=%d.", 1.361 + scanCode, 1.362 + axisInfo.mode, axisInfo.axis, axisInfo.highAxis, 1.363 + axisInfo.splitValue, axisInfo.flatOverride); 1.364 +#endif 1.365 + mMap->mAxes.add(scanCode, axisInfo); 1.366 + return NO_ERROR; 1.367 +} 1.368 + 1.369 +};