SDL_evdev_kbd.c (22134B)
1 /* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20 */ 21 #include "../../SDL_internal.h" 22 23 #include "SDL_evdev_kbd.h" 24 #include "SDL_hints.h" 25 26 #ifdef SDL_INPUT_LINUXKD 27 28 /* This logic is adapted from drivers/tty/vt/keyboard.c in the Linux kernel source */ 29 30 #include <unistd.h> 31 #include <fcntl.h> 32 #include <sys/ioctl.h> 33 #include <linux/kd.h> 34 #include <linux/keyboard.h> 35 #include <linux/vt.h> 36 #include <linux/tiocl.h> /* for TIOCL_GETSHIFTSTATE */ 37 38 #include <signal.h> 39 40 #include "../../events/SDL_events_c.h" 41 #include "SDL_evdev_kbd_default_accents.h" 42 #include "SDL_evdev_kbd_default_keymap.h" 43 44 /* These are not defined in older Linux kernel headers */ 45 #ifndef K_UNICODE 46 #define K_UNICODE 0x03 47 #endif 48 #ifndef K_OFF 49 #define K_OFF 0x04 50 #endif 51 52 /* 53 * Handler Tables. 54 */ 55 56 #define K_HANDLERS\ 57 k_self, k_fn, k_spec, k_pad,\ 58 k_dead, k_cons, k_cur, k_shift,\ 59 k_meta, k_ascii, k_lock, k_lowercase,\ 60 k_slock, k_dead2, k_brl, k_ignore 61 62 typedef void (k_handler_fn)(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag); 63 static k_handler_fn K_HANDLERS; 64 static k_handler_fn *k_handler[16] = { K_HANDLERS }; 65 66 typedef void (fn_handler_fn)(SDL_EVDEV_keyboard_state *kbd); 67 static void fn_enter(SDL_EVDEV_keyboard_state *kbd); 68 static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd); 69 static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd); 70 static void fn_num(SDL_EVDEV_keyboard_state *kbd); 71 static void fn_compose(SDL_EVDEV_keyboard_state *kbd); 72 73 static fn_handler_fn *fn_handler[] = 74 { 75 NULL, fn_enter, NULL, NULL, 76 NULL, NULL, NULL, fn_caps_toggle, 77 fn_num, NULL, NULL, NULL, 78 NULL, fn_caps_on, fn_compose, NULL, 79 NULL, NULL, NULL, fn_num 80 }; 81 82 83 /* 84 * Keyboard State 85 */ 86 87 struct SDL_EVDEV_keyboard_state 88 { 89 int console_fd; 90 int old_kbd_mode; 91 unsigned short **key_maps; 92 unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ 93 SDL_bool dead_key_next; 94 int npadch; /* -1 or number assembled on pad */ 95 struct kbdiacrs *accents; 96 unsigned int diacr; 97 SDL_bool rep; /* flag telling character repeat */ 98 unsigned char lockstate; 99 unsigned char slockstate; 100 unsigned char ledflagstate; 101 char shift_state; 102 char text[128]; 103 unsigned int text_len; 104 }; 105 106 #ifdef DUMP_ACCENTS 107 static void SDL_EVDEV_dump_accents(SDL_EVDEV_keyboard_state *kbd) 108 { 109 unsigned int i; 110 111 printf("static struct kbdiacrs default_accents = {\n"); 112 printf(" %d,\n", kbd->accents->kb_cnt); 113 printf(" {\n"); 114 for (i = 0; i < kbd->accents->kb_cnt; ++i) { 115 struct kbdiacr *diacr = &kbd->accents->kbdiacr[i]; 116 printf(" { 0x%.2x, 0x%.2x, 0x%.2x },\n", 117 diacr->diacr, diacr->base, diacr->result); 118 } 119 while (i < 256) { 120 printf(" { 0x00, 0x00, 0x00 },\n"); 121 ++i; 122 } 123 printf(" }\n"); 124 printf("};\n"); 125 } 126 #endif /* DUMP_ACCENTS */ 127 128 #ifdef DUMP_KEYMAP 129 static void SDL_EVDEV_dump_keymap(SDL_EVDEV_keyboard_state *kbd) 130 { 131 int i, j; 132 133 for (i = 0; i < MAX_NR_KEYMAPS; ++i) { 134 if (kbd->key_maps[i]) { 135 printf("static unsigned short default_key_map_%d[NR_KEYS] = {", i); 136 for (j = 0; j < NR_KEYS; ++j) { 137 if ((j%8) == 0) { 138 printf("\n "); 139 } 140 printf("0x%.4x, ", kbd->key_maps[i][j]); 141 } 142 printf("\n};\n"); 143 } 144 } 145 printf("\n"); 146 printf("static unsigned short *default_key_maps[MAX_NR_KEYMAPS] = {\n"); 147 for (i = 0; i < MAX_NR_KEYMAPS; ++i) { 148 if (kbd->key_maps[i]) { 149 printf(" default_key_map_%d,\n", i); 150 } else { 151 printf(" NULL,\n"); 152 } 153 } 154 printf("};\n"); 155 } 156 #endif /* DUMP_KEYMAP */ 157 158 static int SDL_EVDEV_kbd_load_keymaps(SDL_EVDEV_keyboard_state *kbd) 159 { 160 int i, j; 161 162 kbd->key_maps = (unsigned short **)SDL_calloc(MAX_NR_KEYMAPS, sizeof(unsigned short *)); 163 if (!kbd->key_maps) { 164 return -1; 165 } 166 167 for (i = 0; i < MAX_NR_KEYMAPS; ++i) { 168 struct kbentry kbe; 169 170 kbe.kb_table = i; 171 kbe.kb_index = 0; 172 if (ioctl(kbd->console_fd, KDGKBENT, &kbe) < 0) { 173 return -1; 174 } 175 176 if (kbe.kb_value == K_NOSUCHMAP) { 177 continue; 178 } 179 180 kbd->key_maps[i] = (unsigned short *)SDL_malloc(NR_KEYS * sizeof(unsigned short)); 181 if (!kbd->key_maps[i]) { 182 return -1; 183 } 184 185 for (j = 0; j < NR_KEYS; ++j) { 186 kbe.kb_table = i; 187 kbe.kb_index = j; 188 if (ioctl(kbd->console_fd, KDGKBENT, &kbe) < 0) { 189 return -1; 190 } 191 kbd->key_maps[i][j] = (kbe.kb_value ^ 0xf000); 192 } 193 } 194 return 0; 195 } 196 197 static SDL_EVDEV_keyboard_state * kbd_cleanup_state = NULL; 198 static int kbd_cleanup_sigactions_installed = 0; 199 static int kbd_cleanup_atexit_installed = 0; 200 201 static struct sigaction old_sigaction[NSIG]; 202 203 static int fatal_signals[] = 204 { 205 /* Handlers for SIGTERM and SIGINT are installed in SDL_QuitInit. */ 206 SIGHUP, SIGQUIT, SIGILL, SIGABRT, 207 SIGFPE, SIGSEGV, SIGPIPE, SIGBUS, 208 SIGSYS 209 }; 210 211 static void kbd_cleanup(void) 212 { 213 SDL_EVDEV_keyboard_state* kbd = kbd_cleanup_state; 214 if (kbd == NULL) { 215 return; 216 } 217 kbd_cleanup_state = NULL; 218 219 ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode); 220 } 221 222 void 223 SDL_EVDEV_kbd_reraise_signal(int sig) 224 { 225 raise(sig); 226 } 227 228 siginfo_t* SDL_EVDEV_kdb_cleanup_siginfo = NULL; 229 void* SDL_EVDEV_kdb_cleanup_ucontext = NULL; 230 231 static void kbd_cleanup_signal_action(int signum, siginfo_t* info, void* ucontext) 232 { 233 struct sigaction* old_action_p = &(old_sigaction[signum]); 234 sigset_t sigset; 235 236 /* Restore original signal handler before going any further. */ 237 sigaction(signum, old_action_p, NULL); 238 239 /* Unmask current signal. */ 240 sigemptyset(&sigset); 241 sigaddset(&sigset, signum); 242 sigprocmask(SIG_UNBLOCK, &sigset, NULL); 243 244 /* Save original signal info and context for archeologists. */ 245 SDL_EVDEV_kdb_cleanup_siginfo = info; 246 SDL_EVDEV_kdb_cleanup_ucontext = ucontext; 247 248 /* Restore keyboard. */ 249 kbd_cleanup(); 250 251 /* Reraise signal. */ 252 SDL_EVDEV_kbd_reraise_signal(signum); 253 } 254 255 static void kbd_unregister_emerg_cleanup() 256 { 257 int tabidx, signum; 258 259 kbd_cleanup_state = NULL; 260 261 if (!kbd_cleanup_sigactions_installed) { 262 return; 263 } 264 kbd_cleanup_sigactions_installed = 0; 265 266 for (tabidx = 0; tabidx < sizeof(fatal_signals) / sizeof(fatal_signals[0]); ++tabidx) { 267 struct sigaction* old_action_p; 268 struct sigaction cur_action; 269 signum = fatal_signals[tabidx]; 270 old_action_p = &(old_sigaction[signum]); 271 272 /* Examine current signal action */ 273 if (sigaction(signum, NULL, &cur_action)) 274 continue; 275 276 /* Check if action installed and not modifed */ 277 if (!(cur_action.sa_flags & SA_SIGINFO) 278 || cur_action.sa_sigaction != &kbd_cleanup_signal_action) 279 continue; 280 281 /* Restore original action */ 282 sigaction(signum, old_action_p, NULL); 283 } 284 } 285 286 static void kbd_cleanup_atexit(void) 287 { 288 /* Restore keyboard. */ 289 kbd_cleanup(); 290 291 /* Try to restore signal handlers in case shared library is being unloaded */ 292 kbd_unregister_emerg_cleanup(); 293 } 294 295 static void kbd_register_emerg_cleanup(SDL_EVDEV_keyboard_state * kbd) 296 { 297 int tabidx, signum; 298 299 if (kbd_cleanup_state != NULL) { 300 return; 301 } 302 kbd_cleanup_state = kbd; 303 304 if (!kbd_cleanup_atexit_installed) { 305 /* Since glibc 2.2.3, atexit() (and on_exit(3)) can be used within a shared library to establish 306 * functions that are called when the shared library is unloaded. 307 * -- man atexit(3) 308 */ 309 atexit(kbd_cleanup_atexit); 310 kbd_cleanup_atexit_installed = 1; 311 } 312 313 if (kbd_cleanup_sigactions_installed) { 314 return; 315 } 316 kbd_cleanup_sigactions_installed = 1; 317 318 for (tabidx = 0; tabidx < sizeof(fatal_signals) / sizeof(fatal_signals[0]); ++tabidx) { 319 struct sigaction* old_action_p; 320 struct sigaction new_action; 321 signum = fatal_signals[tabidx]; 322 old_action_p = &(old_sigaction[signum]); 323 if (sigaction(signum, NULL, old_action_p)) 324 continue; 325 326 /* Skip SIGHUP and SIGPIPE if handler is already installed 327 * - assume the handler will do the cleanup 328 */ 329 if ((signum == SIGHUP || signum == SIGPIPE) 330 && (old_action_p->sa_handler != SIG_DFL 331 || (void (*)(int))old_action_p->sa_sigaction != SIG_DFL)) 332 continue; 333 334 new_action = *old_action_p; 335 new_action.sa_flags |= SA_SIGINFO; 336 new_action.sa_sigaction = &kbd_cleanup_signal_action; 337 sigaction(signum, &new_action, NULL); 338 } 339 } 340 341 SDL_EVDEV_keyboard_state * 342 SDL_EVDEV_kbd_init(void) 343 { 344 SDL_EVDEV_keyboard_state *kbd; 345 int i; 346 char flag_state; 347 char shift_state[ sizeof (long) ] = {TIOCL_GETSHIFTSTATE, 0}; 348 349 kbd = (SDL_EVDEV_keyboard_state *)SDL_calloc(1, sizeof(*kbd)); 350 if (!kbd) { 351 return NULL; 352 } 353 354 kbd->npadch = -1; 355 356 /* This might fail if we're not connected to a tty (e.g. on the Steam Link) */ 357 kbd->console_fd = open("/dev/tty", O_RDONLY); 358 359 if (ioctl(kbd->console_fd, TIOCLINUX, shift_state) == 0) { 360 kbd->shift_state = *shift_state; 361 } 362 363 if (ioctl(kbd->console_fd, KDGKBLED, &flag_state) == 0) { 364 kbd->ledflagstate = flag_state; 365 } 366 367 kbd->accents = &default_accents; 368 if (ioctl(kbd->console_fd, KDGKBDIACR, kbd->accents) < 0) { 369 /* No worries, we'll use the default accent table */ 370 } 371 372 kbd->key_maps = default_key_maps; 373 if (ioctl(kbd->console_fd, KDGKBMODE, &kbd->old_kbd_mode) == 0) { 374 /* Set the keyboard in UNICODE mode and load the keymaps */ 375 ioctl(kbd->console_fd, KDSKBMODE, K_UNICODE); 376 377 if (SDL_EVDEV_kbd_load_keymaps(kbd) < 0) { 378 for (i = 0; i < MAX_NR_KEYMAPS; ++i) { 379 if (kbd->key_maps[i]) { 380 SDL_free(kbd->key_maps[i]); 381 } 382 } 383 SDL_free(kbd->key_maps); 384 385 kbd->key_maps = default_key_maps; 386 } 387 388 /* Allow inhibiting keyboard mute with env. variable for debugging etc. */ 389 if (getenv("SDL_INPUT_LINUX_KEEP_KBD") == NULL) { 390 /* Mute the keyboard so keystrokes only generate evdev events 391 * and do not leak through to the console 392 */ 393 ioctl(kbd->console_fd, KDSKBMODE, K_OFF); 394 395 /* Make sure to restore keyboard if application fails to call 396 * SDL_Quit before exit or fatal signal is raised. 397 */ 398 if (!SDL_GetHintBoolean(SDL_HINT_NO_SIGNAL_HANDLERS, SDL_FALSE)) { 399 kbd_register_emerg_cleanup(kbd); 400 } 401 } 402 } 403 404 #ifdef DUMP_ACCENTS 405 SDL_EVDEV_dump_accents(kbd); 406 #endif 407 #ifdef DUMP_KEYMAP 408 SDL_EVDEV_dump_keymap(kbd); 409 #endif 410 return kbd; 411 } 412 413 void 414 SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *kbd) 415 { 416 if (!kbd) { 417 return; 418 } 419 420 kbd_unregister_emerg_cleanup(); 421 422 if (kbd->console_fd >= 0) { 423 /* Restore the original keyboard mode */ 424 ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode); 425 426 close(kbd->console_fd); 427 kbd->console_fd = -1; 428 } 429 430 if (kbd->key_maps && kbd->key_maps != default_key_maps) { 431 int i; 432 for (i = 0; i < MAX_NR_KEYMAPS; ++i) { 433 if (kbd->key_maps[i]) { 434 SDL_free(kbd->key_maps[i]); 435 } 436 } 437 SDL_free(kbd->key_maps); 438 } 439 440 SDL_free(kbd); 441 } 442 443 /* 444 * Helper Functions. 445 */ 446 static void put_queue(SDL_EVDEV_keyboard_state *kbd, uint c) 447 { 448 /* c is already part of a UTF-8 sequence and safe to add as a character */ 449 if (kbd->text_len < (sizeof(kbd->text)-1)) { 450 kbd->text[kbd->text_len++] = (char)c; 451 } 452 } 453 454 static void put_utf8(SDL_EVDEV_keyboard_state *kbd, uint c) 455 { 456 if (c < 0x80) 457 /* 0******* */ 458 put_queue(kbd, c); 459 else if (c < 0x800) { 460 /* 110***** 10****** */ 461 put_queue(kbd, 0xc0 | (c >> 6)); 462 put_queue(kbd, 0x80 | (c & 0x3f)); 463 } else if (c < 0x10000) { 464 if (c >= 0xD800 && c < 0xE000) 465 return; 466 if (c == 0xFFFF) 467 return; 468 /* 1110**** 10****** 10****** */ 469 put_queue(kbd, 0xe0 | (c >> 12)); 470 put_queue(kbd, 0x80 | ((c >> 6) & 0x3f)); 471 put_queue(kbd, 0x80 | (c & 0x3f)); 472 } else if (c < 0x110000) { 473 /* 11110*** 10****** 10****** 10****** */ 474 put_queue(kbd, 0xf0 | (c >> 18)); 475 put_queue(kbd, 0x80 | ((c >> 12) & 0x3f)); 476 put_queue(kbd, 0x80 | ((c >> 6) & 0x3f)); 477 put_queue(kbd, 0x80 | (c & 0x3f)); 478 } 479 } 480 481 /* 482 * We have a combining character DIACR here, followed by the character CH. 483 * If the combination occurs in the table, return the corresponding value. 484 * Otherwise, if CH is a space or equals DIACR, return DIACR. 485 * Otherwise, conclude that DIACR was not combining after all, 486 * queue it and return CH. 487 */ 488 static unsigned int handle_diacr(SDL_EVDEV_keyboard_state *kbd, unsigned int ch) 489 { 490 unsigned int d = kbd->diacr; 491 unsigned int i; 492 493 kbd->diacr = 0; 494 495 for (i = 0; i < kbd->accents->kb_cnt; i++) { 496 if (kbd->accents->kbdiacr[i].diacr == d && 497 kbd->accents->kbdiacr[i].base == ch) { 498 return kbd->accents->kbdiacr[i].result; 499 } 500 } 501 502 if (ch == ' ' || ch == d) 503 return d; 504 505 put_utf8(kbd, d); 506 507 return ch; 508 } 509 510 static int vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag) 511 { 512 return (kbd->ledflagstate & flag) != 0; 513 } 514 515 static void set_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag) 516 { 517 kbd->ledflagstate |= flag; 518 ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate)); 519 } 520 521 static void clr_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag) 522 { 523 kbd->ledflagstate &= ~flag; 524 ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate)); 525 } 526 527 static void chg_vc_kbd_lock(SDL_EVDEV_keyboard_state *kbd, int flag) 528 { 529 kbd->lockstate ^= 1 << flag; 530 } 531 532 static void chg_vc_kbd_slock(SDL_EVDEV_keyboard_state *kbd, int flag) 533 { 534 kbd->slockstate ^= 1 << flag; 535 } 536 537 static void chg_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag) 538 { 539 kbd->ledflagstate ^= flag; 540 ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate)); 541 } 542 543 /* 544 * Special function handlers 545 */ 546 547 static void fn_enter(SDL_EVDEV_keyboard_state *kbd) 548 { 549 if (kbd->diacr) { 550 put_utf8(kbd, kbd->diacr); 551 kbd->diacr = 0; 552 } 553 } 554 555 static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd) 556 { 557 if (kbd->rep) 558 return; 559 560 chg_vc_kbd_led(kbd, K_CAPSLOCK); 561 } 562 563 static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd) 564 { 565 if (kbd->rep) 566 return; 567 568 set_vc_kbd_led(kbd, K_CAPSLOCK); 569 } 570 571 static void fn_num(SDL_EVDEV_keyboard_state *kbd) 572 { 573 if (!kbd->rep) 574 chg_vc_kbd_led(kbd, K_NUMLOCK); 575 } 576 577 static void fn_compose(SDL_EVDEV_keyboard_state *kbd) 578 { 579 kbd->dead_key_next = SDL_TRUE; 580 } 581 582 /* 583 * Special key handlers 584 */ 585 586 static void k_ignore(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 587 { 588 } 589 590 static void k_spec(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 591 { 592 if (up_flag) 593 return; 594 if (value >= SDL_arraysize(fn_handler)) 595 return; 596 if (fn_handler[value]) 597 fn_handler[value](kbd); 598 } 599 600 static void k_lowercase(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 601 { 602 } 603 604 static void k_self(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 605 { 606 if (up_flag) 607 return; /* no action, if this is a key release */ 608 609 if (kbd->diacr) 610 value = handle_diacr(kbd, value); 611 612 if (kbd->dead_key_next) { 613 kbd->dead_key_next = SDL_FALSE; 614 kbd->diacr = value; 615 return; 616 } 617 put_utf8(kbd, value); 618 } 619 620 static void k_deadunicode(SDL_EVDEV_keyboard_state *kbd, unsigned int value, char up_flag) 621 { 622 if (up_flag) 623 return; 624 625 kbd->diacr = (kbd->diacr ? handle_diacr(kbd, value) : value); 626 } 627 628 static void k_dead(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 629 { 630 const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; 631 632 k_deadunicode(kbd, ret_diacr[value], up_flag); 633 } 634 635 static void k_dead2(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 636 { 637 k_deadunicode(kbd, value, up_flag); 638 } 639 640 static void k_cons(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 641 { 642 } 643 644 static void k_fn(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 645 { 646 } 647 648 static void k_cur(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 649 { 650 } 651 652 static void k_pad(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 653 { 654 static const char pad_chars[] = "0123456789+-*/\015,.?()#"; 655 656 if (up_flag) 657 return; /* no action, if this is a key release */ 658 659 if (!vc_kbd_led(kbd, K_NUMLOCK)) { 660 /* unprintable action */ 661 return; 662 } 663 664 put_queue(kbd, pad_chars[value]); 665 } 666 667 static void k_shift(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 668 { 669 int old_state = kbd->shift_state; 670 671 if (kbd->rep) 672 return; 673 /* 674 * Mimic typewriter: 675 * a CapsShift key acts like Shift but undoes CapsLock 676 */ 677 if (value == KVAL(K_CAPSSHIFT)) { 678 value = KVAL(K_SHIFT); 679 if (!up_flag) 680 clr_vc_kbd_led(kbd, K_CAPSLOCK); 681 } 682 683 if (up_flag) { 684 /* 685 * handle the case that two shift or control 686 * keys are depressed simultaneously 687 */ 688 if (kbd->shift_down[value]) 689 kbd->shift_down[value]--; 690 } else 691 kbd->shift_down[value]++; 692 693 if (kbd->shift_down[value]) 694 kbd->shift_state |= (1 << value); 695 else 696 kbd->shift_state &= ~(1 << value); 697 698 /* kludge */ 699 if (up_flag && kbd->shift_state != old_state && kbd->npadch != -1) { 700 put_utf8(kbd, kbd->npadch); 701 kbd->npadch = -1; 702 } 703 } 704 705 static void k_meta(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 706 { 707 } 708 709 static void k_ascii(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 710 { 711 int base; 712 713 if (up_flag) 714 return; 715 716 if (value < 10) { 717 /* decimal input of code, while Alt depressed */ 718 base = 10; 719 } else { 720 /* hexadecimal input of code, while AltGr depressed */ 721 value -= 10; 722 base = 16; 723 } 724 725 if (kbd->npadch == -1) 726 kbd->npadch = value; 727 else 728 kbd->npadch = kbd->npadch * base + value; 729 } 730 731 static void k_lock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 732 { 733 if (up_flag || kbd->rep) 734 return; 735 736 chg_vc_kbd_lock(kbd, value); 737 } 738 739 static void k_slock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 740 { 741 k_shift(kbd, value, up_flag); 742 if (up_flag || kbd->rep) 743 return; 744 745 chg_vc_kbd_slock(kbd, value); 746 /* try to make Alt, oops, AltGr and such work */ 747 if (!kbd->key_maps[kbd->lockstate ^ kbd->slockstate]) { 748 kbd->slockstate = 0; 749 chg_vc_kbd_slock(kbd, value); 750 } 751 } 752 753 static void k_brl(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 754 { 755 } 756 757 void 758 SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode, int down) 759 { 760 unsigned char shift_final; 761 unsigned char type; 762 unsigned short *key_map; 763 unsigned short keysym; 764 765 if (!kbd) { 766 return; 767 } 768 769 kbd->rep = (down == 2); 770 771 shift_final = (kbd->shift_state | kbd->slockstate) ^ kbd->lockstate; 772 key_map = kbd->key_maps[shift_final]; 773 if (!key_map) { 774 /* Unsupported shift state (e.g. ctrl = 4, alt = 8), just reset to the default state */ 775 kbd->shift_state = 0; 776 kbd->slockstate = 0; 777 kbd->lockstate = 0; 778 return; 779 } 780 781 if (keycode < NR_KEYS) { 782 keysym = key_map[keycode]; 783 } else { 784 return; 785 } 786 787 type = KTYP(keysym); 788 789 if (type < 0xf0) { 790 if (down) { 791 put_utf8(kbd, keysym); 792 } 793 } else { 794 type -= 0xf0; 795 796 /* if type is KT_LETTER then it can be affected by Caps Lock */ 797 if (type == KT_LETTER) { 798 type = KT_LATIN; 799 800 if (vc_kbd_led(kbd, K_CAPSLOCK)) { 801 key_map = kbd->key_maps[shift_final ^ (1 << KG_SHIFT)]; 802 if (key_map) { 803 keysym = key_map[keycode]; 804 } 805 } 806 } 807 808 (*k_handler[type])(kbd, keysym & 0xff, !down); 809 810 if (type != KT_SLOCK) { 811 kbd->slockstate = 0; 812 } 813 } 814 815 if (kbd->text_len > 0) { 816 kbd->text[kbd->text_len] = '\0'; 817 SDL_SendKeyboardText(kbd->text); 818 kbd->text_len = 0; 819 } 820 } 821 822 #elif !defined(SDL_INPUT_FBSDKBIO) /* !SDL_INPUT_LINUXKD */ 823 824 SDL_EVDEV_keyboard_state * 825 SDL_EVDEV_kbd_init(void) 826 { 827 return NULL; 828 } 829 830 void 831 SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down) 832 { 833 } 834 835 void 836 SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state) 837 { 838 } 839 840 #endif /* SDL_INPUT_LINUXKD */ 841 842 /* vi: set ts=4 sw=4 expandtab: */