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