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