Mac and Linux SDL2 binary snapshots
Edward Rudd
2019-04-09 9cd2e9ec8fc0127393dfce9c0359d500c8c238be
source/src/core/linux/SDL_evdev_kbd.c
@@ -21,6 +21,7 @@
#include "../../SDL_internal.h"
#include "SDL_evdev_kbd.h"
#include "SDL_hints.h"
#ifdef SDL_INPUT_LINUXKD
@@ -33,6 +34,8 @@
#include <linux/keyboard.h>
#include <linux/vt.h>
#include <linux/tiocl.h> /* for TIOCL_GETSHIFTSTATE */
#include <signal.h>
#include "../../events/SDL_events_c.h"
#include "SDL_evdev_kbd_default_accents.h"
@@ -191,6 +194,151 @@
    return 0;
}
static SDL_EVDEV_keyboard_state * kbd_cleanup_state = NULL;
static int kbd_cleanup_sigactions_installed = 0;
static int kbd_cleanup_atexit_installed = 0;
static struct sigaction old_sigaction[NSIG];
static int fatal_signals[] =
{
    /* Handlers for SIGTERM and SIGINT are installed in SDL_QuitInit. */
    SIGHUP,  SIGQUIT, SIGILL,  SIGABRT,
    SIGFPE,  SIGSEGV, SIGPIPE, SIGBUS,
    SIGSYS
};
static void kbd_cleanup(void)
{
    SDL_EVDEV_keyboard_state* kbd = kbd_cleanup_state;
    if (kbd == NULL) {
        return;
    }
    kbd_cleanup_state = NULL;
    fprintf(stderr, "(SDL restoring keyboard) ");
    ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
}
void
SDL_EVDEV_kbd_reraise_signal(int sig)
{
    raise(sig);
}
siginfo_t* SDL_EVDEV_kdb_cleanup_siginfo = NULL;
void*      SDL_EVDEV_kdb_cleanup_ucontext = NULL;
static void kbd_cleanup_signal_action(int signum, siginfo_t* info, void* ucontext)
{
    struct sigaction* old_action_p = &(old_sigaction[signum]);
    sigset_t sigset;
    /* Restore original signal handler before going any further. */
    sigaction(signum, old_action_p, NULL);
    /* Unmask current signal. */
    sigemptyset(&sigset);
    sigaddset(&sigset, signum);
    sigprocmask(SIG_UNBLOCK, &sigset, NULL);
    /* Save original signal info and context for archeologists. */
    SDL_EVDEV_kdb_cleanup_siginfo = info;
    SDL_EVDEV_kdb_cleanup_ucontext = ucontext;
    /* Restore keyboard. */
    kbd_cleanup();
    /* Reraise signal. */
    SDL_EVDEV_kbd_reraise_signal(signum);
}
static void kbd_unregister_emerg_cleanup()
{
    int tabidx, signum;
    kbd_cleanup_state = NULL;
    if (!kbd_cleanup_sigactions_installed) {
        return;
    }
    kbd_cleanup_sigactions_installed = 0;
    for (tabidx = 0; tabidx < sizeof(fatal_signals) / sizeof(fatal_signals[0]); ++tabidx) {
        struct sigaction* old_action_p;
        struct sigaction cur_action;
        signum = fatal_signals[tabidx];
        old_action_p = &(old_sigaction[signum]);
        /* Examine current signal action */
        if (sigaction(signum, NULL, &cur_action))
            continue;
        /* Check if action installed and not modifed */
        if (!(cur_action.sa_flags & SA_SIGINFO)
                || cur_action.sa_sigaction != &kbd_cleanup_signal_action)
            continue;
        /* Restore original action */
        sigaction(signum, old_action_p, NULL);
    }
}
static void kbd_cleanup_atexit(void)
{
    /* Restore keyboard. */
    kbd_cleanup();
    /* Try to restore signal handlers in case shared library is being unloaded */
    kbd_unregister_emerg_cleanup();
}
static void kbd_register_emerg_cleanup(SDL_EVDEV_keyboard_state * kbd)
{
    int tabidx, signum;
    if (kbd_cleanup_state != NULL) {
        return;
    }
    kbd_cleanup_state = kbd;
    if (!kbd_cleanup_atexit_installed) {
        /* Since glibc 2.2.3, atexit() (and on_exit(3)) can be used within a shared library to establish
         * functions that are called when the shared library is unloaded.
         * -- man atexit(3)
         */
        atexit(kbd_cleanup_atexit);
        kbd_cleanup_atexit_installed = 1;
    }
    if (kbd_cleanup_sigactions_installed) {
        return;
    }
    kbd_cleanup_sigactions_installed = 1;
    for (tabidx = 0; tabidx < sizeof(fatal_signals) / sizeof(fatal_signals[0]); ++tabidx) {
        struct sigaction* old_action_p;
        struct sigaction new_action;
        signum = fatal_signals[tabidx];
        old_action_p = &(old_sigaction[signum]);
        if (sigaction(signum, NULL, old_action_p))
            continue;
        /* Skip SIGHUP and SIGPIPE if handler is already installed
         * - assume the handler will do the cleanup
         */
        if ((signum == SIGHUP || signum == SIGPIPE)
                && (old_action_p->sa_handler != SIG_DFL
                    || (void (*)(int))old_action_p->sa_sigaction != SIG_DFL))
            continue;
        new_action = *old_action_p;
        new_action.sa_flags |= SA_SIGINFO;
        new_action.sa_sigaction = &kbd_cleanup_signal_action;
        sigaction(signum, &new_action, NULL);
    }
}
SDL_EVDEV_keyboard_state *
SDL_EVDEV_kbd_init(void)
{
@@ -238,10 +386,20 @@
            kbd->key_maps = default_key_maps;
        }
        /* Mute the keyboard so keystrokes only generate evdev events
         * and do not leak through to the console
         */
        ioctl(kbd->console_fd, KDSKBMODE, K_OFF);
        /* Allow inhibiting keyboard mute with env. variable for debugging etc. */
        if (getenv("SDL_INPUT_LINUX_KEEP_KBD") == NULL) {
            /* Mute the keyboard so keystrokes only generate evdev events
             * and do not leak through to the console
             */
            ioctl(kbd->console_fd, KDSKBMODE, K_OFF);
            /* Make sure to restore keyboard if application fails to call
             * SDL_Quit before exit or fatal signal is raised.
             */
            if (!SDL_GetHintBoolean(SDL_HINT_NO_SIGNAL_HANDLERS, SDL_FALSE)) {
                kbd_register_emerg_cleanup(kbd);
            }
        }
    }
#ifdef DUMP_ACCENTS
@@ -259,6 +417,8 @@
    if (!kbd) {
        return;
    }
    kbd_unregister_emerg_cleanup();
    if (kbd->console_fd >= 0) {
        /* Restore the original keyboard mode */
@@ -609,7 +769,10 @@
    shift_final = (kbd->shift_state | kbd->slockstate) ^ kbd->lockstate;
    key_map = kbd->key_maps[shift_final];
    if (!key_map) {
        /* Unsupported shift state (e.g. ctrl = 4, alt = 8), just reset to the default state */
        kbd->shift_state = 0;
        kbd->slockstate = 0;
        kbd->lockstate = 0;
        return;
    }