blob: e891181c828a4a9ba719d440bc12a424370f1cbc [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001#define LOG_TAG "KeyCharacterMap"
2
3#include <ui/KeyCharacterMap.h>
4#include <cutils/properties.h>
5
6#include <utils/Log.h>
7#include <sys/types.h>
8#include <unistd.h>
9#include <stdlib.h>
10#include <fcntl.h>
11#include <limits.h>
12#include <string.h>
13
14struct Header
15{
16 char magic[8];
17 unsigned int endian;
18 unsigned int version;
19 unsigned int keycount;
20 unsigned char kbdtype;
21 char padding[11];
22};
23
24KeyCharacterMap::KeyCharacterMap()
25{
26}
27
28KeyCharacterMap::~KeyCharacterMap()
29{
30 free(m_keys);
31}
32
33unsigned short
34KeyCharacterMap::get(int keycode, int meta)
35{
36 Key* k = find_key(keycode);
37 if (k != NULL) {
38 return k->data[meta & META_MASK];
39 }
40 return 0;
41}
42
43unsigned short
44KeyCharacterMap::getNumber(int keycode)
45{
46 Key* k = find_key(keycode);
47 if (k != NULL) {
48 return k->number;
49 }
50 return 0;
51}
52
53unsigned short
54KeyCharacterMap::getMatch(int keycode, const unsigned short* chars,
55 int charsize, uint32_t modifiers)
56{
57 Key* k = find_key(keycode);
58 modifiers &= 3; // ignore the SYM key because we don't have keymap entries for it
59 if (k != NULL) {
60 const uint16_t* data = k->data;
61 for (int j=0; j<charsize; j++) {
62 uint16_t c = chars[j];
63 for (int i=0; i<(META_MASK + 1); i++) {
64 if ((modifiers == 0) || ((modifiers & i) != 0)) {
65 if (c == data[i]) {
66 return c;
67 }
68 }
69 }
70 }
71 }
72 return 0;
73}
74
75unsigned short
76KeyCharacterMap::getDisplayLabel(int keycode)
77{
78 Key* k = find_key(keycode);
79 if (k != NULL) {
80 return k->display_label;
81 }
82 return 0;
83}
84
85bool
86KeyCharacterMap::getKeyData(int keycode, unsigned short *displayLabel,
87 unsigned short *number, unsigned short* results)
88{
89 Key* k = find_key(keycode);
90 if (k != NULL) {
91 memcpy(results, k->data, sizeof(short)*(META_MASK + 1));
92 *number = k->number;
93 *displayLabel = k->display_label;
94 return true;
95 } else {
96 return false;
97 }
98}
99
100bool
101KeyCharacterMap::find_char(uint16_t c, uint32_t* key, uint32_t* mods)
102{
103 uint32_t N = m_keyCount;
104 for (int j=0; j<(META_MASK + 1); j++) {
105 Key const* keys = m_keys;
106 for (uint32_t i=0; i<N; i++) {
107 if (keys->data[j] == c) {
108 *key = keys->keycode;
109 *mods = j;
110 return true;
111 }
112 keys++;
113 }
114 }
115 return false;
116}
117
118bool
119KeyCharacterMap::getEvents(uint16_t* chars, size_t len,
120 Vector<int32_t>* keys, Vector<uint32_t>* modifiers)
121{
122 for (size_t i=0; i<len; i++) {
123 uint32_t k, mods;
124 if (find_char(chars[i], &k, &mods)) {
125 keys->add(k);
126 modifiers->add(mods);
127 } else {
128 return false;
129 }
130 }
131 return true;
132}
133
134KeyCharacterMap::Key*
135KeyCharacterMap::find_key(int keycode)
136{
137 Key* keys = m_keys;
138 int low = 0;
139 int high = m_keyCount - 1;
140 int mid;
141 int n;
142 while (low <= high) {
143 mid = (low + high) / 2;
144 n = keys[mid].keycode;
145 if (keycode < n) {
146 high = mid - 1;
147 } else if (keycode > n) {
148 low = mid + 1;
149 } else {
150 return keys + mid;
151 }
152 }
153 return NULL;
154}
155
156KeyCharacterMap*
157KeyCharacterMap::load(int id)
158{
159 KeyCharacterMap* rv = NULL;
160 char path[PATH_MAX];
161 char propName[100];
162 char dev[PROPERTY_VALUE_MAX];
163 char tmpfn[PROPERTY_VALUE_MAX];
164 int err;
165 const char* root = getenv("ANDROID_ROOT");
166
167 sprintf(propName, "hw.keyboards.%u.devname", id);
168 err = property_get(propName, dev, "");
169 if (err > 0) {
170 // replace all the spaces with underscores
171 strcpy(tmpfn, dev);
172 for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
173 *p = '_';
174 snprintf(path, sizeof(path), "%s/usr/keychars/%s.kcm.bin", root, tmpfn);
175 //LOGD("load: dev='%s' path='%s'\n", dev, path);
176 rv = try_file(path);
177 if (rv != NULL) {
178 return rv;
179 }
180 LOGW("Error loading keycharmap file '%s'. %s='%s'", path, propName, dev);
181 } else {
182 LOGW("No keyboard for id %d", id);
183 }
184
185 snprintf(path, sizeof(path), "%s/usr/keychars/qwerty.kcm.bin", root);
186 rv = try_file(path);
187 if (rv == NULL) {
188 LOGE("Can't find any keycharmaps (also tried %s)", path);
189 return NULL;
190 }
191 LOGW("Using default keymap: %s", path);
192
193 return rv;
194}
195
196KeyCharacterMap*
197KeyCharacterMap::try_file(const char* filename)
198{
199 KeyCharacterMap* rv = NULL;
200 Key* keys;
201 int fd;
202 off_t filesize;
203 Header header;
204 int err;
205
206 fd = open(filename, O_RDONLY);
207 if (fd == -1) {
208 LOGW("Can't open keycharmap file");
209 return NULL;
210 }
211
212 filesize = lseek(fd, 0, SEEK_END);
213 lseek(fd, 0, SEEK_SET);
214
215 // validate the header
216 if (filesize <= (off_t)sizeof(header)) {
217 LOGW("Bad keycharmap - filesize=%d\n", (int)filesize);
218 goto cleanup1;
219 }
220
221 err = read(fd, &header, sizeof(header));
222 if (err == -1) {
223 LOGW("Error reading keycharmap file");
224 goto cleanup1;
225 }
226
227 if (0 != memcmp(header.magic, "keychar", 8)) {
228 LOGW("Bad keycharmap magic token");
229 goto cleanup1;
230 }
231 if (header.endian != 0x12345678) {
232 LOGW("Bad keycharmap endians");
233 goto cleanup1;
234 }
235 if ((header.version & 0xff) != 2) {
236 LOGW("Only support keycharmap version 2 (got 0x%08x)", header.version);
237 goto cleanup1;
238 }
239 if (filesize < (off_t)(sizeof(Header)+(sizeof(Key)*header.keycount))) {
240 LOGW("Bad keycharmap file size\n");
241 goto cleanup1;
242 }
243
244 // read the key data
245 keys = (Key*)malloc(sizeof(Key)*header.keycount);
246 err = read(fd, keys, sizeof(Key)*header.keycount);
247 if (err == -1) {
248 LOGW("Error reading keycharmap file");
249 free(keys);
250 goto cleanup1;
251 }
252
253 // return the object
254 rv = new KeyCharacterMap;
255 rv->m_keyCount = header.keycount;
256 rv->m_keys = keys;
257 rv->m_type = header.kbdtype;
258
259cleanup1:
260 close(fd);
261
262 return rv;
263}