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