1 /* Copyright (C) 2007-2008 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 ** GNU General Public License for more details.
11 */
12 #include "android/utils/path.h"
13 #include "android/utils/misc.h"
14 #include "android/utils/debug.h"
15 #include "android/utils/system.h"
16 #include "android/charmap.h"
17 #include <stdio.h>
18 #include <errno.h>
19
20 /* Parses .kcm file producing key characters map.
21 * .kcm file parsed by this module is expected to contain 4 types of
22 * lines:
23 * 1. An empty line (containing no characters, or only space or tab
24 * characters).
25 * 2. A comment line (begins with '#')
26 * 3. A type section line (begins with '[')
27 * 4. Character map line, formatted as such:
28 * Key code value, followed by one or more space or tab characters.
29 * Display value, followed by one or more space or tab characters.
30 * Number value, followed by one or more space or tab characters.
31 * Base value, followed by one or more space or tab characters.
32 * Caps value, followed by one or more space or tab characters.
33 * Fn value, followed by one or more space or tab characters.
34 * Caps_fn value, followed by one or more space or tab characters.
35 * All values, except for the key code value must be either in character
36 * form ('X', where X is the value), or in hexadecimal form (0xXXXX, where
37 * XXXX is hexadecimal representation of the value). Note that if value is
38 * in hexadecimal form, it must not exceed value that can be contained in
39 * variable of 'unsigned short' type.
40 * Bellow are a couple of examples of valid .kcm file lines:
41 * # keycode display number base caps fn caps_fn
42 * A 'A' '2' 'a' 'A' '#' 0x00
43 * PERIOD '.' '.' '.' ':' ':' 0x2026
44 * SPACE 0x20 0x20 0x20 0x20 0xEF01 0xEF01
45 */
46
47 /* Maximum length of a line expected in .kcm file. */
48 #define KCM_MAX_LINE_LEN 1024
49
50 /* Maximum length of a token in a key map line. */
51 #define KCM_MAX_TOKEN_LEN 512
52
53 /* Maps symbol name from .kcm file to a keycode value. */
54 typedef struct AKeycodeMapEntry {
55 /* Symbol name from .kcm file. */
56 const char* key_name;
57
58 /* Key code value for the symbol. */
59 int key_code;
60 } AKeycodeMapEntry;
61
62 /* Result of parsing a line in a .kcm file. */
63 typedef enum {
64 /* Line format was bad. */
65 BAD_FORMAT,
66
67 /* Line had been skipped (an empty line, or a comment, etc.). */
68 SKIP_LINE,
69
70 /* Line represents an entry in the key map. */
71 KEY_ENTRY,
72 } ParseStatus;
73
74 static const AKeycodeMapEntry keycode_map[] = {
75 /* Symbol Key code */
76
77 { "A", kKeyCodeA },
78 { "B", kKeyCodeB },
79 { "C", kKeyCodeC },
80 { "D", kKeyCodeD },
81 { "E", kKeyCodeE },
82 { "F", kKeyCodeF },
83 { "G", kKeyCodeG },
84 { "H", kKeyCodeH },
85 { "I", kKeyCodeI },
86 { "J", kKeyCodeJ },
87 { "K", kKeyCodeK },
88 { "L", kKeyCodeL },
89 { "M", kKeyCodeM },
90 { "N", kKeyCodeN },
91 { "O", kKeyCodeO },
92 { "P", kKeyCodeP },
93 { "Q", kKeyCodeQ },
94 { "R", kKeyCodeR },
95 { "S", kKeyCodeS },
96 { "T", kKeyCodeT },
97 { "U", kKeyCodeU },
98 { "V", kKeyCodeV },
99 { "W", kKeyCodeW },
100 { "X", kKeyCodeX },
101 { "Y", kKeyCodeY },
102 { "Z", kKeyCodeZ },
103 { "0", kKeyCode0 },
104 { "1", kKeyCode1 },
105 { "2", kKeyCode2 },
106 { "3", kKeyCode3 },
107 { "4", kKeyCode4 },
108 { "5", kKeyCode5 },
109 { "6", kKeyCode6 },
110 { "7", kKeyCode7 },
111 { "8", kKeyCode8 },
112 { "9", kKeyCode9 },
113 { "COMMA", kKeyCodeComma },
114 { "PERIOD", kKeyCodePeriod },
115 { "AT", kKeyCodeAt },
116 { "SLASH", kKeyCodeSlash },
117 { "SPACE", kKeyCodeSpace },
118 { "ENTER", kKeyCodeNewline },
119 { "TAB", kKeyCodeTab },
120 { "GRAVE", kKeyCodeGrave },
121 { "MINUS", kKeyCodeMinus },
122 { "EQUALS", kKeyCodeEquals },
123 { "LEFT_BRACKET", kKeyCodeLeftBracket },
124 { "RIGHT_BRACKET", kKeyCodeRightBracket },
125 { "BACKSLASH", kKeyCodeBackslash },
126 { "SEMICOLON", kKeyCodeSemicolon },
127 { "APOSTROPHE", kKeyCodeApostrophe },
128 { "STAR", kKeyCodeStar },
129 { "POUND", kKeyCodePound },
130 { "PLUS", kKeyCodePlus },
131 { "DEL", kKeyCodeDel },
132 };
133
134 /* the following is automatically generated by the 'gen-charmap.py' script
135 * do not touch. the generation command was:
136 * gen-charmap.py qwerty2.kcm
137 */
138
139 static const AKeyEntry _qwerty2_keys[] =
140 {
141 /* keycode base caps fn caps+fn number */
142
143 { kKeyCodeA , 'a', 'A', 'a', 'A', 'a' },
144 { kKeyCodeB , 'b', 'B', 'b', 'B', 'b' },
145 { kKeyCodeC , 'c', 'C', 0x00e7, 0x00E7, 'c' },
146 { kKeyCodeD , 'd', 'D', '\'', '\'', '\'' },
147 { kKeyCodeE , 'e', 'E', '"', 0x0301, '"' },
148 { kKeyCodeF , 'f', 'F', '[', '[', '[' },
149 { kKeyCodeG , 'g', 'G', ']', ']', ']' },
150 { kKeyCodeH , 'h', 'H', '<', '<', '<' },
151 { kKeyCodeI , 'i', 'I', '-', 0x0302, '-' },
152 { kKeyCodeJ , 'j', 'J', '>', '>', '>' },
153 { kKeyCodeK , 'k', 'K', ';', '~', ';' },
154 { kKeyCodeL , 'l', 'L', ':', '`', ':' },
155 { kKeyCodeM , 'm', 'M', '%', 0x00, '%' },
156 { kKeyCodeN , 'n', 'N', 0x00, 0x0303, 'n' },
157 { kKeyCodeO , 'o', 'O', '+', '+', '+' },
158 { kKeyCodeP , 'p', 'P', '=', 0x00A5, '=' },
159 { kKeyCodeQ , 'q', 'Q', '|', 0x0300, '|' },
160 { kKeyCodeR , 'r', 'R', '`', 0x20AC, '`' },
161 { kKeyCodeS , 's', 'S', '\\', 0x00DF, '\\' },
162 { kKeyCodeT , 't', 'T', '{', 0x00A3, '}' },
163 { kKeyCodeU , 'u', 'U', '_', 0x0308, '_' },
164 { kKeyCodeV , 'v', 'V', 'v', 'V', 'v' },
165 { kKeyCodeW , 'w', 'W', '~', '~', '~' },
166 { kKeyCodeX , 'x', 'X', 'x', 'X', 'x' },
167 { kKeyCodeY , 'y', 'Y', '}', 0x00A1, '}' },
168 { kKeyCodeZ , 'z', 'Z', 'z', 'Z', 'z' },
169 { kKeyCodeComma , ',', '<', ',', ',', ',' },
170 { kKeyCodePeriod , '.', '>', '.', 0x2026, '.' },
171 { kKeyCodeAt , '@', '@', '@', 0x2022, '@' },
172 { kKeyCodeSlash , '/', '?', '?', '?', '/' },
173 { kKeyCodeSpace , 0x20, 0x20, 0x9, 0x9, 0x20 },
174 { kKeyCodeNewline , 0xa, 0xa, 0xa, 0xa, 0xa },
175 { kKeyCode0 , '0', ')', ')', ')', '0' },
176 { kKeyCode1 , '1', '!', '!', '!', '1' },
177 { kKeyCode2 , '2', '@', '@', '@', '2' },
178 { kKeyCode3 , '3', '#', '#', '#', '3' },
179 { kKeyCode4 , '4', '$', '$', '$', '4' },
180 { kKeyCode5 , '5', '%', '%', '%', '5' },
181 { kKeyCode6 , '6', '^', '^', '^', '6' },
182 { kKeyCode7 , '7', '&', '&', '&', '7' },
183 { kKeyCode8 , '8', '*', '*', '*', '8' },
184 { kKeyCode9 , '9', '(', '(', '(', '9' },
185 { kKeyCodeTab , 0x9, 0x9, 0x9, 0x9, 0x9 },
186 { kKeyCodeGrave , '`', '~', '`', '~', '`' },
187 { kKeyCodeMinus , '-', '_', '-', '_', '-' },
188 { kKeyCodeEquals , '=', '+', '=', '+', '=' },
189 { kKeyCodeLeftBracket , '[', '{', '[', '{', '[' },
190 { kKeyCodeRightBracket , ']', '}', ']', '}', ']' },
191 { kKeyCodeBackslash , '\\', '|', '\\', '|', '\\' },
192 { kKeyCodeSemicolon , ';', ':', ';', ':', ';' },
193 { kKeyCodeApostrophe , '\'', '"', '\'', '"', '\'' },
194 };
195
196 static const AKeyCharmap _default_charmap =
197 {
198 _qwerty2_keys,
199 51,
200 "qwerty2"
201 };
202
203 /* Custom character map created with -charmap option. */
204 static AKeyCharmap android_custom_charmap = { 0 };
205
206 static const AKeyCharmap* android_charmap = &_default_charmap;
207
208 /* Checks if a character represents an end of the line.
209 * Returns a non-zero value if ch is an EOL character. Returns
210 * zero value if ch is not an EOL character.
211 */
212 static int
kcm_is_eol(char ch)213 kcm_is_eol(char ch) {
214 // EOLs are 0, \r and \n chars.
215 return ('\0' == ch) || ('\n' == ch) || ('\r' == ch);
216 }
217
218 /* Checks if a character represents a token separator.
219 * Returns a non-zero value if ch is a token separator.
220 * Returns zero value if ch is not a token separator.
221 */
222 static int
kcm_is_token_separator(char ch)223 kcm_is_token_separator(char ch) {
224 // Spaces and tabs are the only separators allowed
225 // between tokens in .kcm files.
226 return (' ' == ch) || ('\t' == ch);
227 }
228
229 /* Checks if a character represents a path separator.
230 * Returns a non-zero value if ch is a path separator.
231 * Returns zero value if ch is not a path separator.
232 */
233 static int
kcm_is_path_separator(char ch)234 kcm_is_path_separator(char ch) {
235 #ifdef _WIN32
236 return '/' == ch || '\\' == ch;
237 #else
238 return '/' == ch;
239 #endif // _WIN32
240 }
241
242 /* Skips space separators in a string.
243 * str - string to advance past space separators.
244 * Returns pointer to the first character in the string, that is
245 * not a space separator. Note that this routine may return
246 * pointer to EOL in case if all characters in the string were
247 * space separators.
248 */
249 static const char*
kcm_skip_spaces(const char * str)250 kcm_skip_spaces(const char* str) {
251 while (!kcm_is_eol(*str) && kcm_is_token_separator(*str)) {
252 str++;
253 }
254 return str;
255 }
256
257 /* Advances string to the first space separator character.
258 * str - string to advance.
259 * Returns pointer to the first space separator character in the string.
260 * Note that this routine may return pointer to EOL in case if all
261 * characters in the string were not space separators.
262 */
263 static const char*
kcm_skip_non_spaces(const char * str)264 kcm_skip_non_spaces(const char* str) {
265 while (!kcm_is_eol(*str) && !kcm_is_token_separator(*str)) {
266 str++;
267 }
268 return str;
269 }
270
271 /* Gets first token from a string.
272 * line - String to get token from. End of the string should be
273 * determined using kcm_is_eol() routine.
274 * token - String where to copy token. Token, copied to this
275 * string will be zero-terminated. Note that buffer for the
276 * token string must be large enough to fit token of any size.
277 * max_token_len - character size of the buffer addressed by
278 * the 'token' parameter.
279 * Returns NULL if there were no tokens found in the string, or
280 * a pointer to the line string, advanced past the found token.
281 */
282 static const char*
kcm_get_token(const char * line,char * token,size_t max_token_len)283 kcm_get_token(const char* line, char* token, size_t max_token_len) {
284 // Pass spaces and tabs.
285 const char* token_starts = kcm_skip_spaces(line);
286 // Advance to next space.
287 const char* token_ends = kcm_skip_non_spaces(token_starts);
288 // Calc token length
289 size_t token_len = token_ends - token_starts;
290 if ((0 == token_len) || (token_len >= max_token_len)) {
291 return NULL;
292 }
293 memcpy(token, token_starts, token_len);
294 token[token_len] = '\0';
295 return token_ends;
296 }
297
298 /* Checks if token represents a comment.
299 * Returns non-zero value if token represents a comment, or zero otherwise.
300 */
301 static int
kcm_is_token_comment(const char * token)302 kcm_is_token_comment(const char* token) {
303 return '#' == *token;
304 }
305
306 /* Converts a key name to a key code as defined by AndroidKeyCode enum.
307 * key_name - Key name to convert.
308 * key_code - Upon success contains key code value for the key_name.
309 * Returns a zero value on success, or -1 if key code was not found
310 * for the given key_name.
311 */
312 static int
kcm_get_key_code(const char * key_name,unsigned short * key_code)313 kcm_get_key_code(const char* key_name, unsigned short* key_code) {
314 int n;
315 // Iterate through the key code map, matching key names.
316 for (n = 0; n < sizeof(keycode_map) / sizeof(keycode_map[0]); n++) {
317 if (0 == strcmp(key_name, keycode_map[n].key_name)) {
318 *key_code = keycode_map[n].key_code;
319 return 0;
320 }
321 }
322 return -1;
323 }
324
325 /* Gets unsigned short hexadecimal value for a token.
326 * token - Token to get hexadecimal value for. Note that this
327 * routine expects a "clean" (i.e. no "0x" prefix) hex number
328 * represented by the token string.
329 * val - Upon success contains hexadecimal value for the token.
330 * Returns a zero value on success, or -1 on error.
331 */
332 static int
kcm_get_ushort_hex_val(const char * token,unsigned short * val)333 kcm_get_ushort_hex_val(const char* token, unsigned short* val) {
334 int hex_val = hex2int((const uint8_t*)token, strlen(token));
335 // Make sure token format was ok and value doesn't exceed unsigned short.
336 if (-1 == hex_val || 0 != (hex_val & ~0xFFFF)) {
337 return -1;
338 }
339
340 *val = (unsigned short)hex_val;
341
342 return 0;
343 }
344
345 /* Gets a character or hexadecimal value represented by a token.
346 * token - Token to get value from.
347 * val - Upon success will contain a character or hexadecimal
348 * value represented by a token.
349 * Returns a zero value on success, or -1 on error.
350 */
351 static int
kcm_get_char_or_hex_val(const char * token,unsigned short * val)352 kcm_get_char_or_hex_val(const char* token, unsigned short* val) {
353 // For chars token must begin with ' followed by character followed by '
354 if ('\'' == *token) {
355 if ('\0' == token[1] || '\'' != token[2] || '\0' != token[3]) {
356 return 0;
357 }
358 *val = token[1];
359 return 0;
360 } else {
361 // Make sure that hex token is prefixed with "0x"
362 if (('0' != *token) || ('x' != token[1])) {
363 return -1;
364 }
365 // Past 0x
366 return kcm_get_ushort_hex_val(token + 2, val);
367 }
368 }
369
370 /* Gets first token for the line and calculates its value.
371 * line - Line to get token's value from.
372 * val - Upon success will contain a character or hexadecimal
373 * value represented by the first token in the line.
374 * returns NULL on error, or a pointer to the line string,
375 * advanced past the found token.
376 */
377 static const char*
kcm_get_char_or_hex_token_value(const char * line,unsigned short * val)378 kcm_get_char_or_hex_token_value(const char* line, unsigned short* val) {
379 char token[KCM_MAX_TOKEN_LEN];
380 line = kcm_get_token(line, token, KCM_MAX_TOKEN_LEN);
381 if (NULL != line) {
382 // Token must be a char, or a hex number.
383 if (kcm_get_char_or_hex_val(token, val)) {
384 return NULL;
385 }
386 }
387
388 return line;
389 }
390
391 /* Parses a line in .kcm file extracting key information.
392 * line - Line in .kcm file to parse.
393 * line_index - Index of the parsing line in .kcm file.
394 * key_entry - Upon success contains key information extracted from
395 * the line.
396 * kcm_file_path - Path to the charmap file, where paresed line was taken from.
397 * returns BAD_FORMAT if line format was not recognized, SKIP_LINE if line
398 * format was ok, but it didn't contain key information, or KEY_ENTRY
399 * if key information was successfuly extracted from the line.
400 */
401 static ParseStatus
kcm_parse_line(const char * line,int line_index,AKeyEntry * key_entry,const char * kcm_file_path)402 kcm_parse_line(const char* line,
403 int line_index,
404 AKeyEntry* key_entry,
405 const char* kcm_file_path) {
406 char token[KCM_MAX_TOKEN_LEN];
407 unsigned short disp;
408
409 // Get first token, and see if it's an empty, or a comment line.
410 line = kcm_get_token(line, token, KCM_MAX_TOKEN_LEN);
411 if ((NULL == line) || kcm_is_token_comment(token)) {
412 // Empty line, or a comment.
413 return SKIP_LINE;
414 }
415
416 // Here we expect either [type=XXXX], or a key string.
417 if ('[' == token[0]) {
418 return SKIP_LINE;
419 }
420
421 // It must be a key string.
422 // First token is key code.
423 if (kcm_get_key_code(token, &key_entry->code)) {
424 derror("Invalid format of charmap file %s. Unknown key %s in line %d",
425 kcm_file_path, token, line_index);
426 return BAD_FORMAT;
427 }
428
429 // 2-nd token is display character, which is ignored.
430 line = kcm_get_char_or_hex_token_value(line, &disp);
431 if (NULL == line) {
432 derror("Invalid format of charmap file %s. Invalid display value in line %d",
433 kcm_file_path, line_index);
434 return BAD_FORMAT;
435 }
436
437 // 3-rd token is number.
438 line = kcm_get_char_or_hex_token_value(line, &key_entry->number);
439 if (NULL == line) {
440 derror("Invalid format of charmap file %s. Invalid number value in line %d",
441 kcm_file_path, line_index);
442 return BAD_FORMAT;
443 }
444
445 // 4-th token is base.
446 line = kcm_get_char_or_hex_token_value(line, &key_entry->base);
447 if (NULL == line) {
448 derror("Invalid format of charmap file %s. Invalid base value in line %d",
449 kcm_file_path, line_index);
450 return BAD_FORMAT;
451 }
452
453 // 5-th token is caps.
454 line = kcm_get_char_or_hex_token_value(line, &key_entry->caps);
455 if (NULL == line) {
456 derror("Invalid format of charmap file %s. Invalid caps value in line %d",
457 kcm_file_path, line_index);
458 return BAD_FORMAT;
459 }
460
461 // 6-th token is fn.
462 line = kcm_get_char_or_hex_token_value(line, &key_entry->fn);
463 if (NULL == line) {
464 derror("Invalid format of charmap file %s. Invalid fn value in line %d",
465 kcm_file_path, line_index);
466 return BAD_FORMAT;
467 }
468
469 // 7-th token is caps_fn.
470 line = kcm_get_char_or_hex_token_value(line, &key_entry->caps_fn);
471 if (NULL == line) {
472 derror("Invalid format of charmap file %s. Invalid caps_fn value in line %d",
473 kcm_file_path, line_index);
474 return BAD_FORMAT;
475 }
476
477 // Make sure that line doesn't contain anything else,
478 // except (may be) a comment token.
479 line = kcm_get_token(line, token, KCM_MAX_TOKEN_LEN);
480 if ((NULL == line) || kcm_is_token_comment(token)) {
481 return KEY_ENTRY;
482 } else {
483 derror("Invalid format of charmap file %s in line %d",
484 kcm_file_path, line_index);
485 return BAD_FORMAT;
486 }
487 }
488
489 void
kcm_extract_charmap_name(const char * kcm_file_path,char * charmap_name,int max_len)490 kcm_extract_charmap_name(const char* kcm_file_path,
491 char* charmap_name,
492 int max_len) {
493 const char* ext_separator;
494 size_t to_copy;
495
496 // Initialize charmap name with name of .kcm file.
497 // First, get file name from the full path to .kcm file.
498 const char* file_name = kcm_file_path + strlen(kcm_file_path);
499 while (!kcm_is_path_separator(*file_name) &&
500 (file_name != kcm_file_path)) {
501 file_name--;
502 }
503 if (kcm_is_path_separator(*file_name)) {
504 file_name++;
505 }
506
507 // Cut off file name extension.
508 ext_separator = strrchr(file_name, '.');
509 if (NULL == ext_separator) {
510 // "filename" is legal name.
511 ext_separator = file_name + strlen(file_name);
512 } else if (ext_separator == file_name) {
513 // ".filename" is legal name too. In this case we will use
514 // "filename" as our custom charmap name.
515 file_name++;
516 ext_separator = file_name + strlen(file_name);
517 }
518
519 // Copy file name to charmap name.
520 to_copy = ext_separator - file_name;
521 if (to_copy > (max_len - 1)) {
522 to_copy = max_len - 1;
523 }
524 memcpy(charmap_name, file_name, to_copy);
525 charmap_name[to_copy] = '\0';
526 }
527
528 /* Extracts charmap name from .kcm file name,
529 * and saves it into char_map as its name.
530 */
531 static void
kcm_get_charmap_name(const char * kcm_file_path,AKeyCharmap * char_map)532 kcm_get_charmap_name(const char* kcm_file_path, AKeyCharmap* char_map) {
533 kcm_extract_charmap_name(kcm_file_path, char_map->name,
534 sizeof(char_map->name));
535 }
536
537 /* Parses .kcm file producing key characters map.
538 * See comments to this module for .kcm file format information.
539 * This routine checks format only for character map lines. It will not check
540 * format for empty lines, comments, and type section lines.
541 * Note that line length in .kcm file should not exceed 1024 characters,
542 * including newline character.
543 *
544 * Parameters:
545 * kcm_file_path - Full path to the .kcm file to parse.
546 * char_map - Upon success will contain initialized characters map.
547 * Returns a zero value on success, or -1 on failure.
548 */
549 static int
parse_kcm_file(const char * kcm_file_path,AKeyCharmap * char_map)550 parse_kcm_file(const char* kcm_file_path, AKeyCharmap* char_map) {
551 // A line read from .kcm file.
552 char line[KCM_MAX_LINE_LEN];
553 // Return code.
554 int err = 0;
555 // Number of the currently parsed line.
556 int cur_line = 1;
557 // Initial size of the charmap's array of keys.
558 int map_size = 52;
559 FILE* kcm_file;
560
561 char_map->num_entries = 0;
562 char_map->entries = 0;
563
564 kcm_file = fopen(kcm_file_path, "r");
565 if (NULL == kcm_file) {
566 derror("Unable to open charmap file %s : %s",
567 kcm_file_path, strerror(errno));
568 return -1;
569 }
570
571 // Calculate charmap name.
572 kcm_get_charmap_name(kcm_file_path, char_map);
573
574 // Preallocate map.
575 char_map->num_entries = 0;
576 AARRAY_NEW0(char_map->entries, map_size);
577
578 // Line by line parse the file.
579 for (; 0 != fgets(line, sizeof(line), kcm_file); cur_line++) {
580 AKeyEntry key_entry;
581 ParseStatus parse_res =
582 kcm_parse_line(line, cur_line, &key_entry, kcm_file_path);
583 if (BAD_FORMAT == parse_res) {
584 err = -1;
585 break;
586 } else if (KEY_ENTRY == parse_res) {
587 AKeyEntry* entries;
588 // Key information has been extracted. Add it to the map.
589 // Lets see if we need to reallocate map.
590 if (map_size == char_map->num_entries) {
591 AKeyEntry* entries = (AKeyEntry*)char_map->entries;
592 map_size += 10;
593 AARRAY_RENEW(entries, map_size);
594 char_map->entries = (const AKeyEntry*)entries;
595 }
596 entries = (AKeyEntry*)char_map->entries;
597 entries[char_map->num_entries] = key_entry;
598 char_map->num_entries++;
599 }
600 }
601
602 if (!err) {
603 // Make sure we exited the loop on EOF condition. Any other
604 // condition is an error.
605 if (0 == feof(kcm_file)) {
606 err = -1;
607 }
608 if (err) {
609 derror("Error reading charmap file %s : %s",
610 kcm_file_path, strerror(errno));
611 }
612 }
613
614 fclose(kcm_file);
615
616 if (err) {
617 // Cleanup on failure.
618 if (0 != char_map->entries) {
619 AFREE((void*)char_map->entries);
620 char_map->entries = 0;
621 }
622 char_map->num_entries = 0;
623 }
624
625 return err;
626 }
627
628 int
android_charmap_setup(const char * kcm_file_path)629 android_charmap_setup(const char* kcm_file_path) {
630
631 /* Return if we already loaded a charmap */
632 if (android_charmap != &_default_charmap || kcm_file_path == NULL)
633 return 0;
634
635 if (!parse_kcm_file(kcm_file_path, &android_custom_charmap)) {
636 // Here we have the default charmap and the custom one.
637 android_charmap = &android_custom_charmap;
638 } else {
639 derror("Unable to parse kcm file.");
640 return -1;
641 }
642
643 return 0;
644 }
645
646 void
android_charmap_done(void)647 android_charmap_done(void) {
648 if (android_charmap != &_default_charmap)
649 AFREE((void*)android_charmap->entries);
650 }
651
652 const AKeyCharmap*
android_get_charmap_by_name(const char * name)653 android_get_charmap_by_name(const char* name) {
654 if (name != NULL) {
655 if (!strcmp(android_charmap->name, name))
656 return android_charmap;
657 if (!strcmp(_default_charmap.name, name))
658 return &_default_charmap;
659 }
660 return NULL;
661 }
662
663 int
android_charmap_reverse_map_unicode(const AKeyCharmap * cmap,unsigned int unicode,int down,AKeycodeBuffer * keycodes)664 android_charmap_reverse_map_unicode(const AKeyCharmap* cmap,
665 unsigned int unicode,
666 int down,
667 AKeycodeBuffer* keycodes)
668 {
669 int n;
670
671 if (unicode == 0)
672 return 0;
673
674 /* check base keys */
675 for (n = 0; n < cmap->num_entries; n++) {
676 if (cmap->entries[n].base == unicode) {
677 android_keycodes_add_key_event(keycodes, cmap->entries[n].code, down);
678 return 1;
679 }
680 }
681
682 /* check caps + keys */
683 for (n = 0; n < cmap->num_entries; n++) {
684 if (cmap->entries[n].caps == unicode) {
685 if (down) {
686 android_keycodes_add_key_event(keycodes, kKeyCodeCapLeft, down);
687 }
688 android_keycodes_add_key_event(keycodes, cmap->entries[n].code, down);
689 if (!down) {
690 android_keycodes_add_key_event(keycodes, kKeyCodeCapLeft, down);
691 }
692 return 2;
693 }
694 }
695
696 /* check fn + keys */
697 for (n = 0; n < cmap->num_entries; n++) {
698 if (cmap->entries[n].fn == unicode) {
699 if (down) {
700 android_keycodes_add_key_event(keycodes, kKeyCodeAltLeft, down);
701 }
702 android_keycodes_add_key_event(keycodes, cmap->entries[n].code, down);
703 if (!down) {
704 android_keycodes_add_key_event(keycodes, kKeyCodeAltLeft, down);
705 }
706 return 2;
707 }
708 }
709
710 /* check caps + fn + keys */
711 for (n = 0; n < cmap->num_entries; n++) {
712 if (cmap->entries[n].caps_fn == unicode) {
713 if (down) {
714 android_keycodes_add_key_event(keycodes, kKeyCodeAltLeft, down);
715 android_keycodes_add_key_event(keycodes, kKeyCodeCapLeft, down);
716 }
717 android_keycodes_add_key_event(keycodes, cmap->entries[n].code, down);
718 if (!down) {
719 android_keycodes_add_key_event(keycodes, kKeyCodeCapLeft, down);
720 android_keycodes_add_key_event(keycodes, kKeyCodeAltLeft, down);
721 }
722 return 3;
723 }
724 }
725
726 /* no match */
727 return 0;
728 }
729
android_get_default_charmap(void)730 const AKeyCharmap* android_get_default_charmap(void)
731 {
732 return &_default_charmap;
733 }
734
android_get_charmap(void)735 const AKeyCharmap* android_get_charmap(void)
736 {
737 return android_charmap;
738 }
739
android_get_charmap_name(void)740 const char* android_get_charmap_name(void)
741 {
742 return android_get_charmap()->name;
743 }
744