widget/gonk/libui/KeyLayoutMap.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     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  */
    17 #define LOG_TAG "KeyLayoutMap"
    18 #include "cutils_log.h"
    20 #include <stdlib.h>
    21 #include "android_keycodes.h"
    22 #include "Keyboard.h"
    23 #include "KeyLayoutMap.h"
    24 #include <utils/Errors.h>
    25 #include "Tokenizer.h"
    26 #include <utils/Timers.h>
    28 // Enables debug output for the parser.
    29 #define DEBUG_PARSER 0
    31 // Enables debug output for parser performance.
    32 #define DEBUG_PARSER_PERFORMANCE 0
    34 // Enables debug output for mapping.
    35 #define DEBUG_MAPPING 0
    38 namespace android {
    40 static const char* WHITESPACE = " \t\r";
    42 // --- KeyLayoutMap ---
    44 KeyLayoutMap::KeyLayoutMap() {
    45 }
    47 KeyLayoutMap::~KeyLayoutMap() {
    48 }
    50 status_t KeyLayoutMap::load(const String8& filename, sp<KeyLayoutMap>* outMap) {
    51     outMap->clear();
    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 }
    83 status_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     }
    95     *outKeyCode = key->keyCode;
    96     *outFlags = key->flags;
    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 }
   105 const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const {
   106     if (usageCode) {
   107         ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
   108         if (index >= 0) {
   109             return &mKeysByUsageCode.valueAt(index);
   110         }
   111     }
   112     if (scanCode) {
   113         ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
   114         if (index >= 0) {
   115             return &mKeysByScanCode.valueAt(index);
   116         }
   117     }
   118     return NULL;
   119 }
   121 status_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 }
   131 status_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     }
   140     *outAxisInfo = mAxes.valueAt(index);
   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 }
   153 // --- KeyLayoutMap::Parser ---
   155 KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
   156         mMap(map), mTokenizer(tokenizer) {
   157 }
   159 KeyLayoutMap::Parser::~Parser() {
   160 }
   162 status_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
   169         mTokenizer->skipDelimiters(WHITESPACE);
   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             }
   187             mTokenizer->skipDelimiters(WHITESPACE);
   188             if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
   189                 ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
   190                         mTokenizer->getLocation().string(),
   191                         mTokenizer->peekRemainderOfLine().string());
   192                 return BAD_VALUE;
   193             }
   194         }
   196         mTokenizer->nextLine();
   197     }
   198     return NO_ERROR;
   199 }
   201 status_t KeyLayoutMap::Parser::parseKey() {
   202     String8 codeToken = mTokenizer->nextToken(WHITESPACE);
   203     bool mapUsage = false;
   204     if (codeToken == "usage") {
   205         mapUsage = true;
   206         mTokenizer->skipDelimiters(WHITESPACE);
   207         codeToken = mTokenizer->nextToken(WHITESPACE);
   208     }
   210     char* end;
   211     int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
   212     if (*end) {
   213         ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
   214                 mapUsage ? "usage" : "scan code", codeToken.string());
   215         return BAD_VALUE;
   216     }
   217     KeyedVector<int32_t, Key>& map =
   218             mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
   219     if (map.indexOfKey(code) >= 0) {
   220         ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
   221                 mapUsage ? "usage" : "scan code", codeToken.string());
   222         return BAD_VALUE;
   223     }
   225     mTokenizer->skipDelimiters(WHITESPACE);
   226     String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
   227     int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
   228     if (!keyCode) {
   229         ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
   230                 keyCodeToken.string());
   231         return BAD_VALUE;
   232     }
   234     uint32_t flags = 0;
   235     for (;;) {
   236         mTokenizer->skipDelimiters(WHITESPACE);
   237         if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break;
   239         String8 flagToken = mTokenizer->nextToken(WHITESPACE);
   240         uint32_t flag = getKeyFlagByLabel(flagToken.string());
   241         if (!flag) {
   242             ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),
   243                     flagToken.string());
   244             return BAD_VALUE;
   245         }
   246         if (flags & flag) {
   247             ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(),
   248                     flagToken.string());
   249             return BAD_VALUE;
   250         }
   251         flags |= flag;
   252     }
   254 #if DEBUG_PARSER
   255     ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
   256             mapUsage ? "usage" : "scan code", code, keyCode, flags);
   257 #endif
   258     Key key;
   259     key.keyCode = keyCode;
   260     key.flags = flags;
   261     map.add(code, key);
   262     return NO_ERROR;
   263 }
   265 status_t KeyLayoutMap::Parser::parseAxis() {
   266     String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
   267     char* end;
   268     int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
   269     if (*end) {
   270         ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(),
   271                 scanCodeToken.string());
   272         return BAD_VALUE;
   273     }
   274     if (mMap->mAxes.indexOfKey(scanCode) >= 0) {
   275         ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(),
   276                 scanCodeToken.string());
   277         return BAD_VALUE;
   278     }
   280     AxisInfo axisInfo;
   282     mTokenizer->skipDelimiters(WHITESPACE);
   283     String8 token = mTokenizer->nextToken(WHITESPACE);
   284     if (token == "invert") {
   285         axisInfo.mode = AxisInfo::MODE_INVERT;
   287         mTokenizer->skipDelimiters(WHITESPACE);
   288         String8 axisToken = mTokenizer->nextToken(WHITESPACE);
   289         axisInfo.axis = getAxisByLabel(axisToken.string());
   290         if (axisInfo.axis < 0) {
   291             ALOGE("%s: Expected inverted axis label, got '%s'.",
   292                     mTokenizer->getLocation().string(), axisToken.string());
   293             return BAD_VALUE;
   294         }
   295     } else if (token == "split") {
   296         axisInfo.mode = AxisInfo::MODE_SPLIT;
   298         mTokenizer->skipDelimiters(WHITESPACE);
   299         String8 splitToken = mTokenizer->nextToken(WHITESPACE);
   300         axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0));
   301         if (*end) {
   302             ALOGE("%s: Expected split value, got '%s'.",
   303                     mTokenizer->getLocation().string(), splitToken.string());
   304             return BAD_VALUE;
   305         }
   307         mTokenizer->skipDelimiters(WHITESPACE);
   308         String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE);
   309         axisInfo.axis = getAxisByLabel(lowAxisToken.string());
   310         if (axisInfo.axis < 0) {
   311             ALOGE("%s: Expected low axis label, got '%s'.",
   312                     mTokenizer->getLocation().string(), lowAxisToken.string());
   313             return BAD_VALUE;
   314         }
   316         mTokenizer->skipDelimiters(WHITESPACE);
   317         String8 highAxisToken = mTokenizer->nextToken(WHITESPACE);
   318         axisInfo.highAxis = getAxisByLabel(highAxisToken.string());
   319         if (axisInfo.highAxis < 0) {
   320             ALOGE("%s: Expected high axis label, got '%s'.",
   321                     mTokenizer->getLocation().string(), highAxisToken.string());
   322             return BAD_VALUE;
   323         }
   324     } else {
   325         axisInfo.axis = getAxisByLabel(token.string());
   326         if (axisInfo.axis < 0) {
   327             ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.",
   328                     mTokenizer->getLocation().string(), token.string());
   329             return BAD_VALUE;
   330         }
   331     }
   333     for (;;) {
   334         mTokenizer->skipDelimiters(WHITESPACE);
   335         if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') {
   336             break;
   337         }
   338         String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
   339         if (keywordToken == "flat") {
   340             mTokenizer->skipDelimiters(WHITESPACE);
   341             String8 flatToken = mTokenizer->nextToken(WHITESPACE);
   342             axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0));
   343             if (*end) {
   344                 ALOGE("%s: Expected flat value, got '%s'.",
   345                         mTokenizer->getLocation().string(), flatToken.string());
   346                 return BAD_VALUE;
   347             }
   348         } else {
   349             ALOGE("%s: Expected keyword 'flat', got '%s'.",
   350                     mTokenizer->getLocation().string(), keywordToken.string());
   351             return BAD_VALUE;
   352         }
   353     }
   355 #if DEBUG_PARSER
   356     ALOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
   357             "splitValue=%d, flatOverride=%d.",
   358             scanCode,
   359             axisInfo.mode, axisInfo.axis, axisInfo.highAxis,
   360             axisInfo.splitValue, axisInfo.flatOverride);
   361 #endif
   362     mMap->mAxes.add(scanCode, axisInfo);
   363     return NO_ERROR;
   364 }
   366 };

mercurial