• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #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 
14 struct 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 
KeyCharacterMap()24 KeyCharacterMap::KeyCharacterMap()
25 {
26 }
27 
~KeyCharacterMap()28 KeyCharacterMap::~KeyCharacterMap()
29 {
30     free(m_keys);
31 }
32 
33 unsigned short
get(int keycode,int meta)34 KeyCharacterMap::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 
43 unsigned short
getNumber(int keycode)44 KeyCharacterMap::getNumber(int keycode)
45 {
46     Key* k = find_key(keycode);
47     if (k != NULL) {
48         return k->number;
49     }
50     return 0;
51 }
52 
53 unsigned short
getMatch(int keycode,const unsigned short * chars,int charsize,uint32_t modifiers)54 KeyCharacterMap::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 
75 unsigned short
getDisplayLabel(int keycode)76 KeyCharacterMap::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 
85 bool
getKeyData(int keycode,unsigned short * displayLabel,unsigned short * number,unsigned short * results)86 KeyCharacterMap::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 
100 bool
find_char(uint16_t c,uint32_t * key,uint32_t * mods)101 KeyCharacterMap::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 
118 bool
getEvents(uint16_t * chars,size_t len,Vector<int32_t> * keys,Vector<uint32_t> * modifiers)119 KeyCharacterMap::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 
134 KeyCharacterMap::Key*
find_key(int keycode)135 KeyCharacterMap::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 
156 KeyCharacterMap*
load(int id)157 KeyCharacterMap::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 
196 KeyCharacterMap*
try_file(const char * filename)197 KeyCharacterMap::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 
259 cleanup1:
260     close(fd);
261 
262     return rv;
263 }
264