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