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*
skin_key_command_to_str(SkinKeyCommand cmd)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
skin_key_command_from_str(const char * str,int len)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*
skin_key_command_description(SkinKeyCommand cmd)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
skin_keysym_str_count(void)207 skin_keysym_str_count( void )
208 {
209 return sizeof(keysym_names)/sizeof(keysym_names[0])-1;
210 }
211
212 const char*
skin_keysym_str(int index)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*
skin_key_symmod_to_str(int sym,int mod)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
skin_key_symmod_from_str(const char * str,int * psym,int * pmod)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
skin_keyset_add(SkinKeyset * kset,int sym,int mod,SkinKeyCommand command)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*
skin_keyset_new(AConfig * root)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*
skin_keyset_new_from_text(const char * text)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
skin_keyset_free(SkinKeyset * kset)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
skin_keyset_get_bindings(SkinKeyset * kset,SkinKeyCommand command,SkinKeyBinding * bindings)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
skin_keyset_get_command(SkinKeyset * kset,int sym,int mod)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*
skin_keyset_get_default(void)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