15912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown/*
25912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * Copyright (C) 2010 The Android Open Source Project
35912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown *
45912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
55912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * you may not use this file except in compliance with the License.
65912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * You may obtain a copy of the License at
75912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown *
85912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
95912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown *
105912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * Unless required by applicable law or agreed to in writing, software
115912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
125912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * See the License for the specific language governing permissions and
145912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown * limitations under the License.
155912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown */
165912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
175912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#define LOG_TAG "VirtualKeyMap"
185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <stdlib.h>
205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <string.h>
215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
225912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <input/VirtualKeyMap.h>
235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <utils/Log.h>
245912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <utils/Errors.h>
255912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <utils/Tokenizer.h>
265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#include <utils/Timers.h>
275912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown// Enables debug output for the parser.
295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#define DEBUG_PARSER 0
305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
315912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown// Enables debug output for parser performance.
325912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#define DEBUG_PARSER_PERFORMANCE 0
335912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
345912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
355912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownnamespace android {
365912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
375912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatic const char* WHITESPACE = " \t\r";
385912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatic const char* WHITESPACE_OR_FIELD_DELIMITER = " \t\r:";
395912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
405912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
415912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown// --- VirtualKeyMap ---
425912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
435912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownVirtualKeyMap::VirtualKeyMap() {
445912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
455912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
465912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownVirtualKeyMap::~VirtualKeyMap() {
475912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
485912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
495912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatus_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) {
505912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    *outMap = NULL;
515912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
525912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    Tokenizer* tokenizer;
535912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    status_t status = Tokenizer::open(filename, &tokenizer);
545912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (status) {
555912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGE("Error %d opening virtual key map file %s.", status, filename.string());
565912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    } else {
575912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        VirtualKeyMap* map = new VirtualKeyMap();
585912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (!map) {
595912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            ALOGE("Error allocating virtual key map.");
605912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            status = NO_MEMORY;
615912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        } else {
625912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PARSER_PERFORMANCE
635912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
645912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
655912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            Parser parser(map, tokenizer);
665912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            status = parser.parse();
675912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PARSER_PERFORMANCE
685912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
695912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
705912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    tokenizer->getFilename().string(), tokenizer->getLineNumber(),
715912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    elapsedTime / 1000000.0);
725912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
735912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (status) {
745912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                delete map;
755912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            } else {
765912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                *outMap = map;
775912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
785912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
795912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        delete tokenizer;
805912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
815912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return status;
825912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
835912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
845912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
855912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown// --- VirtualKeyMap::Parser ---
865912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
875912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownVirtualKeyMap::Parser::Parser(VirtualKeyMap* map, Tokenizer* tokenizer) :
885912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        mMap(map), mTokenizer(tokenizer) {
895912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
905912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
915912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff BrownVirtualKeyMap::Parser::~Parser() {
925912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
935912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
945912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownstatus_t VirtualKeyMap::Parser::parse() {
955912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    while (!mTokenizer->isEof()) {
965912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PARSER
975912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
985912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                mTokenizer->peekRemainderOfLine().string());
995912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
1005912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1015912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        mTokenizer->skipDelimiters(WHITESPACE);
1025912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1035912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
1045912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            // Multiple keys can appear on one line or they can be broken up across multiple lines.
1055912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            do {
1065912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
1075912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                if (token != "0x01") {
1085912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    ALOGE("%s: Unknown virtual key type, expected 0x01.",
1095912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                          mTokenizer->getLocation().string());
1105912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    return BAD_VALUE;
1115912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                }
1125912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1135912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                VirtualKeyDefinition defn;
1145912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                bool success = parseNextIntField(&defn.scanCode)
1155912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        && parseNextIntField(&defn.centerX)
1165912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        && parseNextIntField(&defn.centerY)
1175912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        && parseNextIntField(&defn.width)
1185912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        && parseNextIntField(&defn.height);
1195912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                if (!success) {
1205912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    ALOGE("%s: Expected 5 colon-delimited integers in virtual key definition.",
1215912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                          mTokenizer->getLocation().string());
1225912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                    return BAD_VALUE;
1235912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                }
1245912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1255912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#if DEBUG_PARSER
1265912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                ALOGD("Parsed virtual key: scanCode=%d, centerX=%d, centerY=%d, "
1275912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        "width=%d, height=%d",
1285912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height);
1295912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown#endif
1305912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                mMap->mVirtualKeys.push(defn);
1315912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            } while (consumeFieldDelimiterAndSkipWhitespace());
1325912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1335912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            if (!mTokenizer->isEol()) {
1345912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                ALOGE("%s: Expected end of line, got '%s'.",
1355912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        mTokenizer->getLocation().string(),
1365912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                        mTokenizer->peekRemainderOfLine().string());
1375912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown                return BAD_VALUE;
1385912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown            }
1395912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        }
1405912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1415912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        mTokenizer->nextLine();
1425912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1435912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1445912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return NO_ERROR;
1455912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1465912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1475912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownbool VirtualKeyMap::Parser::consumeFieldDelimiterAndSkipWhitespace() {
1485912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    mTokenizer->skipDelimiters(WHITESPACE);
1495912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (mTokenizer->peekChar() == ':') {
1505912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        mTokenizer->nextChar();
1515912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        mTokenizer->skipDelimiters(WHITESPACE);
1525912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return true;
1535912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1545912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return false;
1555912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1565912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1575912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brownbool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) {
1585912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (!consumeFieldDelimiterAndSkipWhitespace()) {
1595912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return false;
1605912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1615912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1625912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
1635912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    char* end;
1645912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    *outValue = strtol(token.string(), &end, 0);
1655912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    if (token.isEmpty() || *end != '\0') {
1665912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        ALOGE("Expected an integer, got '%s'.", token.string());
1675912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown        return false;
1685912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    }
1695912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown    return true;
1705912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown}
1715912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown
1725912f95d26f77d2b6df13e1f2672e48e3f9b871cJeff Brown} // namespace android
173