Home | History | Annotate | Download | only in skin
      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