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/skin/keyset.h" 13 #include "android/utils/debug.h" 14 #include "android/utils/bufprint.h" 15 #include "android/android.h" 16 #include <SDL.h> 17 18 #define DEBUG 1 19 20 #if 1 21 # define D_ACTIVE VERBOSE_CHECK(keys) 22 #else 23 # define D_ACTIVE DEBUG 24 #endif 25 26 #if DEBUG 27 # define D(...) VERBOSE_PRINT(keys,__VA_ARGS__) 28 #else 29 # define D(...) ((void)0) 30 #endif 31 32 #define _SKIN_KEY_COMMAND(x,y) #x , 33 static const char* const command_strings[ SKIN_KEY_COMMAND_MAX ] = { 34 SKIN_KEY_COMMAND_LIST 35 }; 36 #undef _SKIN_KEY_COMMAND 37 38 const char* 39 skin_key_command_to_str( SkinKeyCommand cmd ) 40 { 41 if (cmd > SKIN_KEY_COMMAND_NONE && cmd < SKIN_KEY_COMMAND_MAX) 42 return command_strings[cmd]; 43 44 return NULL; 45 } 46 47 SkinKeyCommand 48 skin_key_command_from_str( const char* str, int len ) 49 { 50 int nn; 51 if (len < 0) 52 len = strlen(str); 53 for (nn = 0; nn < SKIN_KEY_COMMAND_MAX; nn++) { 54 const char* cmd = command_strings[nn]; 55 56 if ( !memcmp( cmd, str, len ) && cmd[len] == 0 ) 57 return (SkinKeyCommand) nn; 58 } 59 return SKIN_KEY_COMMAND_NONE; 60 } 61 62 63 #define _SKIN_KEY_COMMAND(x,y) y , 64 static const char* const command_descriptions[ SKIN_KEY_COMMAND_MAX ] = { 65 SKIN_KEY_COMMAND_LIST 66 }; 67 #undef _SKIN_KEY_COMMAND 68 69 const char* 70 skin_key_command_description( SkinKeyCommand cmd ) 71 { 72 if (cmd > SKIN_KEY_COMMAND_NONE && cmd < SKIN_KEY_COMMAND_MAX) 73 return command_descriptions[cmd]; 74 75 return NULL; 76 } 77 78 #define _KEYSYM1_(x) _KEYSYM_(x,x) 79 80 #define _KEYSYM_LIST \ 81 _KEYSYM1_(BACKSPACE) \ 82 _KEYSYM1_(TAB) \ 83 _KEYSYM1_(CLEAR) \ 84 _KEYSYM_(RETURN,ENTER) \ 85 _KEYSYM1_(PAUSE) \ 86 _KEYSYM1_(ESCAPE) \ 87 _KEYSYM1_(SPACE) \ 88 _KEYSYM_(EXCLAIM,EXCLAM) \ 89 _KEYSYM_(QUOTEDBL,DOUBLEQUOTE) \ 90 _KEYSYM_(HASH,HASH) \ 91 _KEYSYM1_(DOLLAR) \ 92 _KEYSYM1_(AMPERSAND) \ 93 _KEYSYM1_(QUOTE) \ 94 _KEYSYM_(LEFTPAREN,LPAREN) \ 95 _KEYSYM_(RIGHTPAREN,RPAREN) \ 96 _KEYSYM1_(ASTERISK) \ 97 _KEYSYM1_(PLUS) \ 98 _KEYSYM1_(COMMA) \ 99 _KEYSYM1_(MINUS) \ 100 _KEYSYM1_(PERIOD) \ 101 _KEYSYM1_(SLASH) \ 102 _KEYSYM1_(0) \ 103 _KEYSYM1_(1) \ 104 _KEYSYM1_(2) \ 105 _KEYSYM1_(3) \ 106 _KEYSYM1_(4) \ 107 _KEYSYM1_(5) \ 108 _KEYSYM1_(6) \ 109 _KEYSYM1_(7) \ 110 _KEYSYM1_(8) \ 111 _KEYSYM1_(9) \ 112 _KEYSYM1_(COLON) \ 113 _KEYSYM1_(SEMICOLON) \ 114 _KEYSYM1_(LESS) \ 115 _KEYSYM_(EQUALS,EQUAL) \ 116 _KEYSYM1_(GREATER) \ 117 _KEYSYM1_(QUESTION) \ 118 _KEYSYM1_(AT) \ 119 _KEYSYM1_(LEFTBRACKET) \ 120 _KEYSYM1_(BACKSLASH) \ 121 _KEYSYM1_(RIGHTBRACKET) \ 122 _KEYSYM1_(CARET) \ 123 _KEYSYM1_(UNDERSCORE) \ 124 _KEYSYM1_(BACKQUOTE) \ 125 _KEYSYM_(a,A) \ 126 _KEYSYM_(b,B) \ 127 _KEYSYM_(c,C) \ 128 _KEYSYM_(d,D) \ 129 _KEYSYM_(e,E) \ 130 _KEYSYM_(f,F) \ 131 _KEYSYM_(g,G) \ 132 _KEYSYM_(h,H) \ 133 _KEYSYM_(i,I) \ 134 _KEYSYM_(j,J) \ 135 _KEYSYM_(k,K) \ 136 _KEYSYM_(l,L) \ 137 _KEYSYM_(m,M) \ 138 _KEYSYM_(n,N) \ 139 _KEYSYM_(o,O) \ 140 _KEYSYM_(p,P) \ 141 _KEYSYM_(q,Q) \ 142 _KEYSYM_(r,R) \ 143 _KEYSYM_(s,S) \ 144 _KEYSYM_(t,T) \ 145 _KEYSYM_(u,U) \ 146 _KEYSYM_(v,V) \ 147 _KEYSYM_(w,W) \ 148 _KEYSYM_(x,X) \ 149 _KEYSYM_(y,Y) \ 150 _KEYSYM_(z,Z) \ 151 _KEYSYM1_(DELETE) \ 152 _KEYSYM_(KP_PLUS,KEYPAD_PLUS) \ 153 _KEYSYM_(KP_MINUS,KEYPAD_MINUS) \ 154 _KEYSYM_(KP_MULTIPLY,KEYPAD_MULTIPLY) \ 155 _KEYSYM_(KP_DIVIDE,KEYPAD_DIVIDE) \ 156 _KEYSYM_(KP_ENTER,KEYPAD_ENTER) \ 157 _KEYSYM_(KP_PERIOD,KEYPAD_PERIOD) \ 158 _KEYSYM_(KP_EQUALS,KEYPAD_EQUALS) \ 159 _KEYSYM_(KP1,KEYPAD_1) \ 160 _KEYSYM_(KP2,KEYPAD_2) \ 161 _KEYSYM_(KP3,KEYPAD_3) \ 162 _KEYSYM_(KP4,KEYPAD_4) \ 163 _KEYSYM_(KP5,KEYPAD_5) \ 164 _KEYSYM_(KP6,KEYPAD_6) \ 165 _KEYSYM_(KP7,KEYPAD_7) \ 166 _KEYSYM_(KP8,KEYPAD_8) \ 167 _KEYSYM_(KP9,KEYPAD_9) \ 168 _KEYSYM_(KP0,KEYPAD_0) \ 169 _KEYSYM1_(UP) \ 170 _KEYSYM1_(DOWN) \ 171 _KEYSYM1_(RIGHT) \ 172 _KEYSYM1_(LEFT) \ 173 _KEYSYM1_(INSERT) \ 174 _KEYSYM1_(HOME) \ 175 _KEYSYM1_(END) \ 176 _KEYSYM1_(PAGEUP) \ 177 _KEYSYM1_(PAGEDOWN) \ 178 _KEYSYM1_(F1) \ 179 _KEYSYM1_(F2) \ 180 _KEYSYM1_(F3) \ 181 _KEYSYM1_(F4) \ 182 _KEYSYM1_(F5) \ 183 _KEYSYM1_(F6) \ 184 _KEYSYM1_(F7) \ 185 _KEYSYM1_(F8) \ 186 _KEYSYM1_(F9) \ 187 _KEYSYM1_(F10) \ 188 _KEYSYM1_(F11) \ 189 _KEYSYM1_(F12) \ 190 _KEYSYM1_(F13) \ 191 _KEYSYM1_(F14) \ 192 _KEYSYM1_(F15) \ 193 _KEYSYM1_(SCROLLOCK) \ 194 _KEYSYM1_(SYSREQ) \ 195 _KEYSYM1_(PRINT) \ 196 _KEYSYM1_(BREAK) \ 197 198 #define _KEYSYM_(x,y) { SDLK_##x, #y }, 199 static const struct { int _sym; const char* _str; } keysym_names[] = 200 { 201 _KEYSYM_LIST 202 { 0, NULL } 203 }; 204 #undef _KEYSYM_ 205 206 int 207 skin_keysym_str_count( void ) 208 { 209 return sizeof(keysym_names)/sizeof(keysym_names[0])-1; 210 } 211 212 const char* 213 skin_keysym_str( int index ) 214 { 215 if (index >= 0 && index < skin_keysym_str_count()) 216 return keysym_names[index]._str; 217 218 return NULL; 219 } 220 221 const char* 222 skin_key_symmod_to_str( int sym, int mod ) 223 { 224 static char temp[32]; 225 char* p = temp; 226 char* end = p + sizeof(temp); 227 int nn; 228 229 if ((mod & KMOD_LCTRL) != 0) { 230 p = bufprint(p, end, "Ctrl-"); 231 } 232 if ((mod & KMOD_RCTRL) != 0) { 233 p = bufprint(p, end, "RCtrl-"); 234 } 235 if ((mod & KMOD_LSHIFT) != 0) { 236 p = bufprint(p, end, "Shift-"); 237 } 238 if ((mod & KMOD_RSHIFT) != 0) { 239 p = bufprint(p, end, "RShift-"); 240 } 241 if ((mod & KMOD_LALT) != 0) { 242 p = bufprint(p, end, "Alt-"); 243 } 244 if ((mod & KMOD_RALT) != 0) { 245 p = bufprint(p, end, "RAlt-"); 246 } 247 for (nn = 0; keysym_names[nn]._sym != 0; nn++) { 248 if (keysym_names[nn]._sym == sym) { 249 p = bufprint(p, end, "%s", keysym_names[nn]._str); 250 return temp;; 251 } 252 } 253 254 if (sym >= 32 && sym <= 127) { 255 p = bufprint(p, end, "%c", sym); 256 return temp; 257 } 258 259 return NULL; 260 } 261 262 263 int 264 skin_key_symmod_from_str( const char* str, int *psym, int *pmod ) 265 { 266 int mod = 0; 267 int match = 1; 268 int nn; 269 const char* s0 = str; 270 static const struct { const char* prefix; int mod; } mods[] = 271 { 272 { "^", KMOD_LCTRL }, 273 { "Ctrl", KMOD_LCTRL }, 274 { "ctrl", KMOD_LCTRL }, 275 { "RCtrl", KMOD_RCTRL }, 276 { "rctrl", KMOD_RCTRL }, 277 { "Alt", KMOD_LALT }, 278 { "alt", KMOD_LALT }, 279 { "RAlt", KMOD_RALT }, 280 { "ralt", KMOD_RALT }, 281 { "Shift", KMOD_LSHIFT }, 282 { "shift", KMOD_LSHIFT }, 283 { "RShift", KMOD_RSHIFT }, 284 { "rshift", KMOD_RSHIFT }, 285 { NULL, 0 } 286 }; 287 288 while (match) { 289 match = 0; 290 for (nn = 0; mods[nn].prefix != NULL; nn++) { 291 const char* prefix = mods[nn].prefix; 292 int len = strlen(prefix); 293 294 if ( !memcmp(str, prefix, len) ) { 295 str += len; 296 match = 1; 297 mod |= mods[nn].mod; 298 if (str[0] == '-' && str[1] != 0) 299 str++; 300 break; 301 } 302 } 303 } 304 305 for (nn = 0; keysym_names[nn]._sym; nn++) { 306 #ifdef _WIN32 307 if ( !stricmp(str, keysym_names[nn]._str) ) 308 #else 309 if ( !strcasecmp(str, keysym_names[nn]._str) ) 310 #endif 311 { 312 *psym = keysym_names[nn]._sym; 313 *pmod = mod; 314 return 0; 315 } 316 } 317 318 D("%s: can't find sym value for '%s' (mod=%d, str=%s)", __FUNCTION__, s0, mod, str); 319 return -1; 320 } 321 322 323 typedef struct { 324 int sym; 325 int mod; 326 SkinKeyCommand command; 327 } SkinKeyItem; 328 329 330 struct SkinKeyset { 331 int num_items; 332 int max_items; 333 SkinKeyItem* items; 334 }; 335 336 337 static int 338 skin_keyset_add( SkinKeyset* kset, int sym, int mod, SkinKeyCommand command ) 339 { 340 SkinKeyItem* item = kset->items; 341 SkinKeyItem* end = item + kset->num_items; 342 SkinKeyItem* first = NULL; 343 int count = 0; 344 345 D( "adding binding %s to %s", skin_key_command_to_str(command), skin_key_symmod_to_str(sym,mod)); 346 for ( ; item < end; item++) { 347 if (item->command == command) { 348 if (!first) 349 first = item; 350 if (++count == SKIN_KEY_COMMAND_MAX_BINDINGS) { 351 /* replace the first (oldest) one in the list */ 352 first->sym = sym; 353 first->mod = mod; 354 return 0; 355 } 356 continue; 357 } 358 if (item->sym == sym && item->mod == mod) { 359 /* replace a (sym,mod) binding */ 360 item->command = command; 361 return 0; 362 } 363 } 364 if (kset->num_items >= kset->max_items) { 365 int old_size = kset->max_items; 366 int new_size = old_size + (old_size >> 1) + 4; 367 SkinKeyItem* new_items = realloc( kset->items, new_size*sizeof(SkinKeyItem) ); 368 if (new_items == NULL) { 369 return -1; 370 } 371 kset->items = new_items; 372 kset->max_items = new_size; 373 } 374 item = kset->items + kset->num_items++; 375 item->command = command; 376 item->sym = sym; 377 item->mod = mod; 378 return 1; 379 } 380 381 382 SkinKeyset* 383 skin_keyset_new ( AConfig* root ) 384 { 385 SkinKeyset* kset = calloc(1, sizeof(*kset)); 386 AConfig* node = root->first_child;; 387 388 if (kset == NULL) 389 return NULL; 390 391 for ( ; node != NULL; node = node->next ) 392 { 393 SkinKeyCommand command; 394 int sym, mod; 395 char* p; 396 397 command = skin_key_command_from_str( node->name, -1 ); 398 if (command == SKIN_KEY_COMMAND_NONE) { 399 D( "ignoring unknown keyset command '%s'", node->name ); 400 continue; 401 } 402 p = (char*)node->value; 403 while (*p) { 404 char* q = strpbrk( p, " \t,:" ); 405 if (q == NULL) 406 q = p + strlen(p); 407 408 if (q > p) { 409 int len = q - p; 410 char keys[24]; 411 if (len+1 >= (int)sizeof(keys)) { 412 D("key binding too long: '%s'", p); 413 } 414 else { 415 memcpy( keys, p, len ); 416 keys[len] = 0; 417 if ( skin_key_symmod_from_str( keys, &sym, &mod ) < 0 ) { 418 D( "ignoring unknown keys '%s' for command '%s'", 419 keys, node->name ); 420 } else { 421 skin_keyset_add( kset, sym, mod, command ); 422 } 423 } 424 } else if (*q) 425 q += 1; 426 427 p = q; 428 } 429 } 430 return kset; 431 } 432 433 434 SkinKeyset* 435 skin_keyset_new_from_text( const char* text ) 436 { 437 AConfig* root = aconfig_node("",""); 438 char* str = strdup(text); 439 SkinKeyset* result; 440 441 D("kset new from:\n%s", text); 442 aconfig_load( root, str ); 443 result = skin_keyset_new( root ); 444 free(str); 445 D("kset done result=%p", result); 446 return result; 447 } 448 449 450 void 451 skin_keyset_free( SkinKeyset* kset ) 452 { 453 if (kset) { 454 free(kset->items); 455 kset->items = NULL; 456 kset->num_items = 0; 457 kset->max_items = 0; 458 free(kset); 459 } 460 } 461 462 463 extern int 464 skin_keyset_get_bindings( SkinKeyset* kset, 465 SkinKeyCommand command, 466 SkinKeyBinding* bindings ) 467 { 468 if (kset) { 469 int count = 0; 470 SkinKeyItem* item = kset->items; 471 SkinKeyItem* end = item + kset->num_items; 472 473 for ( ; item < end; item++ ) { 474 if (item->command == command) { 475 bindings->sym = item->sym; 476 bindings->mod = item->mod; 477 bindings ++; 478 if ( ++count >= SKIN_KEY_COMMAND_MAX_BINDINGS ) { 479 /* shouldn't happen, but be safe */ 480 break; 481 } 482 } 483 } 484 return count; 485 } 486 return -1; 487 } 488 489 490 /* retrieve the command corresponding to a given (sym,mod) pair. returns SKIN_KEY_COMMAND_NONE if not found */ 491 SkinKeyCommand 492 skin_keyset_get_command( SkinKeyset* kset, int sym, int mod ) 493 { 494 if (kset) { 495 SkinKeyItem* item = kset->items; 496 SkinKeyItem* end = item + kset->num_items; 497 498 for ( ; item < end; item++ ) { 499 if (item->sym == sym && item->mod == mod) { 500 return item->command; 501 } 502 } 503 } 504 return SKIN_KEY_COMMAND_NONE; 505 } 506 507 508 const char* 509 skin_keyset_get_default( void ) 510 { 511 return 512 "BUTTON_CALL F3\n" 513 "BUTTON_HANGUP F4\n" 514 "BUTTON_HOME Home\n" 515 "BUTTON_BACK Escape\n" 516 "BUTTON_MENU F2, PageUp\n" 517 "BUTTON_STAR Shift-F2, PageDown\n" 518 "BUTTON_POWER F7\n" 519 "BUTTON_SEARCH F5\n" 520 "BUTTON_CAMERA Ctrl-Keypad_5, Ctrl-F3\n" 521 "BUTTON_VOLUME_UP Keypad_Plus, Ctrl-F5\n" 522 "BUTTON_VOLUME_DOWN Keypad_Minus, Ctrl-F6\n" 523 524 "TOGGLE_NETWORK F8\n" 525 "TOGGLE_TRACING F9\n" 526 "TOGGLE_FULLSCREEN Alt-Enter\n" 527 528 "BUTTON_DPAD_CENTER Keypad_5\n" 529 "BUTTON_DPAD_UP Keypad_8\n" 530 "BUTTON_DPAD_LEFT Keypad_4\n" 531 "BUTTON_DPAD_RIGHT Keypad_6\n" 532 "BUTTON_DPAD_DOWN Keypad_2\n" 533 534 "TOGGLE_TRACKBALL F6\n" 535 "SHOW_TRACKBALL Delete\n" 536 537 "CHANGE_LAYOUT_PREV Keypad_7, Ctrl-F11\n" 538 "CHANGE_LAYOUT_NEXT Keypad_9, Ctrl-F12\n" 539 "ONION_ALPHA_UP Keypad_Multiply\n" 540 "ONION_ALPHA_DOWN Keypad_Divide\n" 541 ; 542 } 543