Home | History | Annotate | Download | only in ui
      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