Home | History | Annotate | Download | only in skin
      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
     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*
     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
     84 skin_keyboard_set_rotation( SkinKeyboard*     keyboard,
     85                             SkinRotation      rotation )
     86 {
     87     keyboard->rotation = (rotation & 3);
     88 }
     89 
     90 void
     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
     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
    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
    114 skin_keyboard_flush( SkinKeyboard*  kb )
    115 {
    116     android_keycodes_flush(&kb->keycodes);
    117 }
    118 
    119 
    120 static void
    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*
    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
    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
    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
    182 skin_keyboard_clear_last( SkinKeyboard*  keyboard )
    183 {
    184     keyboard->last_count = 0;
    185 }
    186 
    187 static int
    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
    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
    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
    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
    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
    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
    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*
    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*
    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*
    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
    561 skin_keyboard_free( SkinKeyboard*  keyboard )
    562 {
    563     if (keyboard) {
    564         AFREE(keyboard);
    565     }
    566 }
    567