blob: 2ed0e66e1c1ced4e399b7ffaba2d4ae876f395cb [file] [log] [blame]
Jeff Browna3477c82010-11-10 16:03:06 -08001/*
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
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080017#define LOG_TAG "KeyLayoutMap"
18
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080019#include <stdlib.h>
Jeff Browna3477c82010-11-10 16:03:06 -080020#include <android/keycodes.h>
21#include <ui/Keyboard.h>
22#include <ui/KeyLayoutMap.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080023#include <utils/Log.h>
Jeff Browna3477c82010-11-10 16:03:06 -080024#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
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080037
38namespace android {
39
Jeff Browna3477c82010-11-10 16:03:06 -080040static const char* WHITESPACE = " \t\r";
41
42// --- KeyLayoutMap ---
43
44KeyLayoutMap::KeyLayoutMap() {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080045}
46
Jeff Browna3477c82010-11-10 16:03:06 -080047KeyLayoutMap::~KeyLayoutMap() {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080048}
49
Jeff Browna3477c82010-11-10 16:03:06 -080050status_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 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080079 }
Jeff Browna3477c82010-11-10 16:03:06 -080080 delete tokenizer;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080081 }
Jeff Browna3477c82010-11-10 16:03:06 -080082 return status;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080083}
84
Jeff Brown3ea4de82011-02-19 01:08:02 -080085status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const {
Jeff Browna3477c82010-11-10 16:03:06 -080086 ssize_t index = mKeys.indexOfKey(scanCode);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080087 if (index < 0) {
Jeff Browna3477c82010-11-10 16:03:06 -080088#if DEBUG_MAPPING
Jeff Brown3ea4de82011-02-19 01:08:02 -080089 LOGD("mapKey: scanCode=%d ~ Failed.", scanCode);
Jeff Browna3477c82010-11-10 16:03:06 -080090#endif
91 *keyCode = AKEYCODE_UNKNOWN;
92 *flags = 0;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080093 return NAME_NOT_FOUND;
94 }
95
Jeff Browna3477c82010-11-10 16:03:06 -080096 const Key& k = mKeys.valueAt(index);
97 *keyCode = k.keyCode;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080098 *flags = k.flags;
99
Jeff Browna3477c82010-11-10 16:03:06 -0800100#if DEBUG_MAPPING
Jeff Brown3ea4de82011-02-19 01:08:02 -0800101 LOGD("mapKey: scanCode=%d ~ Result keyCode=%d, flags=0x%08x.", scanCode, *keyCode, *flags);
Jeff Browna3477c82010-11-10 16:03:06 -0800102#endif
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800103 return NO_ERROR;
104}
105
Jeff Brown3ea4de82011-02-19 01:08:02 -0800106status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const {
Jeff Browna3477c82010-11-10 16:03:06 -0800107 const size_t N = mKeys.size();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800108 for (size_t i=0; i<N; i++) {
Jeff Browna3477c82010-11-10 16:03:06 -0800109 if (mKeys.valueAt(i).keyCode == keyCode) {
110 outScanCodes->add(mKeys.keyAt(i));
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800111 }
112 }
Jeff Browna3477c82010-11-10 16:03:06 -0800113 return NO_ERROR;
114}
115
Jeff Brown3ea4de82011-02-19 01:08:02 -0800116status_t KeyLayoutMap::mapAxis(int32_t scanCode, int32_t* axis) 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 *axis = -1;
123 return NAME_NOT_FOUND;
124 }
125
126 *axis = mAxes.valueAt(index);
127
128#if DEBUG_MAPPING
129 LOGD("mapAxis: scanCode=%d ~ Result axis=%d.", scanCode, *axis);
130#endif
131 return NO_ERROR;
132}
133
134
Jeff Browna3477c82010-11-10 16:03:06 -0800135// --- KeyLayoutMap::Parser ---
136
137KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
138 mMap(map), mTokenizer(tokenizer) {
139}
140
141KeyLayoutMap::Parser::~Parser() {
142}
143
144status_t KeyLayoutMap::Parser::parse() {
145 while (!mTokenizer->isEof()) {
146#if DEBUG_PARSER
147 LOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
148 mTokenizer->peekRemainderOfLine().string());
149#endif
150
151 mTokenizer->skipDelimiters(WHITESPACE);
152
153 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
154 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
155 if (keywordToken == "key") {
156 mTokenizer->skipDelimiters(WHITESPACE);
157 status_t status = parseKey();
158 if (status) return status;
Jeff Brown3ea4de82011-02-19 01:08:02 -0800159 } else if (keywordToken == "axis") {
160 mTokenizer->skipDelimiters(WHITESPACE);
161 status_t status = parseAxis();
162 if (status) return status;
Jeff Browna3477c82010-11-10 16:03:06 -0800163 } else {
164 LOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
165 keywordToken.string());
166 return BAD_VALUE;
167 }
168
169 mTokenizer->skipDelimiters(WHITESPACE);
170 if (!mTokenizer->isEol()) {
171 LOGE("%s: Expected end of line, got '%s'.",
172 mTokenizer->getLocation().string(),
173 mTokenizer->peekRemainderOfLine().string());
174 return BAD_VALUE;
175 }
176 }
177
178 mTokenizer->nextLine();
179 }
180 return NO_ERROR;
181}
182
183status_t KeyLayoutMap::Parser::parseKey() {
184 String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
185 char* end;
186 int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
187 if (*end) {
Jeff Brown3ea4de82011-02-19 01:08:02 -0800188 LOGE("%s: Expected key scan code number, got '%s'.", mTokenizer->getLocation().string(),
Jeff Browna3477c82010-11-10 16:03:06 -0800189 scanCodeToken.string());
190 return BAD_VALUE;
191 }
192 if (mMap->mKeys.indexOfKey(scanCode) >= 0) {
Jeff Brown3ea4de82011-02-19 01:08:02 -0800193 LOGE("%s: Duplicate entry for key scan code '%s'.", mTokenizer->getLocation().string(),
Jeff Browna3477c82010-11-10 16:03:06 -0800194 scanCodeToken.string());
195 return BAD_VALUE;
196 }
197
198 mTokenizer->skipDelimiters(WHITESPACE);
199 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
200 int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
201 if (!keyCode) {
202 LOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
203 keyCodeToken.string());
204 return BAD_VALUE;
205 }
206
207 uint32_t flags = 0;
208 for (;;) {
209 mTokenizer->skipDelimiters(WHITESPACE);
210 if (mTokenizer->isEol()) break;
211
212 String8 flagToken = mTokenizer->nextToken(WHITESPACE);
213 uint32_t flag = getKeyFlagByLabel(flagToken.string());
214 if (!flag) {
Jeff Brown3ea4de82011-02-19 01:08:02 -0800215 LOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),
Jeff Browna3477c82010-11-10 16:03:06 -0800216 flagToken.string());
217 return BAD_VALUE;
218 }
219 if (flags & flag) {
Jeff Brown3ea4de82011-02-19 01:08:02 -0800220 LOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(),
Jeff Browna3477c82010-11-10 16:03:06 -0800221 flagToken.string());
222 return BAD_VALUE;
223 }
224 flags |= flag;
225 }
226
227#if DEBUG_PARSER
228 LOGD("Parsed key: scanCode=%d, keyCode=%d, flags=0x%08x.", scanCode, keyCode, flags);
229#endif
230 Key key;
231 key.keyCode = keyCode;
232 key.flags = flags;
233 mMap->mKeys.add(scanCode, key);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800234 return NO_ERROR;
235}
236
Jeff Brown3ea4de82011-02-19 01:08:02 -0800237status_t KeyLayoutMap::Parser::parseAxis() {
238 String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
239 char* end;
240 int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
241 if (*end) {
242 LOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(),
243 scanCodeToken.string());
244 return BAD_VALUE;
245 }
246 if (mMap->mAxes.indexOfKey(scanCode) >= 0) {
247 LOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(),
248 scanCodeToken.string());
249 return BAD_VALUE;
250 }
251
252 mTokenizer->skipDelimiters(WHITESPACE);
253 String8 axisToken = mTokenizer->nextToken(WHITESPACE);
254 int32_t axis = getAxisByLabel(axisToken.string());
255 if (axis < 0) {
256 LOGE("%s: Expected axis label, got '%s'.", mTokenizer->getLocation().string(),
257 axisToken.string());
258 return BAD_VALUE;
259 }
260
261#if DEBUG_PARSER
262 LOGD("Parsed axis: scanCode=%d, axis=%d.", scanCode, axis);
263#endif
264 mMap->mAxes.add(scanCode, axis);
265 return NO_ERROR;
266}
267
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800268};