blob: 56bc26fd6d7396d64b54f70dfd0e53ec83841280 [file] [log] [blame]
Jeff Brown6b53e8d2010-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 Project9066cfe2009-03-03 19:31:44 -080017#define LOG_TAG "KeyLayoutMap"
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019#include <stdlib.h>
Jeff Brown6b53e8d2010-11-10 16:03:06 -080020#include <android/keycodes.h>
21#include <ui/Keyboard.h>
22#include <ui/KeyLayoutMap.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023#include <utils/Log.h>
Jeff Brown6b53e8d2010-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 Project9066cfe2009-03-03 19:31:44 -080037
38namespace android {
39
Jeff Brown6b53e8d2010-11-10 16:03:06 -080040static const char* WHITESPACE = " \t\r";
41
42// --- KeyLayoutMap ---
43
44KeyLayoutMap::KeyLayoutMap() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045}
46
Jeff Brown6b53e8d2010-11-10 16:03:06 -080047KeyLayoutMap::~KeyLayoutMap() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048}
49
Jeff Brown6b53e8d2010-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 Project9066cfe2009-03-03 19:31:44 -080079 }
Jeff Brown6b53e8d2010-11-10 16:03:06 -080080 delete tokenizer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 }
Jeff Brown6b53e8d2010-11-10 16:03:06 -080082 return status;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083}
84
Jeff Brown6b53e8d2010-11-10 16:03:06 -080085status_t KeyLayoutMap::map(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const {
86 ssize_t index = mKeys.indexOfKey(scanCode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 if (index < 0) {
Jeff Brown6b53e8d2010-11-10 16:03:06 -080088#if DEBUG_MAPPING
89 LOGD("map: scanCode=%d ~ Failed.", scanCode);
90#endif
91 *keyCode = AKEYCODE_UNKNOWN;
92 *flags = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 return NAME_NOT_FOUND;
94 }
95
Jeff Brown6b53e8d2010-11-10 16:03:06 -080096 const Key& k = mKeys.valueAt(index);
97 *keyCode = k.keyCode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 *flags = k.flags;
99
Jeff Brown6b53e8d2010-11-10 16:03:06 -0800100#if DEBUG_MAPPING
101 LOGD("map: scanCode=%d ~ Result keyCode=%d, flags=0x%08x.", scanCode, *keyCode, *flags);
102#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 return NO_ERROR;
104}
105
Jeff Brown6b53e8d2010-11-10 16:03:06 -0800106status_t KeyLayoutMap::findScanCodes(int32_t keyCode, Vector<int32_t>* outScanCodes) const {
107 const size_t N = mKeys.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 for (size_t i=0; i<N; i++) {
Jeff Brown6b53e8d2010-11-10 16:03:06 -0800109 if (mKeys.valueAt(i).keyCode == keyCode) {
110 outScanCodes->add(mKeys.keyAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111 }
112 }
Jeff Brown6b53e8d2010-11-10 16:03:06 -0800113 return NO_ERROR;
114}
115
116// --- KeyLayoutMap::Parser ---
117
118KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
119 mMap(map), mTokenizer(tokenizer) {
120}
121
122KeyLayoutMap::Parser::~Parser() {
123}
124
125status_t KeyLayoutMap::Parser::parse() {
126 while (!mTokenizer->isEof()) {
127#if DEBUG_PARSER
128 LOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
129 mTokenizer->peekRemainderOfLine().string());
130#endif
131
132 mTokenizer->skipDelimiters(WHITESPACE);
133
134 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
135 String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
136 if (keywordToken == "key") {
137 mTokenizer->skipDelimiters(WHITESPACE);
138 status_t status = parseKey();
139 if (status) return status;
140 } else {
141 LOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
142 keywordToken.string());
143 return BAD_VALUE;
144 }
145
146 mTokenizer->skipDelimiters(WHITESPACE);
147 if (!mTokenizer->isEol()) {
148 LOGE("%s: Expected end of line, got '%s'.",
149 mTokenizer->getLocation().string(),
150 mTokenizer->peekRemainderOfLine().string());
151 return BAD_VALUE;
152 }
153 }
154
155 mTokenizer->nextLine();
156 }
157 return NO_ERROR;
158}
159
160status_t KeyLayoutMap::Parser::parseKey() {
161 String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
162 char* end;
163 int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
164 if (*end) {
165 LOGE("%s: Expected scan code number, got '%s'.", mTokenizer->getLocation().string(),
166 scanCodeToken.string());
167 return BAD_VALUE;
168 }
169 if (mMap->mKeys.indexOfKey(scanCode) >= 0) {
170 LOGE("%s: Duplicate entry for scan code '%s'.", mTokenizer->getLocation().string(),
171 scanCodeToken.string());
172 return BAD_VALUE;
173 }
174
175 mTokenizer->skipDelimiters(WHITESPACE);
176 String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
177 int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
178 if (!keyCode) {
179 LOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
180 keyCodeToken.string());
181 return BAD_VALUE;
182 }
183
184 uint32_t flags = 0;
185 for (;;) {
186 mTokenizer->skipDelimiters(WHITESPACE);
187 if (mTokenizer->isEol()) break;
188
189 String8 flagToken = mTokenizer->nextToken(WHITESPACE);
190 uint32_t flag = getKeyFlagByLabel(flagToken.string());
191 if (!flag) {
192 LOGE("%s: Expected flag label, got '%s'.", mTokenizer->getLocation().string(),
193 flagToken.string());
194 return BAD_VALUE;
195 }
196 if (flags & flag) {
197 LOGE("%s: Duplicate flag '%s'.", mTokenizer->getLocation().string(),
198 flagToken.string());
199 return BAD_VALUE;
200 }
201 flags |= flag;
202 }
203
204#if DEBUG_PARSER
205 LOGD("Parsed key: scanCode=%d, keyCode=%d, flags=0x%08x.", scanCode, keyCode, flags);
206#endif
207 Key key;
208 key.keyCode = keyCode;
209 key.flags = flags;
210 mMap->mKeys.add(scanCode, key);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 return NO_ERROR;
212}
213
214};