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 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 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 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* 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* 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* 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 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 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 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 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* 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 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 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 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 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 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 647 android_charmap_done(void) { 648 if (android_charmap != &_default_charmap) 649 AFREE((void*)android_charmap->entries); 650 } 651 652 const AKeyCharmap* 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 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 730 const AKeyCharmap* android_get_default_charmap(void) 731 { 732 return &_default_charmap; 733 } 734 735 const AKeyCharmap* android_get_charmap(void) 736 { 737 return android_charmap; 738 } 739 740 const char* android_get_charmap_name(void) 741 { 742 return android_get_charmap()->name; 743 } 744