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