Atlas - SDL_evdev_kbd.c
Home / ext / SDL2 / src / core / linux Lines: 16 | Size: 21946 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 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#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 62typedef void (k_handler_fn)(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag); 63static k_handler_fn K_HANDLERS; 64static k_handler_fn *k_handler[16] = { K_HANDLERS }; 65 66typedef void (fn_handler_fn)(SDL_EVDEV_keyboard_state *kbd); 67static void fn_enter(SDL_EVDEV_keyboard_state *kbd); 68static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd); 69static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd); 70static void fn_num(SDL_EVDEV_keyboard_state *kbd); 71static void fn_compose(SDL_EVDEV_keyboard_state *kbd); 72 73static 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 87struct 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 107static 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 129static 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 158static 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 197static SDL_EVDEV_keyboard_state * kbd_cleanup_state = NULL; 198static int kbd_cleanup_sigactions_installed = 0; 199static int kbd_cleanup_atexit_installed = 0; 200 201static struct sigaction old_sigaction[NSIG] = { 0 }; 202 203static 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 211static 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 fprintf(stderr, "(SDL restoring keyboard) "); 220 ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode); 221} 222 223void 224SDL_EVDEV_kbd_reraise_signal(int sig) 225{ 226 raise(sig); 227} 228 229siginfo_t* SDL_EVDEV_kdb_cleanup_siginfo = NULL; 230void* SDL_EVDEV_kdb_cleanup_ucontext = NULL; 231 232static void kbd_cleanup_signal_action(int signum, siginfo_t* info, void* ucontext) 233{ 234 struct sigaction* old_action_p = &(old_sigaction[signum]); 235 sigset_t sigset; 236 237 /* Restore original signal handler before going any further. */ 238 sigaction(signum, old_action_p, NULL); 239 240 /* Unmask current signal. */ 241 sigemptyset(&sigset); 242 sigaddset(&sigset, signum); 243 sigprocmask(SIG_UNBLOCK, &sigset, NULL); 244 245 /* Save original signal info and context for archeologists. */ 246 SDL_EVDEV_kdb_cleanup_siginfo = info; 247 SDL_EVDEV_kdb_cleanup_ucontext = ucontext; 248 249 /* Restore keyboard. */ 250 kbd_cleanup(); 251 252 /* Reraise signal. */ 253 SDL_EVDEV_kbd_reraise_signal(signum); 254} 255 256static void kbd_unregister_emerg_cleanup() 257{ 258 int tabidx, signum; 259 260 kbd_cleanup_state = NULL; 261 262 if (!kbd_cleanup_sigactions_installed) { 263 return; 264 } 265 kbd_cleanup_sigactions_installed = 0; 266 267 for (tabidx = 0; tabidx < sizeof(fatal_signals) / sizeof(fatal_signals[0]); ++tabidx) { 268 struct sigaction* old_action_p; 269 struct sigaction cur_action; 270 signum = fatal_signals[tabidx]; 271 old_action_p = &(old_sigaction[signum]); 272 273 /* Examine current signal action */ 274 if (sigaction(signum, NULL, &cur_action)) 275 continue; 276 277 /* Check if action installed and not modifed */ 278 if (!(cur_action.sa_flags & SA_SIGINFO) 279 || cur_action.sa_sigaction != &kbd_cleanup_signal_action) 280 continue; 281 282 /* Restore original action */ 283 sigaction(signum, old_action_p, NULL); 284 } 285} 286 287static void kbd_cleanup_atexit(void) 288{ 289 /* Restore keyboard. */ 290 kbd_cleanup(); 291 292 /* Try to restore signal handlers in case shared library is being unloaded */ 293 kbd_unregister_emerg_cleanup(); 294} 295 296static void kbd_register_emerg_cleanup(SDL_EVDEV_keyboard_state * kbd) 297{ 298 int tabidx, signum; 299 300 if (kbd_cleanup_state != NULL) { 301 return; 302 } 303 kbd_cleanup_state = kbd; 304 305 if (!kbd_cleanup_atexit_installed) { 306 /* Since glibc 2.2.3, atexit() (and on_exit(3)) can be used within a shared library to establish 307 * functions that are called when the shared library is unloaded. 308 * -- man atexit(3) 309 */ 310 atexit(kbd_cleanup_atexit); 311 kbd_cleanup_atexit_installed = 1; 312 } 313 314 if (kbd_cleanup_sigactions_installed) { 315 return; 316 } 317 kbd_cleanup_sigactions_installed = 1; 318 319 for (tabidx = 0; tabidx < sizeof(fatal_signals) / sizeof(fatal_signals[0]); ++tabidx) { 320 struct sigaction* old_action_p; 321 struct sigaction new_action; 322 signum = fatal_signals[tabidx]; 323 old_action_p = &(old_sigaction[signum]); 324 if (sigaction(signum, NULL, old_action_p)) 325 continue; 326 327 /* Skip SIGHUP and SIGPIPE if handler is already installed 328 * - assume the handler will do the cleanup 329 */ 330 if ((signum == SIGHUP || signum == SIGPIPE) 331 && (old_action_p->sa_handler != SIG_DFL 332 || (void (*)(int))old_action_p->sa_sigaction != SIG_DFL)) 333 continue; 334 335 new_action = *old_action_p; 336 new_action.sa_flags |= SA_SIGINFO; 337 new_action.sa_sigaction = &kbd_cleanup_signal_action; 338 sigaction(signum, &new_action, NULL); 339 } 340} 341 342SDL_EVDEV_keyboard_state * 343SDL_EVDEV_kbd_init(void) 344{ 345 SDL_EVDEV_keyboard_state *kbd; 346 int i; 347 char flag_state; 348 char shift_state[2] = {TIOCL_GETSHIFTSTATE, 0}; 349 350 kbd = (SDL_EVDEV_keyboard_state *)SDL_calloc(1, sizeof(*kbd)); 351 if (!kbd) { 352 return NULL; 353 } 354 355 kbd->npadch = -1; 356 357 /* This might fail if we're not connected to a tty (e.g. on the Steam Link) */ 358 kbd->console_fd = open("/dev/tty", O_RDONLY); 359 360 if (ioctl(kbd->console_fd, TIOCLINUX, shift_state) == 0) { 361 kbd->shift_state = *shift_state; 362 } 363 364 if (ioctl(kbd->console_fd, KDGKBLED, &flag_state) == 0) { 365 kbd->ledflagstate = flag_state; 366 } 367 368 kbd->accents = &default_accents; 369 if (ioctl(kbd->console_fd, KDGKBDIACR, kbd->accents) < 0) { 370 /* No worries, we'll use the default accent table */ 371 } 372 373 kbd->key_maps = default_key_maps; 374 if (ioctl(kbd->console_fd, KDGKBMODE, &kbd->old_kbd_mode) == 0) { 375 /* Set the keyboard in UNICODE mode and load the keymaps */ 376 ioctl(kbd->console_fd, KDSKBMODE, K_UNICODE); 377 378 if (SDL_EVDEV_kbd_load_keymaps(kbd) < 0) { 379 for (i = 0; i < MAX_NR_KEYMAPS; ++i) { 380 if (kbd->key_maps[i]) { 381 SDL_free(kbd->key_maps[i]); 382 } 383 } 384 SDL_free(kbd->key_maps); 385 386 kbd->key_maps = default_key_maps; 387 } 388 389 /* Allow inhibiting keyboard mute with env. variable for debugging etc. */ 390 if (getenv("SDL_INPUT_LINUX_KEEP_KBD") == NULL) { 391 /* Mute the keyboard so keystrokes only generate evdev events 392 * and do not leak through to the console 393 */ 394 ioctl(kbd->console_fd, KDSKBMODE, K_OFF); 395 396 /* Make sure to restore keyboard if application fails to call 397 * SDL_Quit before exit or fatal signal is raised. 398 */ 399 if (!SDL_GetHintBoolean(SDL_HINT_NO_SIGNAL_HANDLERS, SDL_FALSE)) { 400 kbd_register_emerg_cleanup(kbd); 401 } 402 } 403 } 404 405#ifdef DUMP_ACCENTS 406 SDL_EVDEV_dump_accents(kbd); 407#endif 408#ifdef DUMP_KEYMAP 409 SDL_EVDEV_dump_keymap(kbd); 410#endif 411 return kbd; 412} 413 414void 415SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *kbd) 416{ 417 if (!kbd) { 418 return; 419 } 420 421 kbd_unregister_emerg_cleanup(); 422 423 if (kbd->console_fd >= 0) { 424 /* Restore the original keyboard mode */ 425 ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode); 426 427 close(kbd->console_fd); 428 kbd->console_fd = -1; 429 } 430 431 if (kbd->key_maps && kbd->key_maps != default_key_maps) { 432 int i; 433 for (i = 0; i < MAX_NR_KEYMAPS; ++i) { 434 if (kbd->key_maps[i]) { 435 SDL_free(kbd->key_maps[i]); 436 } 437 } 438 SDL_free(kbd->key_maps); 439 } 440 441 SDL_free(kbd); 442} 443 444/* 445 * Helper Functions. 446 */ 447static void put_queue(SDL_EVDEV_keyboard_state *kbd, uint c) 448{ 449 /* c is already part of a UTF-8 sequence and safe to add as a character */ 450 if (kbd->text_len < (sizeof(kbd->text)-1)) { 451 kbd->text[kbd->text_len++] = (char)c; 452 } 453} 454 455static void put_utf8(SDL_EVDEV_keyboard_state *kbd, uint c) 456{ 457 if (c < 0x80) 458 /* 0******* */ 459 put_queue(kbd, c); 460 else if (c < 0x800) { 461 /* 110***** 10****** */ 462 put_queue(kbd, 0xc0 | (c >> 6)); 463 put_queue(kbd, 0x80 | (c & 0x3f)); 464 } else if (c < 0x10000) { 465 if (c >= 0xD800 && c < 0xE000) 466 return; 467 if (c == 0xFFFF) 468 return; 469 /* 1110**** 10****** 10****** */ 470 put_queue(kbd, 0xe0 | (c >> 12)); 471 put_queue(kbd, 0x80 | ((c >> 6) & 0x3f)); 472 put_queue(kbd, 0x80 | (c & 0x3f)); 473 } else if (c < 0x110000) { 474 /* 11110*** 10****** 10****** 10****** */ 475 put_queue(kbd, 0xf0 | (c >> 18)); 476 put_queue(kbd, 0x80 | ((c >> 12) & 0x3f)); 477 put_queue(kbd, 0x80 | ((c >> 6) & 0x3f)); 478 put_queue(kbd, 0x80 | (c & 0x3f)); 479 } 480} 481 482/* 483 * We have a combining character DIACR here, followed by the character CH. 484 * If the combination occurs in the table, return the corresponding value. 485 * Otherwise, if CH is a space or equals DIACR, return DIACR. 486 * Otherwise, conclude that DIACR was not combining after all, 487 * queue it and return CH. 488 */ 489static unsigned int handle_diacr(SDL_EVDEV_keyboard_state *kbd, unsigned int ch) 490{ 491 unsigned int d = kbd->diacr; 492 unsigned int i; 493 494 kbd->diacr = 0; 495 496 for (i = 0; i < kbd->accents->kb_cnt; i++) { 497 if (kbd->accents->kbdiacr[i].diacr == d && 498 kbd->accents->kbdiacr[i].base == ch) { 499 return kbd->accents->kbdiacr[i].result; 500 } 501 } 502 503 if (ch == ' ' || ch == d) 504 return d; 505 506 put_utf8(kbd, d); 507 508 return ch; 509} 510 511static int vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag) 512{ 513 return ((kbd->ledflagstate >> flag) & 1); 514} 515 516static void set_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag) 517{ 518 kbd->ledflagstate |= 1 << flag; 519} 520 521static void clr_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag) 522{ 523 kbd->ledflagstate &= ~(1 << flag); 524} 525 526static void chg_vc_kbd_lock(SDL_EVDEV_keyboard_state *kbd, int flag) 527{ 528 kbd->lockstate ^= 1 << flag; 529} 530 531static void chg_vc_kbd_slock(SDL_EVDEV_keyboard_state *kbd, int flag) 532{ 533 kbd->slockstate ^= 1 << flag; 534} 535 536static void chg_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag) 537{ 538 kbd->ledflagstate ^= 1 << flag; 539} 540 541/* 542 * Special function handlers 543 */ 544 545static void fn_enter(SDL_EVDEV_keyboard_state *kbd) 546{ 547 if (kbd->diacr) { 548 put_utf8(kbd, kbd->diacr); 549 kbd->diacr = 0; 550 } 551} 552 553static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd) 554{ 555 if (kbd->rep) 556 return; 557 558 chg_vc_kbd_led(kbd, K_CAPSLOCK); 559} 560 561static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd) 562{ 563 if (kbd->rep) 564 return; 565 566 set_vc_kbd_led(kbd, K_CAPSLOCK); 567} 568 569static void fn_num(SDL_EVDEV_keyboard_state *kbd) 570{ 571 if (!kbd->rep) 572 chg_vc_kbd_led(kbd, K_NUMLOCK); 573} 574 575static void fn_compose(SDL_EVDEV_keyboard_state *kbd) 576{ 577 kbd->dead_key_next = SDL_TRUE; 578} 579 580/* 581 * Special key handlers 582 */ 583 584static void k_ignore(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 585{ 586} 587 588static void k_spec(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 589{ 590 if (up_flag) 591 return; 592 if (value >= SDL_arraysize(fn_handler)) 593 return; 594 if (fn_handler[value]) 595 fn_handler[value](kbd); 596} 597 598static void k_lowercase(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 599{ 600} 601 602static void k_self(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 603{ 604 if (up_flag) 605 return; /* no action, if this is a key release */ 606 607 if (kbd->diacr) 608 value = handle_diacr(kbd, value); 609 610 if (kbd->dead_key_next) { 611 kbd->dead_key_next = SDL_FALSE; 612 kbd->diacr = value; 613 return; 614 } 615 put_utf8(kbd, value); 616} 617 618static void k_deadunicode(SDL_EVDEV_keyboard_state *kbd, unsigned int value, char up_flag) 619{ 620 if (up_flag) 621 return; 622 623 kbd->diacr = (kbd->diacr ? handle_diacr(kbd, value) : value); 624} 625 626static void k_dead(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 627{ 628 const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; 629 630 k_deadunicode(kbd, ret_diacr[value], up_flag); 631} 632 633static void k_dead2(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 634{ 635 k_deadunicode(kbd, value, up_flag); 636} 637 638static void k_cons(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 639{ 640} 641 642static void k_fn(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 643{ 644} 645 646static void k_cur(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 647{ 648} 649 650static void k_pad(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 651{ 652 static const char pad_chars[] = "0123456789+-*/\015,.?()#"; 653 654 if (up_flag) 655 return; /* no action, if this is a key release */ 656 657 if (!vc_kbd_led(kbd, K_NUMLOCK)) { 658 /* unprintable action */ 659 return; 660 } 661 662 put_queue(kbd, pad_chars[value]); 663} 664 665static void k_shift(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 666{ 667 int old_state = kbd->shift_state; 668 669 if (kbd->rep) 670 return; 671 /* 672 * Mimic typewriter: 673 * a CapsShift key acts like Shift but undoes CapsLock 674 */ 675 if (value == KVAL(K_CAPSSHIFT)) { 676 value = KVAL(K_SHIFT); 677 if (!up_flag) 678 clr_vc_kbd_led(kbd, K_CAPSLOCK); 679 } 680 681 if (up_flag) { 682 /* 683 * handle the case that two shift or control 684 * keys are depressed simultaneously 685 */ 686 if (kbd->shift_down[value]) 687 kbd->shift_down[value]--; 688 } else 689 kbd->shift_down[value]++; 690 691 if (kbd->shift_down[value]) 692 kbd->shift_state |= (1 << value); 693 else 694 kbd->shift_state &= ~(1 << value); 695 696 /* kludge */ 697 if (up_flag && kbd->shift_state != old_state && kbd->npadch != -1) { 698 put_utf8(kbd, kbd->npadch); 699 kbd->npadch = -1; 700 } 701} 702 703static void k_meta(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 704{ 705} 706 707static void k_ascii(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 708{ 709 int base; 710 711 if (up_flag) 712 return; 713 714 if (value < 10) { 715 /* decimal input of code, while Alt depressed */ 716 base = 10; 717 } else { 718 /* hexadecimal input of code, while AltGr depressed */ 719 value -= 10; 720 base = 16; 721 } 722 723 if (kbd->npadch == -1) 724 kbd->npadch = value; 725 else 726 kbd->npadch = kbd->npadch * base + value; 727} 728 729static void k_lock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 730{ 731 if (up_flag || kbd->rep) 732 return; 733 734 chg_vc_kbd_lock(kbd, value); 735} 736 737static void k_slock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 738{ 739 k_shift(kbd, value, up_flag); 740 if (up_flag || kbd->rep) 741 return; 742 743 chg_vc_kbd_slock(kbd, value); 744 /* try to make Alt, oops, AltGr and such work */ 745 if (!kbd->key_maps[kbd->lockstate ^ kbd->slockstate]) { 746 kbd->slockstate = 0; 747 chg_vc_kbd_slock(kbd, value); 748 } 749} 750 751static void k_brl(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag) 752{ 753} 754 755void 756SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode, int down) 757{ 758 unsigned char shift_final; 759 unsigned char type; 760 unsigned short *key_map; 761 unsigned short keysym; 762 763 if (!kbd) { 764 return; 765 } 766 767 kbd->rep = (down == 2); 768 769 shift_final = (kbd->shift_state | kbd->slockstate) ^ kbd->lockstate; 770 key_map = kbd->key_maps[shift_final]; 771 if (!key_map) { 772 /* Unsupported shift state (e.g. ctrl = 4, alt = 8), just reset to the default state */ 773 kbd->shift_state = 0; 774 kbd->slockstate = 0; 775 kbd->lockstate = 0; 776 return; 777 } 778 779 if (keycode < NR_KEYS) { 780 keysym = key_map[keycode]; 781 } else { 782 return; 783 } 784 785 type = KTYP(keysym); 786 787 if (type < 0xf0) { 788 if (down) { 789 put_utf8(kbd, keysym); 790 } 791 } else { 792 type -= 0xf0; 793 794 /* if type is KT_LETTER then it can be affected by Caps Lock */ 795 if (type == KT_LETTER) { 796 type = KT_LATIN; 797 798 if (vc_kbd_led(kbd, K_CAPSLOCK)) { 799 key_map = kbd->key_maps[shift_final ^ (1 << KG_SHIFT)]; 800 if (key_map) { 801 keysym = key_map[keycode]; 802 } 803 } 804 } 805 806 (*k_handler[type])(kbd, keysym & 0xff, !down); 807 808 if (type != KT_SLOCK) { 809 kbd->slockstate = 0; 810 } 811 } 812 813 if (kbd->text_len > 0) { 814 kbd->text[kbd->text_len] = '\0'; 815 SDL_SendKeyboardText(kbd->text); 816 kbd->text_len = 0; 817 } 818} 819 820#else /* !SDL_INPUT_LINUXKD */ 821 822SDL_EVDEV_keyboard_state * 823SDL_EVDEV_kbd_init(void) 824{ 825 return NULL; 826} 827 828void 829SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down) 830{ 831} 832 833void 834SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state) 835{ 836} 837 838#endif /* SDL_INPUT_LINUXKD */ 839 840/* vi: set ts=4 sw=4 expandtab: */ 841[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.