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 , 33static const char* const command_strings[ SKIN_KEY_COMMAND_MAX ] = { 34 SKIN_KEY_COMMAND_LIST 35}; 36#undef _SKIN_KEY_COMMAND 37 38const char* 39skin_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 47SkinKeyCommand 48skin_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 , 64static const char* const command_descriptions[ SKIN_KEY_COMMAND_MAX ] = { 65 SKIN_KEY_COMMAND_LIST 66}; 67#undef _SKIN_KEY_COMMAND 68 69const char* 70skin_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 }, 199static const struct { int _sym; const char* _str; } keysym_names[] = 200{ 201 _KEYSYM_LIST 202 { 0, NULL } 203}; 204#undef _KEYSYM_ 205 206int 207skin_keysym_str_count( void ) 208{ 209 return sizeof(keysym_names)/sizeof(keysym_names[0])-1; 210} 211 212const char* 213skin_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 221const char* 222skin_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 263int 264skin_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 323typedef struct { 324 int sym; 325 int mod; 326 SkinKeyCommand command; 327} SkinKeyItem; 328 329 330struct SkinKeyset { 331 int num_items; 332 int max_items; 333 SkinKeyItem* items; 334}; 335 336 337static int 338skin_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 382SkinKeyset* 383skin_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 434SkinKeyset* 435skin_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 450void 451skin_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 463extern int 464skin_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 */ 491SkinKeyCommand 492skin_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 508const char* 509skin_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