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 #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
     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
     76 skin_keyboard_set_rotation( SkinKeyboard*     keyboard,
     77                             SkinRotation      rotation )
     78 {
     79     keyboard->rotation = (rotation & 3);
     80 }
     81 
     82 void
     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
     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
     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
    106 skin_keyboard_flush( SkinKeyboard*  kb )
    107 {
    108     android_keycodes_flush(&kb->keycodes);
    109 }
    110 
    111 
    112 static void
    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*
    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
    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
    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
    174 skin_keyboard_clear_last( SkinKeyboard*  keyboard )
    175 {
    176     keyboard->last_count = 0;
    177 }
    178 
    179 static int
    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
    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
    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
    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
    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
    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
    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*
    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*
    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
    546 skin_keyboard_free( SkinKeyboard*  keyboard )
    547 {
    548     if (keyboard) {
    549         AFREE(keyboard);
    550     }
    551 }
    552