#include "SDL_internal.h"
#include "SDL_evdev_kbd.h"
#ifdef SDL_INPUT_LINUXKD
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/kd.h>
#include <linux/keyboard.h>
#include <linux/vt.h>
#include <linux/tiocl.h>
#include <signal.h>
#include "../../events/SDL_events_c.h"
#include "SDL_evdev_kbd_default_accents.h"
#include "SDL_evdev_kbd_default_keymap.h"
#ifndef K_UNICODE
#define K_UNICODE 0x03
#endif
#ifndef K_OFF
#define K_OFF 0x04
#endif
#define K_HANDLERS \
k_self, k_fn, k_spec, k_pad, \
k_dead, k_cons, k_cur, k_shift, \
k_meta, k_ascii, k_lock, k_lowercase, \
k_slock, k_dead2, k_brl, k_ignore
typedef void(k_handler_fn)(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag);
static k_handler_fn K_HANDLERS;
static k_handler_fn *k_handler[16] = { K_HANDLERS };
typedef void(fn_handler_fn)(SDL_EVDEV_keyboard_state *kbd);
static void fn_enter(SDL_EVDEV_keyboard_state *kbd);
static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd);
static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd);
static void fn_num(SDL_EVDEV_keyboard_state *kbd);
static void fn_compose(SDL_EVDEV_keyboard_state *kbd);
static fn_handler_fn *fn_handler[] = {
NULL, fn_enter, NULL, NULL,
NULL, NULL, NULL, fn_caps_toggle,
fn_num, NULL, NULL, NULL,
NULL, fn_caps_on, fn_compose, NULL,
NULL, NULL, NULL, fn_num
};
struct SDL_EVDEV_keyboard_state
{
int console_fd;
bool muted;
int old_kbd_mode;
unsigned short **key_maps;
unsigned char shift_down[NR_SHIFT]; bool dead_key_next;
int npadch; struct kbdiacrs *accents;
unsigned int diacr;
bool rep; unsigned char lockstate;
unsigned char slockstate;
unsigned char ledflagstate;
char shift_state;
char text[128];
unsigned int text_len;
void (*vt_release_callback)(void *);
void *vt_release_callback_data;
void (*vt_acquire_callback)(void *);
void *vt_acquire_callback_data;
};
#ifdef DUMP_ACCENTS
static void SDL_EVDEV_dump_accents(SDL_EVDEV_keyboard_state *kbd)
{
unsigned int i;
printf("static struct kbdiacrs default_accents = {\n");
printf(" %d,\n", kbd->accents->kb_cnt);
printf(" {\n");
for (i = 0; i < kbd->accents->kb_cnt; ++i) {
struct kbdiacr *diacr = &kbd->accents->kbdiacr[i];
printf(" { 0x%.2x, 0x%.2x, 0x%.2x },\n",
diacr->diacr, diacr->base, diacr->result);
}
while (i < 256) {
printf(" { 0x00, 0x00, 0x00 },\n");
++i;
}
printf(" }\n");
printf("};\n");
}
#endif
#ifdef DUMP_KEYMAP
static void SDL_EVDEV_dump_keymap(SDL_EVDEV_keyboard_state *kbd)
{
int i, j;
for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
if (kbd->key_maps[i]) {
printf("static unsigned short default_key_map_%d[NR_KEYS] = {", i);
for (j = 0; j < NR_KEYS; ++j) {
if ((j % 8) == 0) {
printf("\n ");
}
printf("0x%.4x, ", kbd->key_maps[i][j]);
}
printf("\n};\n");
}
}
printf("\n");
printf("static unsigned short *default_key_maps[MAX_NR_KEYMAPS] = {\n");
for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
if (kbd->key_maps[i]) {
printf(" default_key_map_%d,\n", i);
} else {
printf(" NULL,\n");
}
}
printf("};\n");
}
#endif
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[] = {
SIGHUP, SIGQUIT, SIGILL, SIGABRT,
SIGFPE, SIGSEGV, SIGPIPE, SIGBUS,
SIGSYS
};
static void kbd_cleanup(void)
{
SDL_EVDEV_keyboard_state *kbd = kbd_cleanup_state;
if (!kbd) {
return;
}
kbd_cleanup_state = NULL;
ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
}
static void SDL_EVDEV_kbd_reraise_signal(int sig)
{
(void)raise(sig);
}
static siginfo_t *SDL_EVDEV_kdb_cleanup_siginfo = NULL;
static 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;
sigaction(signum, old_action_p, NULL);
sigemptyset(&sigset);
sigaddset(&sigset, signum);
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
SDL_EVDEV_kdb_cleanup_siginfo = info;
SDL_EVDEV_kdb_cleanup_ucontext = ucontext;
kbd_cleanup();
SDL_EVDEV_kbd_reraise_signal(signum);
}
static void kbd_unregister_emerg_cleanup(void)
{
int tabidx;
kbd_cleanup_state = NULL;
if (!kbd_cleanup_sigactions_installed) {
return;
}
kbd_cleanup_sigactions_installed = 0;
for (tabidx = 0; tabidx < SDL_arraysize(fatal_signals); ++tabidx) {
struct sigaction *old_action_p;
struct sigaction cur_action;
int signum = fatal_signals[tabidx];
old_action_p = &(old_sigaction[signum]);
if (sigaction(signum, NULL, &cur_action)) {
continue;
}
if (!(cur_action.sa_flags & SA_SIGINFO) || cur_action.sa_sigaction != &kbd_cleanup_signal_action) {
continue;
}
sigaction(signum, old_action_p, NULL);
}
}
static void kbd_cleanup_atexit(void)
{
kbd_cleanup();
kbd_unregister_emerg_cleanup();
}
static void kbd_register_emerg_cleanup(SDL_EVDEV_keyboard_state *kbd)
{
int tabidx;
if (kbd_cleanup_state) {
return;
}
kbd_cleanup_state = kbd;
if (!kbd_cleanup_atexit_installed) {
(void)atexit(kbd_cleanup_atexit);
kbd_cleanup_atexit_installed = 1;
}
if (kbd_cleanup_sigactions_installed) {
return;
}
kbd_cleanup_sigactions_installed = 1;
for (tabidx = 0; tabidx < SDL_arraysize(fatal_signals); ++tabidx) {
struct sigaction *old_action_p;
struct sigaction new_action;
int signum = fatal_signals[tabidx];
old_action_p = &(old_sigaction[signum]);
if (sigaction(signum, NULL, old_action_p)) {
continue;
}
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);
}
}
enum {
VT_SIGNAL_NONE,
VT_SIGNAL_RELEASE,
VT_SIGNAL_ACQUIRE,
};
static int vt_release_signal;
static int vt_acquire_signal;
static SDL_AtomicInt vt_signal_pending;
typedef void (*signal_handler)(int signum);
static void kbd_vt_release_signal_action(int signum)
{
SDL_SetAtomicInt(&vt_signal_pending, VT_SIGNAL_RELEASE);
}
static void kbd_vt_acquire_signal_action(int signum)
{
SDL_SetAtomicInt(&vt_signal_pending, VT_SIGNAL_ACQUIRE);
}
static bool setup_vt_signal(int signum, signal_handler handler)
{
struct sigaction *old_action_p;
struct sigaction new_action;
old_action_p = &(old_sigaction[signum]);
SDL_zero(new_action);
new_action.sa_handler = handler;
new_action.sa_flags = SA_RESTART;
if (sigaction(signum, &new_action, old_action_p) < 0) {
return false;
}
if (old_action_p->sa_handler != SIG_DFL) {
sigaction(signum, old_action_p, NULL);
return false;
}
return true;
}
static int find_free_signal(signal_handler handler)
{
#ifdef SIGRTMIN
int i;
for (i = SIGRTMIN + 2; i <= SIGRTMAX; ++i) {
if (setup_vt_signal(i, handler)) {
return i;
}
}
#endif
if (setup_vt_signal(SIGUSR1, handler)) {
return SIGUSR1;
}
if (setup_vt_signal(SIGUSR2, handler)) {
return SIGUSR2;
}
return 0;
}
static void kbd_vt_quit(int console_fd)
{
struct vt_mode mode;
if (vt_release_signal) {
sigaction(vt_release_signal, &old_sigaction[vt_release_signal], NULL);
vt_release_signal = 0;
}
if (vt_acquire_signal) {
sigaction(vt_acquire_signal, &old_sigaction[vt_acquire_signal], NULL);
vt_acquire_signal = 0;
}
SDL_zero(mode);
mode.mode = VT_AUTO;
ioctl(console_fd, VT_SETMODE, &mode);
}
static bool kbd_vt_init(int console_fd)
{
struct vt_mode mode;
vt_release_signal = find_free_signal(kbd_vt_release_signal_action);
vt_acquire_signal = find_free_signal(kbd_vt_acquire_signal_action);
if (!vt_release_signal || !vt_acquire_signal ) {
kbd_vt_quit(console_fd);
return false;
}
SDL_zero(mode);
mode.mode = VT_PROCESS;
mode.relsig = vt_release_signal;
mode.acqsig = vt_acquire_signal;
mode.frsig = SIGIO;
if (ioctl(console_fd, VT_SETMODE, &mode) < 0) {
kbd_vt_quit(console_fd);
return false;
}
return true;
}
static void kbd_vt_update(SDL_EVDEV_keyboard_state *state)
{
int signal_pending = SDL_GetAtomicInt(&vt_signal_pending);
if (signal_pending != VT_SIGNAL_NONE) {
if (signal_pending == VT_SIGNAL_RELEASE) {
if (state->vt_release_callback) {
state->vt_release_callback(state->vt_release_callback_data);
}
ioctl(state->console_fd, VT_RELDISP, 1);
} else {
if (state->vt_acquire_callback) {
state->vt_acquire_callback(state->vt_acquire_callback_data);
}
ioctl(state->console_fd, VT_RELDISP, VT_ACKACQ);
}
SDL_CompareAndSwapAtomicInt(&vt_signal_pending, signal_pending, VT_SIGNAL_NONE);
}
}
SDL_EVDEV_keyboard_state *SDL_EVDEV_kbd_init(void)
{
SDL_EVDEV_keyboard_state *kbd;
char flag_state;
char kbtype;
char shift_state[sizeof(long)] = { TIOCL_GETSHIFTSTATE, 0 };
kbd = (SDL_EVDEV_keyboard_state *)SDL_calloc(1, sizeof(*kbd));
if (!kbd) {
return NULL;
}
kbd->console_fd = open("/dev/tty", O_RDONLY | O_CLOEXEC);
if (!((ioctl(kbd->console_fd, KDGKBTYPE, &kbtype) == 0) && ((kbtype == KB_101) || (kbtype == KB_84)))) {
close(kbd->console_fd);
kbd->console_fd = -1;
}
kbd->npadch = -1;
if (ioctl(kbd->console_fd, TIOCLINUX, shift_state) == 0) {
kbd->shift_state = *shift_state;
}
if (ioctl(kbd->console_fd, KDGKBLED, &flag_state) == 0) {
kbd->ledflagstate = flag_state;
}
kbd->accents = &default_accents;
kbd->key_maps = default_key_maps;
if (ioctl(kbd->console_fd, KDGKBMODE, &kbd->old_kbd_mode) == 0) {
ioctl(kbd->console_fd, KDSKBMODE, K_UNICODE);
}
kbd_vt_init(kbd->console_fd);
return kbd;
}
void SDL_EVDEV_kbd_set_muted(SDL_EVDEV_keyboard_state *state, bool muted)
{
if (!state) {
return;
}
if (muted == state->muted) {
return;
}
if (muted) {
if (SDL_GetHintBoolean(SDL_HINT_MUTE_CONSOLE_KEYBOARD, true)) {
ioctl(state->console_fd, KDSKBMODE, K_OFF);
if (!SDL_GetHintBoolean(SDL_HINT_NO_SIGNAL_HANDLERS, false)) {
kbd_register_emerg_cleanup(state);
}
}
} else {
kbd_unregister_emerg_cleanup();
ioctl(state->console_fd, KDSKBMODE, state->old_kbd_mode);
}
state->muted = muted;
}
void 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)
{
if (state == NULL) {
return;
}
state->vt_release_callback = release_callback;
state->vt_release_callback_data = release_callback_data;
state->vt_acquire_callback = acquire_callback;
state->vt_acquire_callback_data = acquire_callback_data;
}
void SDL_EVDEV_kbd_update(SDL_EVDEV_keyboard_state *state)
{
if (!state) {
return;
}
kbd_vt_update(state);
}
void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state)
{
if (state == NULL) {
return;
}
SDL_EVDEV_kbd_set_muted(state, false);
kbd_vt_quit(state->console_fd);
if (state->console_fd >= 0) {
close(state->console_fd);
state->console_fd = -1;
}
if (state->key_maps && state->key_maps != default_key_maps) {
int i;
for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
SDL_free(state->key_maps[i]);
}
SDL_free(state->key_maps);
}
SDL_free(state);
}
static void put_queue(SDL_EVDEV_keyboard_state *kbd, uint c)
{
if (kbd->text_len < (sizeof(kbd->text) - 1)) {
kbd->text[kbd->text_len++] = (char)c;
}
}
static void put_utf8(SDL_EVDEV_keyboard_state *kbd, uint c)
{
if (c < 0x80) {
put_queue(kbd, c);
} else if (c < 0x800) {
put_queue(kbd, 0xc0 | (c >> 6));
put_queue(kbd, 0x80 | (c & 0x3f));
} else if (c < 0x10000) {
if (c >= 0xD800 && c < 0xE000) {
return;
}
if (c == 0xFFFF) {
return;
}
put_queue(kbd, 0xe0 | (c >> 12));
put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
put_queue(kbd, 0x80 | (c & 0x3f));
} else if (c < 0x110000) {
put_queue(kbd, 0xf0 | (c >> 18));
put_queue(kbd, 0x80 | ((c >> 12) & 0x3f));
put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
put_queue(kbd, 0x80 | (c & 0x3f));
}
}
static unsigned int handle_diacr(SDL_EVDEV_keyboard_state *kbd, unsigned int ch)
{
unsigned int d = kbd->diacr;
unsigned int i;
kbd->diacr = 0;
if (kbd->console_fd >= 0)
if (ioctl(kbd->console_fd, KDGKBDIACR, kbd->accents) < 0) {
}
for (i = 0; i < kbd->accents->kb_cnt; i++) {
if (kbd->accents->kbdiacr[i].diacr == d &&
kbd->accents->kbdiacr[i].base == ch) {
return kbd->accents->kbdiacr[i].result;
}
}
if (ch == ' ' || ch == d) {
return d;
}
put_utf8(kbd, d);
return ch;
}
static bool vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
return (kbd->ledflagstate & flag) != 0;
}
static void set_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
kbd->ledflagstate |= flag;
ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate));
}
static void clr_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
kbd->ledflagstate &= ~flag;
ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate));
}
static void chg_vc_kbd_lock(SDL_EVDEV_keyboard_state *kbd, int flag)
{
kbd->lockstate ^= 1 << flag;
}
static void chg_vc_kbd_slock(SDL_EVDEV_keyboard_state *kbd, int flag)
{
kbd->slockstate ^= 1 << flag;
}
static void chg_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
kbd->ledflagstate ^= flag;
ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate));
}
static void fn_enter(SDL_EVDEV_keyboard_state *kbd)
{
if (kbd->diacr) {
put_utf8(kbd, kbd->diacr);
kbd->diacr = 0;
}
}
static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd)
{
if (kbd->rep) {
return;
}
chg_vc_kbd_led(kbd, K_CAPSLOCK);
}
static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd)
{
if (kbd->rep) {
return;
}
set_vc_kbd_led(kbd, K_CAPSLOCK);
}
static void fn_num(SDL_EVDEV_keyboard_state *kbd)
{
if (!kbd->rep) {
chg_vc_kbd_led(kbd, K_NUMLOCK);
}
}
static void fn_compose(SDL_EVDEV_keyboard_state *kbd)
{
kbd->dead_key_next = true;
}
static void k_ignore(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
}
static void k_spec(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
if (up_flag) {
return;
}
if (value >= SDL_arraysize(fn_handler)) {
return;
}
if (fn_handler[value]) {
fn_handler[value](kbd);
}
}
static void k_lowercase(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
}
static void k_self(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
if (up_flag) {
return; }
if (kbd->diacr) {
value = handle_diacr(kbd, value);
}
if (kbd->dead_key_next) {
kbd->dead_key_next = false;
kbd->diacr = value;
return;
}
put_utf8(kbd, value);
}
static void k_deadunicode(SDL_EVDEV_keyboard_state *kbd, unsigned int value, char up_flag)
{
if (up_flag) {
return;
}
kbd->diacr = (kbd->diacr ? handle_diacr(kbd, value) : value);
}
static void k_dead(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
const unsigned char ret_diacr[NR_DEAD] = { '`', '\'', '^', '~', '"', ',' };
k_deadunicode(kbd, ret_diacr[value], up_flag);
}
static void k_dead2(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
k_deadunicode(kbd, value, up_flag);
}
static void k_cons(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
}
static void k_fn(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
}
static void k_cur(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
}
static void k_pad(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
static const char pad_chars[] = "0123456789+-*/\015,.?()#";
if (up_flag) {
return; }
if (!vc_kbd_led(kbd, K_NUMLOCK)) {
return;
}
put_queue(kbd, pad_chars[value]);
}
static void k_shift(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
int old_state = kbd->shift_state;
if (kbd->rep) {
return;
}
if (value == KVAL(K_CAPSSHIFT)) {
value = KVAL(K_SHIFT);
if (!up_flag) {
clr_vc_kbd_led(kbd, K_CAPSLOCK);
}
}
if (up_flag) {
if (kbd->shift_down[value]) {
kbd->shift_down[value]--;
}
} else {
kbd->shift_down[value]++;
}
if (kbd->shift_down[value]) {
kbd->shift_state |= (1 << value);
} else {
kbd->shift_state &= ~(1 << value);
}
if (up_flag && kbd->shift_state != old_state && kbd->npadch != -1) {
put_utf8(kbd, kbd->npadch);
kbd->npadch = -1;
}
}
static void k_meta(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
}
static void k_ascii(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
int base;
if (up_flag) {
return;
}
if (value < 10) {
base = 10;
} else {
value -= 10;
base = 16;
}
if (kbd->npadch == -1) {
kbd->npadch = value;
} else {
kbd->npadch = kbd->npadch * base + value;
}
}
static void k_lock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
if (up_flag || kbd->rep) {
return;
}
chg_vc_kbd_lock(kbd, value);
}
static void k_slock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
k_shift(kbd, value, up_flag);
if (up_flag || kbd->rep) {
return;
}
chg_vc_kbd_slock(kbd, value);
if (!kbd->key_maps[kbd->lockstate ^ kbd->slockstate]) {
kbd->slockstate = 0;
chg_vc_kbd_slock(kbd, value);
}
}
static void k_brl(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
}
void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down)
{
unsigned char shift_final;
unsigned char type;
unsigned short *key_map;
unsigned short keysym;
if (!state) {
return;
}
state->rep = (down == 2);
shift_final = (state->shift_state | state->slockstate) ^ state->lockstate;
key_map = state->key_maps[shift_final];
if (!key_map) {
state->shift_state = 0;
state->slockstate = 0;
state->lockstate = 0;
return;
}
if (keycode < NR_KEYS) {
if (state->console_fd < 0) {
keysym = key_map[keycode];
} else {
struct kbentry kbe;
kbe.kb_table = shift_final;
kbe.kb_index = keycode;
if (ioctl(state->console_fd, KDGKBENT, &kbe) == 0)
keysym = (kbe.kb_value ^ 0xf000);
else
return;
}
} else {
return;
}
type = KTYP(keysym);
if (type < 0xf0) {
if (down) {
put_utf8(state, keysym);
}
} else {
type -= 0xf0;
if (type == KT_LETTER) {
type = KT_LATIN;
if (vc_kbd_led(state, K_CAPSLOCK)) {
shift_final = shift_final ^ (1 << KG_SHIFT);
key_map = state->key_maps[shift_final];
if (key_map) {
if (state->console_fd < 0) {
keysym = key_map[keycode];
} else {
struct kbentry kbe;
kbe.kb_table = shift_final;
kbe.kb_index = keycode;
if (ioctl(state->console_fd, KDGKBENT, &kbe) == 0)
keysym = (kbe.kb_value ^ 0xf000);
}
}
}
}
(*k_handler[type])(state, keysym & 0xff, !down);
if (type != KT_SLOCK) {
state->slockstate = 0;
}
}
if (state->text_len > 0) {
state->text[state->text_len] = '\0';
SDL_SendKeyboardText(state->text);
state->text_len = 0;
}
}
#elif !defined(SDL_INPUT_FBSDKBIO)
SDL_EVDEV_keyboard_state *SDL_EVDEV_kbd_init(void)
{
return NULL;
}
void SDL_EVDEV_kbd_set_muted(SDL_EVDEV_keyboard_state *state, bool muted)
{
}
void 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)
{
}
void SDL_EVDEV_kbd_update(SDL_EVDEV_keyboard_state *state)
{
}
void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down)
{
}
void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state)
{
}
#endif