aboutsummaryrefslogtreecommitdiffstats
path: root/skins/skin_keyset.c
diff options
context:
space:
mode:
Diffstat (limited to 'skins/skin_keyset.c')
-rw-r--r--skins/skin_keyset.c540
1 files changed, 540 insertions, 0 deletions
diff --git a/skins/skin_keyset.c b/skins/skin_keyset.c
new file mode 100644
index 0000000..ffde933
--- /dev/null
+++ b/skins/skin_keyset.c
@@ -0,0 +1,540 @@
+/* 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 "skins/skin_keyset.h"
+#include "android_utils.h"
+#include "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 Ctrl-T\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"
+ ;
+}