1 /*
2 * Copyright (C) 2010 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 "VirtualKeyMap"
18
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include <input/VirtualKeyMap.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 namespace android {
32
33 static const char* WHITESPACE = " \t\r";
34 static const char* WHITESPACE_OR_FIELD_DELIMITER = " \t\r:";
35
36
37 // --- VirtualKeyMap ---
38
VirtualKeyMap()39 VirtualKeyMap::VirtualKeyMap() {
40 }
41
~VirtualKeyMap()42 VirtualKeyMap::~VirtualKeyMap() {
43 }
44
load(const std::string & filename)45 std::unique_ptr<VirtualKeyMap> VirtualKeyMap::load(const std::string& filename) {
46 Tokenizer* t;
47 status_t status = Tokenizer::open(String8(filename.c_str()), &t);
48 if (status != OK) {
49 ALOGE("Error %d opening virtual key map file %s.", status, filename.c_str());
50 return nullptr;
51 }
52 std::unique_ptr<Tokenizer> tokenizer(t);
53 // Using 'new' to access a non-public constructor
54 std::unique_ptr<VirtualKeyMap> map(new VirtualKeyMap());
55 if (!map) {
56 ALOGE("Error allocating virtual key map.");
57 return nullptr;
58 }
59
60 Parser parser(map.get(), tokenizer.get());
61 status = parser.parse();
62 if (status != OK) {
63 return nullptr;
64 }
65
66 return map;
67 }
68
69
70 // --- VirtualKeyMap::Parser ---
71
Parser(VirtualKeyMap * map,Tokenizer * tokenizer)72 VirtualKeyMap::Parser::Parser(VirtualKeyMap* map, Tokenizer* tokenizer) :
73 mMap(map), mTokenizer(tokenizer) {
74 }
75
~Parser()76 VirtualKeyMap::Parser::~Parser() {
77 }
78
parse()79 status_t VirtualKeyMap::Parser::parse() {
80 while (!mTokenizer->isEof()) {
81 #if DEBUG_PARSER
82 ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
83 mTokenizer->peekRemainderOfLine().string());
84 #endif
85
86 mTokenizer->skipDelimiters(WHITESPACE);
87
88 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
89 // Multiple keys can appear on one line or they can be broken up across multiple lines.
90 do {
91 String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
92 if (token != "0x01") {
93 ALOGE("%s: Unknown virtual key type, expected 0x01.",
94 mTokenizer->getLocation().string());
95 return BAD_VALUE;
96 }
97
98 VirtualKeyDefinition defn;
99 bool success = parseNextIntField(&defn.scanCode)
100 && parseNextIntField(&defn.centerX)
101 && parseNextIntField(&defn.centerY)
102 && parseNextIntField(&defn.width)
103 && parseNextIntField(&defn.height);
104 if (!success) {
105 ALOGE("%s: Expected 5 colon-delimited integers in virtual key definition.",
106 mTokenizer->getLocation().string());
107 return BAD_VALUE;
108 }
109
110 #if DEBUG_PARSER
111 ALOGD("Parsed virtual key: scanCode=%d, centerX=%d, centerY=%d, "
112 "width=%d, height=%d",
113 defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height);
114 #endif
115 mMap->mVirtualKeys.push_back(defn);
116 } while (consumeFieldDelimiterAndSkipWhitespace());
117
118 if (!mTokenizer->isEol()) {
119 ALOGE("%s: Expected end of line, got '%s'.",
120 mTokenizer->getLocation().string(),
121 mTokenizer->peekRemainderOfLine().string());
122 return BAD_VALUE;
123 }
124 }
125
126 mTokenizer->nextLine();
127 }
128
129 return NO_ERROR;
130 }
131
consumeFieldDelimiterAndSkipWhitespace()132 bool VirtualKeyMap::Parser::consumeFieldDelimiterAndSkipWhitespace() {
133 mTokenizer->skipDelimiters(WHITESPACE);
134 if (mTokenizer->peekChar() == ':') {
135 mTokenizer->nextChar();
136 mTokenizer->skipDelimiters(WHITESPACE);
137 return true;
138 }
139 return false;
140 }
141
parseNextIntField(int32_t * outValue)142 bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) {
143 if (!consumeFieldDelimiterAndSkipWhitespace()) {
144 return false;
145 }
146
147 String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
148 char* end;
149 *outValue = strtol(token.string(), &end, 0);
150 if (token.isEmpty() || *end != '\0') {
151 ALOGE("Expected an integer, got '%s'.", token.string());
152 return false;
153 }
154 return true;
155 }
156
157 } // namespace android
158