• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/keyboard.h"
13 #include "android/utils/debug.h"
14 #include "android/utils/bufprint.h"
15 #include "android/utils/system.h"
16 #include "android/android.h"
17 #include "android/keycode-array.h"
18 #include "android/charmap.h"
19 
20 #define  DEBUG  1
21 
22 #if DEBUG
23 #  define  D(...)  VERBOSE_PRINT(keys,__VA_ARGS__)
24 #else
25 #  define  D(...)  ((void)0)
26 #endif
27 
28 
29 /** LAST PRESSED KEYS
30  ** a small buffer of last pressed keys, this is used to properly
31  ** implement the Unicode keyboard mode (SDL key up event always have
32  ** their .unicode field set to 0
33  **/
34 typedef struct {
35     int  unicode;  /* Unicode of last pressed key        */
36     int  sym;      /* SDL key symbol value (e.g. SDLK_a) */
37     int  mod;      /* SDL key modifier value             */
38 } LastKey;
39 
40 #define  MAX_LAST_KEYS  16
41 
42 struct SkinKeyboard {
43     const AKeyCharmap*  charmap;
44     SkinKeyset*         kset;
45     char                enabled;
46     char                raw_keys;
47     char                last_count;
48 
49     SkinRotation        rotation;
50 
51     SkinKeyCommandFunc  command_func;
52     void*               command_opaque;
53     SkinKeyEventFunc    press_func;
54     void*               press_opaque;
55 
56     LastKey             last_keys[ MAX_LAST_KEYS ];
57 
58     AKeycodeBuffer      keycodes;
59 };
60 
61 
62 void
skin_keyboard_set_keyset(SkinKeyboard * keyboard,SkinKeyset * kset)63 skin_keyboard_set_keyset( SkinKeyboard*  keyboard, SkinKeyset*  kset )
64 {
65     if (kset == NULL)
66         return;
67     if (keyboard->kset && keyboard->kset != android_keyset) {
68         skin_keyset_free(keyboard->kset);
69     }
70     keyboard->kset = kset;
71 }
72 
73 
74 const char*
skin_keyboard_charmap_name(SkinKeyboard * keyboard)75 skin_keyboard_charmap_name( SkinKeyboard*  keyboard )
76 {
77     if (keyboard && keyboard->charmap)
78         return keyboard->charmap->name;
79 
80     return "qwerty";
81 }
82 
83 void
skin_keyboard_set_rotation(SkinKeyboard * keyboard,SkinRotation rotation)84 skin_keyboard_set_rotation( SkinKeyboard*     keyboard,
85                             SkinRotation      rotation )
86 {
87     keyboard->rotation = (rotation & 3);
88 }
89 
90 void
skin_keyboard_on_command(SkinKeyboard * keyboard,SkinKeyCommandFunc cmd_func,void * cmd_opaque)91 skin_keyboard_on_command( SkinKeyboard*  keyboard, SkinKeyCommandFunc  cmd_func, void*  cmd_opaque )
92 {
93     keyboard->command_func   = cmd_func;
94     keyboard->command_opaque = cmd_opaque;
95 }
96 
97 void
skin_keyboard_on_key_press(SkinKeyboard * keyboard,SkinKeyEventFunc press_func,void * press_opaque)98 skin_keyboard_on_key_press( SkinKeyboard*  keyboard, SkinKeyEventFunc  press_func, void*  press_opaque )
99 {
100     keyboard->press_func   = press_func;
101     keyboard->press_opaque = press_opaque;
102 }
103 
104 void
skin_keyboard_add_key_event(SkinKeyboard * kb,unsigned code,unsigned down)105 skin_keyboard_add_key_event( SkinKeyboard*  kb,
106                              unsigned       code,
107                              unsigned       down )
108 {
109     android_keycodes_add_key_event(&kb->keycodes, code, down);
110 }
111 
112 
113 void
skin_keyboard_flush(SkinKeyboard * kb)114 skin_keyboard_flush( SkinKeyboard*  kb )
115 {
116     android_keycodes_flush(&kb->keycodes);
117 }
118 
119 
120 static void
skin_keyboard_cmd(SkinKeyboard * keyboard,SkinKeyCommand command,int param)121 skin_keyboard_cmd( SkinKeyboard*   keyboard,
122                    SkinKeyCommand  command,
123                    int             param )
124 {
125     if (keyboard->command_func) {
126         keyboard->command_func( keyboard->command_opaque, command, param );
127     }
128 }
129 
130 
131 static LastKey*
skin_keyboard_find_last(SkinKeyboard * keyboard,int sym)132 skin_keyboard_find_last( SkinKeyboard*  keyboard,
133                          int            sym )
134 {
135     LastKey*  k   = keyboard->last_keys;
136     LastKey*  end = k + keyboard->last_count;
137 
138     for ( ; k < end; k++ ) {
139         if (k->sym == sym)
140             return k;
141     }
142     return NULL;
143 }
144 
145 static void
skin_keyboard_add_last(SkinKeyboard * keyboard,int sym,int mod,int unicode)146 skin_keyboard_add_last( SkinKeyboard*  keyboard,
147                         int            sym,
148                         int            mod,
149                         int            unicode )
150 {
151     LastKey*  k = keyboard->last_keys + keyboard->last_count;
152 
153     if (keyboard->last_count < MAX_LAST_KEYS) {
154         k->sym     = sym;
155         k->mod     = mod;
156         k->unicode = unicode;
157 
158         keyboard->last_count += 1;
159     }
160 }
161 
162 static void
skin_keyboard_remove_last(SkinKeyboard * keyboard,int sym)163 skin_keyboard_remove_last( SkinKeyboard*  keyboard,
164                            int            sym )
165 {
166     LastKey*  k   = keyboard->last_keys;
167     LastKey*  end = k + keyboard->last_count;
168 
169     for ( ; k < end; k++ ) {
170         if (k->sym == sym) {
171            /* we don't need a sorted array, so place the last
172             * element in place at the position of the removed
173             * one... */
174             k[0] = end[-1];
175             keyboard->last_count -= 1;
176             break;
177         }
178     }
179 }
180 
181 static void
skin_keyboard_clear_last(SkinKeyboard * keyboard)182 skin_keyboard_clear_last( SkinKeyboard*  keyboard )
183 {
184     keyboard->last_count = 0;
185 }
186 
187 static int
skin_keyboard_rotate_sym(SkinKeyboard * keyboard,int sym)188 skin_keyboard_rotate_sym( SkinKeyboard*  keyboard,
189                           int            sym )
190 {
191     switch (keyboard->rotation) {
192         case SKIN_ROTATION_90:
193             switch (sym) {
194                 case SDLK_LEFT:  sym = SDLK_DOWN; break;
195                 case SDLK_RIGHT: sym = SDLK_UP; break;
196                 case SDLK_UP:    sym = SDLK_LEFT; break;
197                 case SDLK_DOWN:  sym = SDLK_RIGHT; break;
198             }
199             break;
200 
201         case SKIN_ROTATION_180:
202             switch (sym) {
203                 case SDLK_LEFT:  sym = SDLK_RIGHT; break;
204                 case SDLK_RIGHT: sym = SDLK_LEFT; break;
205                 case SDLK_UP:    sym = SDLK_DOWN; break;
206                 case SDLK_DOWN:  sym = SDLK_UP; break;
207             }
208             break;
209 
210         case SKIN_ROTATION_270:
211             switch (sym) {
212                 case SDLK_LEFT:  sym = SDLK_UP; break;
213                 case SDLK_RIGHT: sym = SDLK_DOWN; break;
214                 case SDLK_UP:    sym = SDLK_RIGHT; break;
215                 case SDLK_DOWN:  sym = SDLK_LEFT; break;
216             }
217             break;
218 
219         default: ;
220     }
221     return  sym;
222 }
223 
224 static AndroidKeyCode
skin_keyboard_key_to_code(SkinKeyboard * keyboard,unsigned sym,int mod,int down)225 skin_keyboard_key_to_code( SkinKeyboard*  keyboard,
226                            unsigned       sym,
227                            int            mod,
228                            int            down )
229 {
230     AndroidKeyCode  code   = 0;
231     int             mod0   = mod;
232     SkinKeyCommand  command;
233 
234     /* first, handle the arrow keys directly */
235     /* rotate them if necessary */
236     sym  = skin_keyboard_rotate_sym(keyboard, sym);
237     mod &= (KMOD_CTRL | KMOD_ALT | KMOD_SHIFT);
238 
239     switch (sym) {
240         case SDLK_LEFT:       code = kKeyCodeDpadLeft; break;
241         case SDLK_RIGHT:      code = kKeyCodeDpadRight; break;
242         case SDLK_UP:         code = kKeyCodeDpadUp; break;
243         case SDLK_DOWN:       code = kKeyCodeDpadDown; break;
244         default: ;
245     }
246 
247     if (code != 0) {
248         D("handling arrow (sym=%d mod=%d)", sym, mod);
249         if (!keyboard->raw_keys) {
250             int  doCapL, doCapR, doAltL, doAltR;
251 
252             if (!down) {
253                 LastKey*  k = skin_keyboard_find_last(keyboard, sym);
254                 if (k != NULL) {
255                     mod = k->mod;
256                     skin_keyboard_remove_last( keyboard, sym );
257                 }
258             } else {
259                 skin_keyboard_add_last( keyboard, sym, mod, 0);
260             }
261 
262             doCapL = (mod & 0x7ff) & KMOD_LSHIFT;
263             doCapR = (mod & 0x7ff) & KMOD_RSHIFT;
264             doAltL = (mod & 0x7ff) & KMOD_LALT;
265             doAltR = (mod & 0x7ff) & KMOD_RALT;
266 
267             if (down) {
268                 if (doAltL) skin_keyboard_add_key_event( keyboard, kKeyCodeAltLeft, 1 );
269                 if (doAltR) skin_keyboard_add_key_event( keyboard, kKeyCodeAltRight, 1 );
270                 if (doCapL) skin_keyboard_add_key_event( keyboard, kKeyCodeCapLeft, 1 );
271                 if (doCapR) skin_keyboard_add_key_event( keyboard, kKeyCodeCapRight, 1 );
272             }
273             skin_keyboard_add_key_event(keyboard, code, down);
274 
275             if (!down) {
276                 if (doCapR) skin_keyboard_add_key_event( keyboard, kKeyCodeCapRight, 0 );
277                 if (doCapL) skin_keyboard_add_key_event( keyboard, kKeyCodeCapLeft, 0 );
278                 if (doAltR) skin_keyboard_add_key_event( keyboard, kKeyCodeAltRight, 0 );
279                 if (doAltL) skin_keyboard_add_key_event( keyboard, kKeyCodeAltLeft, 0 );
280             }
281             code = 0;
282         }
283         return code;
284     }
285 
286     /* special case for keypad keys, ignore them here if numlock is on */
287     if ((mod0 & KMOD_NUM) != 0) {
288         switch (sym) {
289             case SDLK_KP0:
290             case SDLK_KP1:
291             case SDLK_KP2:
292             case SDLK_KP3:
293             case SDLK_KP4:
294             case SDLK_KP5:
295             case SDLK_KP6:
296             case SDLK_KP7:
297             case SDLK_KP8:
298             case SDLK_KP9:
299             case SDLK_KP_PLUS:
300             case SDLK_KP_MINUS:
301             case SDLK_KP_MULTIPLY:
302             case SDLK_KP_DIVIDE:
303             case SDLK_KP_EQUALS:
304             case SDLK_KP_PERIOD:
305             case SDLK_KP_ENTER:
306                 return 0;
307         }
308     }
309 
310     /* now try all keyset combos */
311     command = skin_keyset_get_command( keyboard->kset, sym, mod );
312     if (command != SKIN_KEY_COMMAND_NONE) {
313         D("handling command %s from (sym=%d, mod=%d, str=%s)",
314           skin_key_command_to_str(command), sym, mod, skin_key_symmod_to_str(sym,mod));
315         skin_keyboard_cmd( keyboard, command, down );
316         return 0;
317     }
318     D("could not handle (sym=%d, mod=%d, str=%s)", sym, mod,
319       skin_key_symmod_to_str(sym,mod));
320     return -1;
321 }
322 
323 /* this gets called only if the reverse unicode mapping didn't work
324  * or wasn't used (when in raw keys mode)
325  */
326 static AndroidKeyCode
skin_keyboard_raw_key_to_code(SkinKeyboard * kb,unsigned sym,int down)327 skin_keyboard_raw_key_to_code(SkinKeyboard*  kb, unsigned sym, int  down)
328 {
329     switch(sym){
330     case SDLK_1:          return kKeyCode1;
331     case SDLK_2:          return kKeyCode2;
332     case SDLK_3:          return kKeyCode3;
333     case SDLK_4:          return kKeyCode4;
334     case SDLK_5:          return kKeyCode5;
335     case SDLK_6:          return kKeyCode6;
336     case SDLK_7:          return kKeyCode7;
337     case SDLK_8:          return kKeyCode8;
338     case SDLK_9:          return kKeyCode9;
339     case SDLK_0:          return kKeyCode0;
340 
341     case SDLK_q:          return kKeyCodeQ;
342     case SDLK_w:          return kKeyCodeW;
343     case SDLK_e:          return kKeyCodeE;
344     case SDLK_r:          return kKeyCodeR;
345     case SDLK_t:          return kKeyCodeT;
346     case SDLK_y:          return kKeyCodeY;
347     case SDLK_u:          return kKeyCodeU;
348     case SDLK_i:          return kKeyCodeI;
349     case SDLK_o:          return kKeyCodeO;
350     case SDLK_p:          return kKeyCodeP;
351     case SDLK_a:          return kKeyCodeA;
352     case SDLK_s:          return kKeyCodeS;
353     case SDLK_d:          return kKeyCodeD;
354     case SDLK_f:          return kKeyCodeF;
355     case SDLK_g:          return kKeyCodeG;
356     case SDLK_h:          return kKeyCodeH;
357     case SDLK_j:          return kKeyCodeJ;
358     case SDLK_k:          return kKeyCodeK;
359     case SDLK_l:          return kKeyCodeL;
360     case SDLK_z:          return kKeyCodeZ;
361     case SDLK_x:          return kKeyCodeX;
362     case SDLK_c:          return kKeyCodeC;
363     case SDLK_v:          return kKeyCodeV;
364     case SDLK_b:          return kKeyCodeB;
365     case SDLK_n:          return kKeyCodeN;
366     case SDLK_m:          return kKeyCodeM;
367     case SDLK_COMMA:      return kKeyCodeComma;
368     case SDLK_PERIOD:     return kKeyCodePeriod;
369     case SDLK_SPACE:      return kKeyCodeSpace;
370     case SDLK_SLASH:      return kKeyCodeSlash;
371     case SDLK_RETURN:     return kKeyCodeNewline;
372     case SDLK_BACKSPACE:  return kKeyCodeDel;
373 
374 /* these are qwerty keys not on a device keyboard */
375     case SDLK_TAB:        return kKeyCodeTab;
376     case SDLK_BACKQUOTE:  return kKeyCodeGrave;
377     case SDLK_MINUS:      return kKeyCodeMinus;
378     case SDLK_EQUALS:     return kKeyCodeEquals;
379     case SDLK_LEFTBRACKET: return kKeyCodeLeftBracket;
380     case SDLK_RIGHTBRACKET: return kKeyCodeRightBracket;
381     case SDLK_BACKSLASH:  return kKeyCodeBackslash;
382     case SDLK_SEMICOLON:  return kKeyCodeSemicolon;
383     case SDLK_QUOTE:      return kKeyCodeApostrophe;
384 
385     case SDLK_RSHIFT:     return kKeyCodeCapRight;
386     case SDLK_LSHIFT:     return kKeyCodeCapLeft;
387     case SDLK_RMETA:      return kKeyCodeSym;
388     case SDLK_LMETA:      return kKeyCodeSym;
389     case SDLK_RALT:       return kKeyCodeAltRight;
390     case SDLK_LALT:       return kKeyCodeAltLeft;
391     case SDLK_RCTRL:      return kKeyCodeSym;
392     case SDLK_LCTRL:      return kKeyCodeSym;
393 
394     default:
395         /* fprintf(stderr,"* unknown sdl keysym %d *\n", sym); */
396         return -1;
397     }
398 }
399 
400 
401 static void
skin_keyboard_do_key_event(SkinKeyboard * kb,AndroidKeyCode code,int down)402 skin_keyboard_do_key_event( SkinKeyboard*   kb,
403                             AndroidKeyCode  code,
404                             int             down )
405 {
406     if (kb->press_func) {
407         kb->press_func( kb->press_opaque, code, down );
408     }
409     skin_keyboard_add_key_event(kb, code, down);
410 }
411 
412 
413 int
skin_keyboard_process_unicode_event(SkinKeyboard * kb,unsigned int unicode,int down)414 skin_keyboard_process_unicode_event( SkinKeyboard*  kb,  unsigned int  unicode, int  down )
415 {
416     return android_charmap_reverse_map_unicode(kb->charmap, unicode, down,
417                                                &kb->keycodes);
418 }
419 
420 
421 void
skin_keyboard_enable(SkinKeyboard * keyboard,int enabled)422 skin_keyboard_enable( SkinKeyboard*  keyboard,
423                       int            enabled )
424 {
425     keyboard->enabled = enabled;
426     if (enabled) {
427         SDL_EnableUNICODE(!keyboard->raw_keys);
428         SDL_EnableKeyRepeat(0,0);
429     }
430 }
431 
432 void
skin_keyboard_process_event(SkinKeyboard * kb,SDL_Event * ev,int down)433 skin_keyboard_process_event( SkinKeyboard*  kb, SDL_Event*  ev, int  down )
434 {
435     unsigned         code;
436     int              unicode = ev->key.keysym.unicode;
437     int              sym     = ev->key.keysym.sym;
438     int              mod     = ev->key.keysym.mod;
439 
440     /* ignore key events if we're not enabled */
441     if (!kb->enabled) {
442         printf( "ignoring key event sym=%d mod=0x%x unicode=%d\n",
443                 sym, mod, unicode );
444         return;
445     }
446 
447     /* first, try the keyboard-mode-independent keys */
448     code = skin_keyboard_key_to_code( kb, sym, mod, down );
449     if (code == 0)
450         return;
451 
452     if ((int)code > 0) {
453         skin_keyboard_do_key_event(kb, code, down);
454         skin_keyboard_flush(kb);
455         return;
456     }
457 
458     /* Ctrl-K is used to switch between 'unicode' and 'raw' modes */
459     if (sym == SDLK_k)
460     {
461         int  mod2 = mod & 0x7ff;
462 
463         if ( mod2 == KMOD_LCTRL || mod2 == KMOD_RCTRL ) {
464             if (down) {
465                 skin_keyboard_clear_last(kb);
466                 kb->raw_keys = !kb->raw_keys;
467                 SDL_EnableUNICODE(!kb->raw_keys);
468                 D( "switching keyboard to %s mode", kb->raw_keys ? "raw" : "unicode" );
469             }
470             return;
471         }
472     }
473 
474     if (!kb->raw_keys) {
475        /* ev->key.keysym.unicode is only valid on keydown events, and will be 0
476         * on the corresponding keyup ones, so remember the set of last pressed key
477         * syms to "undo" the job
478         */
479         if ( !down && unicode == 0 ) {
480             LastKey*  k = skin_keyboard_find_last(kb, sym);
481             if (k != NULL) {
482                 unicode = k->unicode;
483                 skin_keyboard_remove_last(kb, sym);
484             }
485         }
486     }
487     if (!kb->raw_keys &&
488         skin_keyboard_process_unicode_event( kb, unicode, down ) > 0)
489     {
490         if (down)
491             skin_keyboard_add_last( kb, sym, mod, unicode );
492 
493         skin_keyboard_flush( kb );
494         return;
495     }
496 
497     code = skin_keyboard_raw_key_to_code( kb, sym, down );
498 
499     if ( !kb->raw_keys &&
500          (code == kKeyCodeAltLeft  || code == kKeyCodeAltRight ||
501           code == kKeyCodeCapLeft  || code == kKeyCodeCapRight ||
502           code == kKeyCodeSym) )
503         return;
504 
505     if (code == -1) {
506         D("ignoring keysym %d", sym );
507     } else if (code > 0) {
508         skin_keyboard_do_key_event(kb, code, down);
509         skin_keyboard_flush(kb);
510     }
511 }
512 
513 static SkinKeyboard*
skin_keyboard_create_from_charmap_name(const char * charmap_name,int use_raw_keys)514 skin_keyboard_create_from_charmap_name(const char*  charmap_name,
515                                        int  use_raw_keys)
516 {
517     SkinKeyboard*  kb;
518 
519     ANEW0(kb);
520 
521     kb->charmap = android_get_charmap_by_name(charmap_name);
522     if (!kb->charmap) {
523         // Charmap name was not found. Default to the first charmap in the array.
524         kb->charmap = android_get_charmap_by_index(0);
525         fprintf(stderr, "### warning, skin requires unknown '%s' charmap, reverting to '%s'\n",
526                 charmap_name, kb->charmap->name );
527     }
528     kb->raw_keys = use_raw_keys;
529     kb->enabled  = 0;
530 
531     /* add default keyset */
532     if (android_keyset)
533         kb->kset = android_keyset;
534     else
535         kb->kset = skin_keyset_new_from_text( skin_keyset_get_default() );
536 
537     return kb;
538 }
539 
540 SkinKeyboard*
skin_keyboard_create_from_aconfig(AConfig * aconfig,int use_raw_keys)541 skin_keyboard_create_from_aconfig( AConfig*  aconfig, int  use_raw_keys )
542 {
543     const char*    charmap_name = "qwerty";
544     AConfig*       node = aconfig_find( aconfig, "keyboard" );
545     if (node != NULL) {
546         charmap_name = aconfig_str(node, "charmap", charmap_name);
547     }
548     return skin_keyboard_create_from_charmap_name(charmap_name, use_raw_keys);
549 }
550 
551 SkinKeyboard*
skin_keyboard_create_from_kcm(const char * kcm_file_path,int use_raw_keys)552 skin_keyboard_create_from_kcm( const char*  kcm_file_path, int  use_raw_keys )
553 {
554     char charmap_name[AKEYCHARMAP_NAME_SIZE];
555     kcm_extract_charmap_name(kcm_file_path, charmap_name,
556                              sizeof(charmap_name));
557     return skin_keyboard_create_from_charmap_name(charmap_name, use_raw_keys);
558 }
559 
560 void
skin_keyboard_free(SkinKeyboard * keyboard)561 skin_keyboard_free( SkinKeyboard*  keyboard )
562 {
563     if (keyboard) {
564         AFREE(keyboard);
565     }
566 }
567