diff options
Diffstat (limited to 'android/skin/keyset.c')
-rw-r--r-- | android/skin/keyset.c | 542 |
1 files changed, 542 insertions, 0 deletions
diff --git a/android/skin/keyset.c b/android/skin/keyset.c new file mode 100644 index 0000000..7a92971 --- /dev/null +++ b/android/skin/keyset.c @@ -0,0 +1,542 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "android/skin/keyset.h" +#include "android/utils/debug.h" +#include "android/utils/bufprint.h" +#include "android/android.h" +#include <SDL.h> + +#define DEBUG 1 + +#if 1 +# define D_ACTIVE VERBOSE_CHECK(keys) +#else +# define D_ACTIVE DEBUG +#endif + +#if DEBUG +# define D(...) VERBOSE_PRINT(keys,__VA_ARGS__) +#else +# define D(...) ((void)0) +#endif + +#define _SKIN_KEY_COMMAND(x,y) #x , +static const char* const command_strings[ SKIN_KEY_COMMAND_MAX ] = { + SKIN_KEY_COMMAND_LIST +}; +#undef _SKIN_KEY_COMMAND + +const char* +skin_key_command_to_str( SkinKeyCommand cmd ) +{ + if (cmd > SKIN_KEY_COMMAND_NONE && cmd < SKIN_KEY_COMMAND_MAX) + return command_strings[cmd]; + + return NULL; +} + +SkinKeyCommand +skin_key_command_from_str( const char* str, int len ) +{ + int nn; + if (len < 0) + len = strlen(str); + for (nn = 0; nn < SKIN_KEY_COMMAND_MAX; nn++) { + const char* cmd = command_strings[nn]; + + if ( !memcmp( cmd, str, len ) && cmd[len] == 0 ) + return (SkinKeyCommand) nn; + } + return SKIN_KEY_COMMAND_NONE; +} + + +#define _SKIN_KEY_COMMAND(x,y) y , +static const char* const command_descriptions[ SKIN_KEY_COMMAND_MAX ] = { + SKIN_KEY_COMMAND_LIST +}; +#undef _SKIN_KEY_COMMAND + +const char* +skin_key_command_description( SkinKeyCommand cmd ) +{ + if (cmd > SKIN_KEY_COMMAND_NONE && cmd < SKIN_KEY_COMMAND_MAX) + return command_descriptions[cmd]; + + return NULL; +} + +#define _KEYSYM1_(x) _KEYSYM_(x,x) + +#define _KEYSYM_LIST \ + _KEYSYM1_(BACKSPACE) \ + _KEYSYM1_(TAB) \ + _KEYSYM1_(CLEAR) \ + _KEYSYM_(RETURN,ENTER) \ + _KEYSYM1_(PAUSE) \ + _KEYSYM1_(ESCAPE) \ + _KEYSYM1_(SPACE) \ + _KEYSYM_(EXCLAIM,EXCLAM) \ + _KEYSYM_(QUOTEDBL,DOUBLEQUOTE) \ + _KEYSYM_(HASH,HASH) \ + _KEYSYM1_(DOLLAR) \ + _KEYSYM1_(AMPERSAND) \ + _KEYSYM1_(QUOTE) \ + _KEYSYM_(LEFTPAREN,LPAREN) \ + _KEYSYM_(RIGHTPAREN,RPAREN) \ + _KEYSYM1_(ASTERISK) \ + _KEYSYM1_(PLUS) \ + _KEYSYM1_(COMMA) \ + _KEYSYM1_(MINUS) \ + _KEYSYM1_(PERIOD) \ + _KEYSYM1_(SLASH) \ + _KEYSYM1_(0) \ + _KEYSYM1_(1) \ + _KEYSYM1_(2) \ + _KEYSYM1_(3) \ + _KEYSYM1_(4) \ + _KEYSYM1_(5) \ + _KEYSYM1_(6) \ + _KEYSYM1_(7) \ + _KEYSYM1_(8) \ + _KEYSYM1_(9) \ + _KEYSYM1_(COLON) \ + _KEYSYM1_(SEMICOLON) \ + _KEYSYM1_(LESS) \ + _KEYSYM_(EQUALS,EQUAL) \ + _KEYSYM1_(GREATER) \ + _KEYSYM1_(QUESTION) \ + _KEYSYM1_(AT) \ + _KEYSYM1_(LEFTBRACKET) \ + _KEYSYM1_(BACKSLASH) \ + _KEYSYM1_(RIGHTBRACKET) \ + _KEYSYM1_(CARET) \ + _KEYSYM1_(UNDERSCORE) \ + _KEYSYM1_(BACKQUOTE) \ + _KEYSYM_(a,A) \ + _KEYSYM_(b,B) \ + _KEYSYM_(c,C) \ + _KEYSYM_(d,D) \ + _KEYSYM_(e,E) \ + _KEYSYM_(f,F) \ + _KEYSYM_(g,G) \ + _KEYSYM_(h,H) \ + _KEYSYM_(i,I) \ + _KEYSYM_(j,J) \ + _KEYSYM_(k,K) \ + _KEYSYM_(l,L) \ + _KEYSYM_(m,M) \ + _KEYSYM_(n,N) \ + _KEYSYM_(o,O) \ + _KEYSYM_(p,P) \ + _KEYSYM_(q,Q) \ + _KEYSYM_(r,R) \ + _KEYSYM_(s,S) \ + _KEYSYM_(t,T) \ + _KEYSYM_(u,U) \ + _KEYSYM_(v,V) \ + _KEYSYM_(w,W) \ + _KEYSYM_(x,X) \ + _KEYSYM_(y,Y) \ + _KEYSYM_(z,Z) \ + _KEYSYM1_(DELETE) \ + _KEYSYM_(KP_PLUS,KEYPAD_PLUS) \ + _KEYSYM_(KP_MINUS,KEYPAD_MINUS) \ + _KEYSYM_(KP_MULTIPLY,KEYPAD_MULTIPLY) \ + _KEYSYM_(KP_DIVIDE,KEYPAD_DIVIDE) \ + _KEYSYM_(KP_ENTER,KEYPAD_ENTER) \ + _KEYSYM_(KP_PERIOD,KEYPAD_PERIOD) \ + _KEYSYM_(KP_EQUALS,KEYPAD_EQUALS) \ + _KEYSYM_(KP1,KEYPAD_1) \ + _KEYSYM_(KP2,KEYPAD_2) \ + _KEYSYM_(KP3,KEYPAD_3) \ + _KEYSYM_(KP4,KEYPAD_4) \ + _KEYSYM_(KP5,KEYPAD_5) \ + _KEYSYM_(KP6,KEYPAD_6) \ + _KEYSYM_(KP7,KEYPAD_7) \ + _KEYSYM_(KP8,KEYPAD_8) \ + _KEYSYM_(KP9,KEYPAD_9) \ + _KEYSYM_(KP0,KEYPAD_0) \ + _KEYSYM1_(UP) \ + _KEYSYM1_(DOWN) \ + _KEYSYM1_(RIGHT) \ + _KEYSYM1_(LEFT) \ + _KEYSYM1_(INSERT) \ + _KEYSYM1_(HOME) \ + _KEYSYM1_(END) \ + _KEYSYM1_(PAGEUP) \ + _KEYSYM1_(PAGEDOWN) \ + _KEYSYM1_(F1) \ + _KEYSYM1_(F2) \ + _KEYSYM1_(F3) \ + _KEYSYM1_(F4) \ + _KEYSYM1_(F5) \ + _KEYSYM1_(F6) \ + _KEYSYM1_(F7) \ + _KEYSYM1_(F8) \ + _KEYSYM1_(F9) \ + _KEYSYM1_(F10) \ + _KEYSYM1_(F11) \ + _KEYSYM1_(F12) \ + _KEYSYM1_(F13) \ + _KEYSYM1_(F14) \ + _KEYSYM1_(F15) \ + _KEYSYM1_(SCROLLOCK) \ + _KEYSYM1_(SYSREQ) \ + _KEYSYM1_(PRINT) \ + _KEYSYM1_(BREAK) \ + +#define _KEYSYM_(x,y) { SDLK_##x, #y }, +static const struct { int _sym; const char* _str; } keysym_names[] = +{ + _KEYSYM_LIST + { 0, NULL } +}; +#undef _KEYSYM_ + +int +skin_keysym_str_count( void ) +{ + return sizeof(keysym_names)/sizeof(keysym_names[0])-1; +} + +const char* +skin_keysym_str( int index ) +{ + if (index >= 0 && index < skin_keysym_str_count()) + return keysym_names[index]._str; + + return NULL; +} + +const char* +skin_key_symmod_to_str( int sym, int mod ) +{ + static char temp[32]; + char* p = temp; + char* end = p + sizeof(temp); + int nn; + + if ((mod & KMOD_LCTRL) != 0) { + p = bufprint(p, end, "Ctrl-"); + } + if ((mod & KMOD_RCTRL) != 0) { + p = bufprint(p, end, "RCtrl-"); + } + if ((mod & KMOD_LSHIFT) != 0) { + p = bufprint(p, end, "Shift-"); + } + if ((mod & KMOD_RSHIFT) != 0) { + p = bufprint(p, end, "RShift-"); + } + if ((mod & KMOD_LALT) != 0) { + p = bufprint(p, end, "Alt-"); + } + if ((mod & KMOD_RALT) != 0) { + p = bufprint(p, end, "RAlt-"); + } + for (nn = 0; keysym_names[nn]._sym != 0; nn++) { + if (keysym_names[nn]._sym == sym) { + p = bufprint(p, end, "%s", keysym_names[nn]._str); + return temp;; + } + } + + if (sym >= 32 && sym <= 127) { + p = bufprint(p, end, "%c", sym); + return temp; + } + + return NULL; +} + + +int +skin_key_symmod_from_str( const char* str, int *psym, int *pmod ) +{ + int mod = 0; + int match = 1; + int nn; + const char* s0 = str; + static const struct { const char* prefix; int mod; } mods[] = + { + { "^", KMOD_LCTRL }, + { "Ctrl", KMOD_LCTRL }, + { "ctrl", KMOD_LCTRL }, + { "RCtrl", KMOD_RCTRL }, + { "rctrl", KMOD_RCTRL }, + { "Alt", KMOD_LALT }, + { "alt", KMOD_LALT }, + { "RAlt", KMOD_RALT }, + { "ralt", KMOD_RALT }, + { "Shift", KMOD_LSHIFT }, + { "shift", KMOD_LSHIFT }, + { "RShift", KMOD_RSHIFT }, + { "rshift", KMOD_RSHIFT }, + { NULL, 0 } + }; + + while (match) { + match = 0; + for (nn = 0; mods[nn].prefix != NULL; nn++) { + const char* prefix = mods[nn].prefix; + int len = strlen(prefix); + + if ( !memcmp(str, prefix, len) ) { + str += len; + match = 1; + mod |= mods[nn].mod; + if (str[0] == '-' && str[1] != 0) + str++; + break; + } + } + } + + for (nn = 0; keysym_names[nn]._sym; nn++) { +#ifdef _WIN32 + if ( !stricmp(str, keysym_names[nn]._str) ) +#else + if ( !strcasecmp(str, keysym_names[nn]._str) ) +#endif + { + *psym = keysym_names[nn]._sym; + *pmod = mod; + return 0; + } + } + + D("%s: can't find sym value for '%s' (mod=%d, str=%s)", __FUNCTION__, s0, mod, str); + return -1; +} + + +typedef struct { + int sym; + int mod; + SkinKeyCommand command; +} SkinKeyItem; + + +struct SkinKeyset { + int num_items; + int max_items; + SkinKeyItem* items; +}; + + +static int +skin_keyset_add( SkinKeyset* kset, int sym, int mod, SkinKeyCommand command ) +{ + SkinKeyItem* item = kset->items; + SkinKeyItem* end = item + kset->num_items; + SkinKeyItem* first = NULL; + int count = 0; + + D( "adding binding %s to %s", skin_key_command_to_str(command), skin_key_symmod_to_str(sym,mod)); + for ( ; item < end; item++) { + if (item->command == command) { + if (!first) + first = item; + if (++count == SKIN_KEY_COMMAND_MAX_BINDINGS) { + /* replace the first (oldest) one in the list */ + first->sym = sym; + first->mod = mod; + return 0; + } + continue; + } + if (item->sym == sym && item->mod == mod) { + /* replace a (sym,mod) binding */ + item->command = command; + return 0; + } + } + if (kset->num_items >= kset->max_items) { + int old_size = kset->max_items; + int new_size = old_size + (old_size >> 1) + 4; + SkinKeyItem* new_items = realloc( kset->items, new_size*sizeof(SkinKeyItem) ); + if (new_items == NULL) { + return -1; + } + kset->items = new_items; + kset->max_items = new_size; + } + item = kset->items + kset->num_items++; + item->command = command; + item->sym = sym; + item->mod = mod; + return 1; +} + + +SkinKeyset* +skin_keyset_new ( AConfig* root ) +{ + SkinKeyset* kset = calloc(1, sizeof(*kset)); + AConfig* node = root->first_child;; + + if (kset == NULL) + return NULL; + + for ( ; node != NULL; node = node->next ) + { + SkinKeyCommand command; + int sym, mod; + char* p; + + command = skin_key_command_from_str( node->name, -1 ); + if (command == SKIN_KEY_COMMAND_NONE) { + D( "ignoring unknown keyset command '%s'", node->name ); + continue; + } + p = (char*)node->value; + while (*p) { + char* q = strpbrk( p, " \t,:" ); + if (q == NULL) + q = p + strlen(p); + + if (q > p) { + int len = q - p; + char keys[24]; + if (len+1 >= (int)sizeof(keys)) { + D("key binding too long: '%s'", p); + } + else { + memcpy( keys, p, len ); + keys[len] = 0; + if ( skin_key_symmod_from_str( keys, &sym, &mod ) < 0 ) { + D( "ignoring unknown keys '%s' for command '%s'", + keys, node->name ); + } else { + skin_keyset_add( kset, sym, mod, command ); + } + } + } else if (*q) + q += 1; + + p = q; + } + } + return kset; +} + + +SkinKeyset* +skin_keyset_new_from_text( const char* text ) +{ + AConfig* root = aconfig_node("",""); + char* str = strdup(text); + SkinKeyset* result; + + D("kset new from:\n%s", text); + aconfig_load( root, str ); + result = skin_keyset_new( root ); + free(str); + D("kset done result=%p", result); + return result; +} + + +void +skin_keyset_free( SkinKeyset* kset ) +{ + if (kset) { + free(kset->items); + kset->items = NULL; + kset->num_items = 0; + kset->max_items = 0; + free(kset); + } +} + + +extern int +skin_keyset_get_bindings( SkinKeyset* kset, + SkinKeyCommand command, + SkinKeyBinding* bindings ) +{ + if (kset) { + int count = 0; + SkinKeyItem* item = kset->items; + SkinKeyItem* end = item + kset->num_items; + + for ( ; item < end; item++ ) { + if (item->command == command) { + bindings->sym = item->sym; + bindings->mod = item->mod; + bindings ++; + if ( ++count >= SKIN_KEY_COMMAND_MAX_BINDINGS ) { + /* shouldn't happen, but be safe */ + break; + } + } + } + return count; + } + return -1; +} + + +/* retrieve the command corresponding to a given (sym,mod) pair. returns SKIN_KEY_COMMAND_NONE if not found */ +SkinKeyCommand +skin_keyset_get_command( SkinKeyset* kset, int sym, int mod ) +{ + if (kset) { + SkinKeyItem* item = kset->items; + SkinKeyItem* end = item + kset->num_items; + + for ( ; item < end; item++ ) { + if (item->sym == sym && item->mod == mod) { + return item->command; + } + } + } + return SKIN_KEY_COMMAND_NONE; +} + + +const char* +skin_keyset_get_default( void ) +{ + return + "BUTTON_CALL F3\n" + "BUTTON_HANGUP F4\n" + "BUTTON_HOME Home\n" + "BUTTON_BACK Escape\n" + "BUTTON_MENU F2, PageUp\n" + "BUTTON_STAR Shift-F2, PageDown\n" + "BUTTON_POWER F7\n" + "BUTTON_SEARCH F5\n" + "BUTTON_CAMERA Ctrl-Keypad_5, Ctrl-F3\n" + "BUTTON_VOLUME_UP Keypad_Plus, Ctrl-F5\n" + "BUTTON_VOLUME_DOWN Keypad_Minus, Ctrl-F6\n" + + "TOGGLE_NETWORK F8\n" + "TOGGLE_TRACING F9\n" + "TOGGLE_FULLSCREEN Alt-Enter\n" + + "BUTTON_DPAD_CENTER Keypad_5\n" + "BUTTON_DPAD_UP Keypad_8\n" + "BUTTON_DPAD_LEFT Keypad_4\n" + "BUTTON_DPAD_RIGHT Keypad_6\n" + "BUTTON_DPAD_DOWN Keypad_2\n" + + "TOGGLE_TRACKBALL F6\n" + "SHOW_TRACKBALL Delete\n" + + "CHANGE_LAYOUT_PREV Keypad_7, Ctrl-F11\n" + "CHANGE_LAYOUT_NEXT Keypad_9, Ctrl-F12\n" + "ONION_ALPHA_UP Keypad_Multiply\n" + "ONION_ALPHA_DOWN Keypad_Divide\n" + ; +} |