• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
KeyLayoutMap()44 KeyLayoutMap::KeyLayoutMap() {
45 }
46 
~KeyLayoutMap()47 KeyLayoutMap::~KeyLayoutMap() {
48 }
49 
load(const String8 & filename,KeyLayoutMap ** outMap)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 
mapKey(int32_t scanCode,int32_t * keyCode,uint32_t * flags) const85 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 
findScanCodesForKey(int32_t keyCode,Vector<int32_t> * outScanCodes) const106 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 
mapAxis(int32_t scanCode,AxisInfo * outAxisInfo) const116 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 
Parser(KeyLayoutMap * map,Tokenizer * tokenizer)140 KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
141         mMap(map), mTokenizer(tokenizer) {
142 }
143 
~Parser()144 KeyLayoutMap::Parser::~Parser() {
145 }
146 
parse()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 
parseKey()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 
parseAxis()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