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