Atlas - SDL_evdev_kbd.c
Home / ext / SDL / src / core / linux Lines: 16 | Size: 26222 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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 SDL_free(state->key_maps[i]); 538 } 539 SDL_free(state->key_maps); 540 } 541 542 SDL_free(state); 543} 544 545/* 546 * Helper Functions. 547 */ 548static void put_queue(SDL_EVDEV_keyboard_state *kbd, uint c) 549{ 550 // c is already part of a UTF-8 sequence and safe to add as a character 551 if (kbd->text_len < (sizeof(kbd->text) - 1)) { 552 kbd->text[kbd->text_len++] = (char)c; 553 } 554} 555 556static void put_utf8(SDL_EVDEV_keyboard_state *kbd, uint c) 557{ 558 if (c < 0x80) { 559 put_queue(kbd, c); /* 0******* */ 560 } else if (c < 0x800) { 561 /* 110***** 10****** */ 562 put_queue(kbd, 0xc0 | (c >> 6)); 563 put_queue(kbd, 0x80 | (c & 0x3f)); 564 } else if (c < 0x10000) { 565 if (c >= 0xD800 && c < 0xE000) { 566 return; 567 } 568 if (c == 0xFFFF) { 569 return; 570 } 571 /* 1110**** 10****** 10****** */ 572 put_queue(kbd, 0xe0 | (c >> 12)); 573 put_queue(kbd, 0x80 | ((c >> 6) & 0x3f)); 574 put_queue(kbd, 0x80 | (c & 0x3f)); 575 } else if (c < 0x110000) { 576 /* 11110*** 10****** 10****** 10****** */ 577 put_queue(kbd, 0xf0 | (c >> 18)); 578 put_queue(kbd, 0x80 | ((c >> 12) & 0x3f)); 579 put_queue(kbd, 0x80 | ((c >> 6) & 0x3f)); 580 put_queue(kbd, 0x80 | (c & 0x3f)); 581 } 582} 583 584/* 585 * We have a combining character DIACR here, followed by the character CH. 586 * If the combination occurs in the table, return the corresponding value. 587 * Otherwise, if CH is a space or equals DIACR, return DIACR. 588 * Otherwise, conclude that DIACR was not combining after all, 589 * queue it and return CH. 590 */ 591static unsigned int handle_diacr(SDL_EVDEV_keyboard_state *kbd, unsigned int ch) 592{ 593 unsigned int d = kbd->diacr; 594 unsigned int i; 595 596 kbd->diacr = 0; 597 598 if (kbd->console_fd >= 0) 599 if (ioctl(kbd->console_fd, KDGKBDIACR, kbd->accents) < 0) { 600 // No worries, we'll use the default accent table 601 } 602 603 for (i = 0; i < kbd->accents->kb_cnt; i++) { 604 if (kbd->accents->kbdiacr[i].diacr == d && 605 kbd->accents->kbdiacr[i].base == ch) { 606 return kbd->accents->kbdiacr[i].result; 607 } 608 } 609 610 if (ch == ' ' || ch == d) { 611 return d; 612 } 613 614 put_utf8(kbd, d); 615 616 return ch; 617} 618 619static bool vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag) 620{ 621 return (kbd->ledflagstate & flag) != 0; 622} 623 624static void set_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag) 625{ 626 kbd->ledflagstate |= flag; 627 ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate)); 628} 629 630static void clr_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag) 631{ 632 kbd->ledflagstate &= ~flag; 633 ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate)); 634} 635 636static void chg_vc_kbd_lock(SDL_EVDEV_keyboard_state *kbd, int flag) 637{ 638 kbd->lockstate ^= 1 << flag; 639} 640 641static void chg_vc_kbd_slock(SDL_EVDEV_keyboard_state *kbd, int flag) 642{ 643 kbd->slockstate ^= 1 << flag; 644} 645 646static void chg_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag) 647{ 648 kbd->ledflagstate ^= flag; 649 ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate)); 650} 651 652/* 653 * Special function handlers 654 */ 655 656static void fn_enter(SDL_EVDEV_keyboard_state *kbd) 657{ 658 if (kbd->diacr) { 659 put_utf8(kbd, kbd->diacr); 660 kbd->diacr = 0; 661 } 662} 663 664static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd) 665{ 666 if (kbd->rep) { 667 return; 668 } 669 670 chg_vc_kbd_led(kbd, K_CAPSLOCK); 671} 672 673static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd) 674{ 675 if (kbd->rep) { 676 return; 677 } 678 679 set_vc_kbd_led(kbd, K_CAPSLOCK); 680} 681 682static void fn_num(SDL_EVDEV_keyboard_state *kbd) 683{ 684 if (!kbd->rep) { 685 chg_vc_kbd_led(kbd, K_NUMLOCK); 686 } 687} 688 689static void fn_compose(SDL_EVDEV_keyboard_state *kbd) 690{ 691 kbd->dead_key_next = true; 692} 693 694/* 695 * Special key handlers 696 */ 697 698static void k_ignore(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 699{ 700} 701 702static void k_spec(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 703{ 704 if (up_flag) { 705 return; 706 } 707 if (value >= SDL_arraysize(fn_handler)) { 708 return; 709 } 710 if (fn_handler[value]) { 711 fn_handler[value](kbd); 712 } 713} 714 715static void k_lowercase(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 716{ 717} 718 719static void k_self(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 720{ 721 if (up_flag) { 722 return; // no action, if this is a key release 723 } 724 725 if (kbd->diacr) { 726 value = handle_diacr(kbd, value); 727 } 728 729 if (kbd->dead_key_next) { 730 kbd->dead_key_next = false; 731 kbd->diacr = value; 732 return; 733 } 734 put_utf8(kbd, value); 735} 736 737static void k_deadunicode(SDL_EVDEV_keyboard_state *kbd, unsigned int value, char up_flag) 738{ 739 if (up_flag) { 740 return; 741 } 742 743 kbd->diacr = (kbd->diacr ? handle_diacr(kbd, value) : value); 744} 745 746static void k_dead(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 747{ 748 const unsigned char ret_diacr[NR_DEAD] = { '`', '\'', '^', '~', '"', ',' }; 749 750 k_deadunicode(kbd, ret_diacr[value], up_flag); 751} 752 753static void k_dead2(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 754{ 755 k_deadunicode(kbd, value, up_flag); 756} 757 758static void k_cons(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 759{ 760} 761 762static void k_fn(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 763{ 764} 765 766static void k_cur(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 767{ 768} 769 770static void k_pad(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 771{ 772 static const char pad_chars[] = "0123456789+-*/\015,.?()#"; 773 774 if (up_flag) { 775 return; // no action, if this is a key release 776 } 777 778 if (!vc_kbd_led(kbd, K_NUMLOCK)) { 779 // unprintable action 780 return; 781 } 782 783 put_queue(kbd, pad_chars[value]); 784} 785 786static void k_shift(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 787{ 788 int old_state = kbd->shift_state; 789 790 if (kbd->rep) { 791 return; 792 } 793 /* 794 * Mimic typewriter: 795 * a CapsShift key acts like Shift but undoes CapsLock 796 */ 797 if (value == KVAL(K_CAPSSHIFT)) { 798 value = KVAL(K_SHIFT); 799 if (!up_flag) { 800 clr_vc_kbd_led(kbd, K_CAPSLOCK); 801 } 802 } 803 804 if (up_flag) { 805 /* 806 * handle the case that two shift or control 807 * keys are depressed simultaneously 808 */ 809 if (kbd->shift_down[value]) { 810 kbd->shift_down[value]--; 811 } 812 } else { 813 kbd->shift_down[value]++; 814 } 815 816 if (kbd->shift_down[value]) { 817 kbd->shift_state |= (1 << value); 818 } else { 819 kbd->shift_state &= ~(1 << value); 820 } 821 822 // kludge 823 if (up_flag && kbd->shift_state != old_state && kbd->npadch != -1) { 824 put_utf8(kbd, kbd->npadch); 825 kbd->npadch = -1; 826 } 827} 828 829static void k_meta(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 830{ 831} 832 833static void k_ascii(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 834{ 835 int base; 836 837 if (up_flag) { 838 return; 839 } 840 841 if (value < 10) { 842 // decimal input of code, while Alt depressed 843 base = 10; 844 } else { 845 // hexadecimal input of code, while AltGr depressed 846 value -= 10; 847 base = 16; 848 } 849 850 if (kbd->npadch == -1) { 851 kbd->npadch = value; 852 } else { 853 kbd->npadch = kbd->npadch * base + value; 854 } 855} 856 857static void k_lock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 858{ 859 if (up_flag || kbd->rep) { 860 return; 861 } 862 863 chg_vc_kbd_lock(kbd, value); 864} 865 866static void k_slock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 867{ 868 k_shift(kbd, value, up_flag); 869 if (up_flag || kbd->rep) { 870 return; 871 } 872 873 chg_vc_kbd_slock(kbd, value); 874 // try to make Alt, oops, AltGr and such work 875 if (!kbd->key_maps[kbd->lockstate ^ kbd->slockstate]) { 876 kbd->slockstate = 0; 877 chg_vc_kbd_slock(kbd, value); 878 } 879} 880 881static void k_brl(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 882{ 883} 884 885void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down) 886{ 887 unsigned char shift_final; 888 unsigned char type; 889 unsigned short *key_map; 890 unsigned short keysym; 891 892 if (!state) { 893 return; 894 } 895 896 state->rep = (down == 2); 897 898 shift_final = (state->shift_state | state->slockstate) ^ state->lockstate; 899 key_map = state->key_maps[shift_final]; 900 if (!key_map) { 901 // Unsupported shift state (e.g. ctrl = 4, alt = 8), just reset to the default state 902 state->shift_state = 0; 903 state->slockstate = 0; 904 state->lockstate = 0; 905 return; 906 } 907 908 if (keycode < NR_KEYS) { 909 if (state->console_fd < 0) { 910 keysym = key_map[keycode]; 911 } else { 912 struct kbentry kbe; 913 kbe.kb_table = shift_final; 914 kbe.kb_index = keycode; 915 if (ioctl(state->console_fd, KDGKBENT, &kbe) == 0) 916 keysym = (kbe.kb_value ^ 0xf000); 917 else 918 return; 919 } 920 } else { 921 return; 922 } 923 924 type = KTYP(keysym); 925 926 if (type < 0xf0) { 927 if (down) { 928 put_utf8(state, keysym); 929 } 930 } else { 931 type -= 0xf0; 932 933 // if type is KT_LETTER then it can be affected by Caps Lock 934 if (type == KT_LETTER) { 935 type = KT_LATIN; 936 937 if (vc_kbd_led(state, K_CAPSLOCK)) { 938 shift_final = shift_final ^ (1 << KG_SHIFT); 939 key_map = state->key_maps[shift_final]; 940 if (key_map) { 941 if (state->console_fd < 0) { 942 keysym = key_map[keycode]; 943 } else { 944 struct kbentry kbe; 945 kbe.kb_table = shift_final; 946 kbe.kb_index = keycode; 947 if (ioctl(state->console_fd, KDGKBENT, &kbe) == 0) 948 keysym = (kbe.kb_value ^ 0xf000); 949 } 950 } 951 } 952 } 953 954 (*k_handler[type])(state, keysym & 0xff, !down); 955 956 if (type != KT_SLOCK) { 957 state->slockstate = 0; 958 } 959 } 960 961 if (state->text_len > 0) { 962 state->text[state->text_len] = '\0'; 963 SDL_SendKeyboardText(state->text); 964 state->text_len = 0; 965 } 966} 967 968#elif !defined(SDL_INPUT_FBSDKBIO) // !SDL_INPUT_LINUXKD 969 970SDL_EVDEV_keyboard_state *SDL_EVDEV_kbd_init(void) 971{ 972 return NULL; 973} 974 975void SDL_EVDEV_kbd_set_muted(SDL_EVDEV_keyboard_state *state, bool muted) 976{ 977} 978 979void 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) 980{ 981} 982 983void SDL_EVDEV_kbd_update(SDL_EVDEV_keyboard_state *state) 984{ 985} 986 987void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down) 988{ 989} 990 991void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state) 992{ 993} 994 995#endif // SDL_INPUT_LINUXKD 996[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.