Fixed bug 5346 - Add FreeBSD evdev KBIO keyboard input driver

wahil1976

This patch adds the KBIO text input driver for FreeBSD, which allows text input to fully work without text spilling out into the console. It also supports accented input, AltGr keys and Alt Lock combinations.

Tested with US accent keys layout and various AltGr layouts.
This commit is contained in:
Sam Lantinga 2020-11-11 19:37:47 -08:00
parent 38ed8a955a
commit 1822f97e5f
6 changed files with 808 additions and 1 deletions

43
configure vendored
View File

@ -22799,6 +22799,45 @@ $as_echo "#define SDL_INPUT_LINUXKD 1" >>confdefs.h
fi
}
CheckInputKBIO()
{
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for FreeBSD kbio.h" >&5
$as_echo_n "checking for FreeBSD kbio.h... " >&6; }
use_input_kbio=no
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/kbio.h>
#include <sys/ioctl.h>
int
main ()
{
accentmap_t accTable;
ioctl(0, KDENABIO, 1);
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
use_input_kbio=yes
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $use_input_kbio" >&5
$as_echo "$use_input_kbio" >&6; }
if test x$use_input_kbio = xyes; then
$as_echo "#define SDL_INPUT_FBSDKBIO 1" >>confdefs.h
SUMMARY_input="${SUMMARY_input} fbsdkbio"
fi
}
CheckLibUDev()
{
# Check whether --enable-libudev was given.
@ -24676,6 +24715,9 @@ case "$host" in
linux)
CheckInputKD
;;
freebsd)
CheckInputKBIO
;;
esac
CheckTslib
CheckUSBHID
@ -24840,6 +24882,7 @@ $as_echo "#define SDL_TIMER_UNIX 1" >>confdefs.h
if test x$use_input_events = xyes; then
SOURCES="$SOURCES $srcdir/src/core/linux/SDL_evdev.c"
SOURCES="$SOURCES $srcdir/src/core/linux/SDL_evdev_kbd.c"
SOURCES="$SOURCES $srcdir/src/core/freebsd/SDL_evdev_kbd_freebsd.c"
fi
# Set up other core UNIX files
SOURCES="$SOURCES $srcdir/src/core/linux/SDL_evdev_capabilities.c"

View File

@ -2643,6 +2643,28 @@ CheckInputKD()
fi
}
dnl See if we can use the FreeBSD kernel kbio.h header
CheckInputKBIO()
{
AC_MSG_CHECKING(for FreeBSD kbio.h)
use_input_kbio=no
AC_TRY_COMPILE([
#include <sys/kbio.h>
#include <sys/ioctl.h>
],[
accentmap_t accTable;
ioctl(0, KDENABIO, 1);
],[
use_input_kbio=yes
])
AC_MSG_RESULT($use_input_kbio)
if test x$use_input_kbio = xyes; then
AC_DEFINE(SDL_INPUT_FBSDKBIO, 1, [ ])
SUMMARY_input="${SUMMARY_input} fbsdkbio"
fi
}
dnl See if the platform offers libudev for device enumeration and hotplugging.
CheckLibUDev()
{
@ -3524,6 +3546,9 @@ case "$host" in
linux)
CheckInputKD
;;
freebsd)
CheckInputKBIO
;;
esac
CheckTslib
CheckUSBHID
@ -3660,6 +3685,7 @@ case "$host" in
if test x$use_input_events = xyes; then
SOURCES="$SOURCES $srcdir/src/core/linux/SDL_evdev.c"
SOURCES="$SOURCES $srcdir/src/core/linux/SDL_evdev_kbd.c"
SOURCES="$SOURCES $srcdir/src/core/freebsd/SDL_evdev_kbd_freebsd.c"
fi
# Set up other core UNIX files
SOURCES="$SOURCES $srcdir/src/core/linux/SDL_evdev_capabilities.c"

View File

@ -279,6 +279,7 @@
/* Enable various input drivers */
#undef SDL_INPUT_LINUXEV
#undef SDL_INPUT_FBSDKBIO
#undef SDL_INPUT_LINUXKD
#undef SDL_INPUT_TSLIB
#undef SDL_JOYSTICK_HAIKU

View File

@ -0,0 +1,165 @@
#include <sys/kbio.h>
/*
* Automatically generated from /usr/share/vt/keymaps/us.acc.kbd.
* DO NOT EDIT!
*/
static keymap_t keymap_default_us_acc = { 0x6d, {
/* alt
* scan cntrl alt alt cntrl
* code base shift cntrl shift alt shift cntrl shift spcl flgs
* ---------------------------------------------------------------------------
*/
/*00*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 },
/*01*/{{ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, DBG, }, 0x03,0x00 },
/*02*/{{ '1', '!', NOP, NOP, '1', '!', NOP, NOP, }, 0x33,0x00 },
/*03*/{{ '2', '@', 0x00, 0x00, '2', '@', 0x00, 0x00, }, 0x00,0x00 },
/*04*/{{ '3', '#', NOP, NOP, '3', '#', NOP, NOP, }, 0x33,0x00 },
/*05*/{{ '4', '$', NOP, NOP, '4', '$', NOP, NOP, }, 0x33,0x00 },
/*06*/{{ '5', '%', NOP, NOP, '5', '%', NOP, NOP, }, 0x33,0x00 },
/*07*/{{ '6', '^', 0x1E, 0x1E, '6', DCIR, 0x1E, 0x1E, }, 0x04,0x00 },
/*08*/{{ '7', '&', NOP, NOP, '7', '&', NOP, NOP, }, 0x33,0x00 },
/*09*/{{ '8', '*', NOP, NOP, '8', DRIN, NOP, NOP, }, 0x37,0x00 },
/*0a*/{{ '9', '(', NOP, NOP, '9', '(', NOP, NOP, }, 0x33,0x00 },
/*0b*/{{ '0', ')', NOP, NOP, '0', ')', NOP, NOP, }, 0x33,0x00 },
/*0c*/{{ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, }, 0x00,0x00 },
/*0d*/{{ '=', '+', NOP, NOP, '=', '+', NOP, NOP, }, 0x33,0x00 },
/*0e*/{{ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, }, 0x00,0x00 },
/*0f*/{{ 0x09, BTAB, NEXT, NEXT, 0x09, BTAB, NOP, NOP, }, 0x77,0x00 },
/*10*/{{ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, }, 0x00,0x01 },
/*11*/{{ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, }, 0x00,0x01 },
/*12*/{{ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, }, 0x00,0x01 },
/*13*/{{ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, }, 0x00,0x01 },
/*14*/{{ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, }, 0x00,0x01 },
/*15*/{{ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, }, 0x00,0x01 },
/*16*/{{ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, }, 0x00,0x01 },
/*17*/{{ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, }, 0x00,0x01 },
/*18*/{{ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, }, 0x00,0x01 },
/*19*/{{ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, }, 0x00,0x01 },
/*1a*/{{ '[', '{', 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, }, 0x00,0x00 },
/*1b*/{{ ']', '}', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, }, 0x00,0x00 },
/*1c*/{{ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, }, 0x00,0x00 },
/*1d*/{{ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, }, 0xFF,0x00 },
/*1e*/{{ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, }, 0x00,0x01 },
/*1f*/{{ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, }, 0x00,0x01 },
/*20*/{{ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, }, 0x00,0x01 },
/*21*/{{ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, }, 0x00,0x01 },
/*22*/{{ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, }, 0x00,0x01 },
/*23*/{{ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, }, 0x00,0x01 },
/*24*/{{ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, }, 0x00,0x01 },
/*25*/{{ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, }, 0x00,0x01 },
/*26*/{{ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, }, 0x00,0x01 },
/*27*/{{ ';', ':', NOP, NOP, ';', ':', NOP, NOP, }, 0x33,0x00 },
/*28*/{{ '\'', '"', NOP, NOP, DACU, DUML, NOP, NOP, }, 0x3F,0x00 },
/*29*/{{ '`', '~', NOP, NOP, DGRA, DTIL, NOP, NOP, }, 0x3F,0x00 },
/*2a*/{{ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, }, 0xFF,0x00 },
/*2b*/{{ '\\', '|', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, }, 0x00,0x00 },
/*2c*/{{ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, }, 0x00,0x01 },
/*2d*/{{ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, }, 0x00,0x01 },
/*2e*/{{ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, }, 0x00,0x01 },
/*2f*/{{ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, }, 0x00,0x01 },
/*30*/{{ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, }, 0x00,0x01 },
/*31*/{{ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, }, 0x00,0x01 },
/*32*/{{ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, }, 0x00,0x01 },
/*33*/{{ ',', '<', NOP, NOP, DCED, '<', NOP, NOP, }, 0x3B,0x00 },
/*34*/{{ '.', '>', NOP, NOP, '.', '>', NOP, NOP, }, 0x33,0x00 },
/*35*/{{ '/', '?', NOP, NOP, '/', '?', NOP, NOP, }, 0x33,0x00 },
/*36*/{{ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, }, 0xFF,0x00 },
/*37*/{{ '*', '*', '*', '*', '*', '*', '*', '*', }, 0x00,0x00 },
/*38*/{{ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, }, 0xFF,0x00 },
/*39*/{{ ' ', ' ', 0x00, 0x00, ' ', ' ', SUSP, SUSP, }, 0x03,0x00 },
/*3a*/{{ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, }, 0xFF,0x00 },
/*3b*/{{ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11),}, 0xFF,0x00 },
/*3c*/{{ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12),}, 0xFF,0x00 },
/*3d*/{{ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13),}, 0xFF,0x00 },
/*3e*/{{ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14),}, 0xFF,0x00 },
/*3f*/{{ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15),}, 0xFF,0x00 },
/*40*/{{ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16),}, 0xFF,0x00 },
/*41*/{{ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7),}, 0xFF,0x00 },
/*42*/{{ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8),}, 0xFF,0x00 },
/*43*/{{ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9),}, 0xFF,0x00 },
/*44*/{{ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10),}, 0xFF,0x00 },
/*45*/{{ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, }, 0xFF,0x00 },
/*46*/{{ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, }, 0xFF,0x00 },
/*47*/{{ F(49), '7', '7', '7', '7', '7', '7', '7', }, 0x80,0x02 },
/*48*/{{ F(50), '8', '8', '8', '8', '8', '8', '8', }, 0x80,0x02 },
/*49*/{{ F(51), '9', '9', '9', '9', '9', '9', '9', }, 0x80,0x02 },
/*4a*/{{ F(52), '-', '-', '-', '-', '-', '-', '-', }, 0x80,0x02 },
/*4b*/{{ F(53), '4', '4', '4', '4', '4', '4', '4', }, 0x80,0x02 },
/*4c*/{{ F(54), '5', '5', '5', '5', '5', '5', '5', }, 0x80,0x02 },
/*4d*/{{ F(55), '6', '6', '6', '6', '6', '6', '6', }, 0x80,0x02 },
/*4e*/{{ F(56), '+', '+', '+', '+', '+', '+', '+', }, 0x80,0x02 },
/*4f*/{{ F(57), '1', '1', '1', '1', '1', '1', '1', }, 0x80,0x02 },
/*50*/{{ F(58), '2', '2', '2', '2', '2', '2', '2', }, 0x80,0x02 },
/*51*/{{ F(59), '3', '3', '3', '3', '3', '3', '3', }, 0x80,0x02 },
/*52*/{{ F(60), '0', '0', '0', '0', '0', '0', '0', }, 0x80,0x02 },
/*53*/{{ 0x7F, '.', '.', '.', '.', '.', RBT, RBT, }, 0x03,0x02 },
/*54*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 },
/*55*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 },
/*56*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 },
/*57*/{{ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11),}, 0xFF,0x00 },
/*58*/{{ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12),}, 0xFF,0x00 },
/*59*/{{ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, }, 0x00,0x00 },
/*5a*/{{ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, }, 0xFF,0x00 },
/*5b*/{{ '/', '/', '/', '/', '/', '/', '/', '/', }, 0x00,0x02 },
/*5c*/{{ NEXT, NEXT, NOP, NOP, DBG, DBG, DBG, DBG, }, 0xFF,0x00 },
/*5d*/{{ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, }, 0xFF,0x00 },
/*5e*/{{ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49),}, 0xFF,0x00 },
/*5f*/{{ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50),}, 0xFF,0x00 },
/*60*/{{ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51),}, 0xFF,0x00 },
/*61*/{{ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53),}, 0xFF,0x00 },
/*62*/{{ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55),}, 0xFF,0x00 },
/*63*/{{ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57),}, 0xFF,0x00 },
/*64*/{{ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58),}, 0xFF,0x00 },
/*65*/{{ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59),}, 0xFF,0x00 },
/*66*/{{ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60),}, 0xFF,0x00 },
/*67*/{{ F(61), F(61), F(61), F(61), F(61), F(61), RBT, F(61),}, 0xFF,0x00 },
/*68*/{{ SPSC, SPSC, SUSP, SUSP, NOP, NOP, SUSP, SUSP, }, 0xFF,0x00 },
/*69*/{{ F(62), F(62), F(62), F(62), F(62), F(62), F(62), F(62),}, 0xFF,0x00 },
/*6a*/{{ F(63), F(63), F(63), F(63), F(63), F(63), F(63), F(63),}, 0xFF,0x00 },
/*6b*/{{ F(64), F(64), F(64), F(64), F(64), F(64), F(64), F(64),}, 0xFF,0x00 },
/*6c*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 },
} };
static accentmap_t accentmap_default_us_acc = { 11, {
/* dgra=0 */
{ '`', { { 'a',0xe0 }, { 'A',0xc0 }, { 'e',0xe8 }, { 'E',0xc8 },
{ 'i',0xec }, { 'I',0xcc }, { 'o',0xf2 }, { 'O',0xd2 },
{ 'u',0xf9 }, { 'U',0xd9 }, }, },
/* dacu=1 */
{ 0xb4, { { 'a',0xe1 }, { 'A',0xc1 }, { 'e',0xe9 }, { 'E',0xc9 },
{ 'i',0xed }, { 'I',0xcd }, { 'o',0xf3 }, { 'O',0xd3 },
{ 'u',0xfa }, { 'U',0xda }, { 'y',0xfd }, { 'Y',0xdd }, }, },
/* dcir=2 */
{ '^', { { 'a',0xe2 }, { 'A',0xc2 }, { 'e',0xea }, { 'E',0xca },
{ 'i',0xee }, { 'I',0xce }, { 'o',0xf4 }, { 'O',0xd4 },
{ 'u',0xfb }, { 'U',0xdb }, }, },
/* dtil=3 */
{ '~', { { 'a',0xe3 }, { 'A',0xc3 }, { 'n',0xf1 }, { 'N',0xd1 },
{ 'o',0xf5 }, { 'O',0xd5 }, }, },
/* dmac=4 */
{ 0x00 },
/* dbre=5 */
{ 0x00 },
/* ddot=6 */
{ 0x00 },
/* duml=7 */
{ 0xa8, { { 'a',0xe4 }, { 'A',0xc4 }, { 'e',0xeb }, { 'E',0xcb },
{ 'i',0xef }, { 'I',0xcf }, { 'o',0xf6 }, { 'O',0xd6 },
{ 'u',0xfc }, { 'U',0xdc }, { 'y',0xff }, }, },
/* dsla=8 */
{ 0x00 },
/* drin=9 */
{ 0xb0, { { 'a',0xe5 }, { 'A',0xc5 }, }, },
/* dced=10 */
{ 0xb8, { { 'c',0xe7 }, { 'C',0xc7 }, }, },
/* dapo=11 */
{ 0x00 },
/* ddac=12 */
{ 0x00 },
/* dogo=13 */
{ 0x00 },
/* dcar=14 */
{ 0x00 },
} };

View File

@ -0,0 +1,572 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#include "../linux/SDL_evdev_kbd.h"
#include "SDL_hints.h"
#ifdef SDL_INPUT_FBSDKBIO
/* This logic is adapted from drivers/tty/vt/keyboard.c in the Linux kernel source, slightly modified to work with FreeBSD */
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/kbio.h>
#include <sys/consio.h>
#include <signal.h>
#include "../../events/SDL_events_c.h"
#include "SDL_evdev_kbd_default_keyaccmap.h"
typedef void (fn_handler_fn)(SDL_EVDEV_keyboard_state *kbd);
/*
* Keyboard State
*/
struct SDL_EVDEV_keyboard_state
{
int console_fd;
int keyboard_fd;
unsigned long old_kbd_mode;
unsigned short **key_maps;
keymap_t* key_map;
keyboard_info_t* kbInfo;
unsigned char shift_down[4]; /* shift state counters.. */
SDL_bool dead_key_next;
int npadch; /* -1 or number assembled on pad */
accentmap_t *accents;
unsigned int diacr;
SDL_bool rep; /* flag telling character repeat */
unsigned char lockstate;
unsigned char ledflagstate;
char shift_state;
char text[128];
unsigned int text_len;
};
static int SDL_EVDEV_kbd_load_keymaps(SDL_EVDEV_keyboard_state *kbd)
{
return (ioctl(kbd->keyboard_fd, GIO_KEYMAP, kbd->key_map) >= 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;
ioctl(kbd->keyboard_fd, KDSKBMODE, kbd->old_kbd_mode);
if (kbd->keyboard_fd != kbd->console_fd) close(kbd->keyboard_fd);
ioctl(kbd->console_fd, CONS_SETKBD, (unsigned long)(kbd->kbInfo->kb_index));
}
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)
{
SDL_EVDEV_keyboard_state *kbd;
char flag_state;
char* devicePath;
kbd = (SDL_EVDEV_keyboard_state *)SDL_calloc(1, sizeof(SDL_EVDEV_keyboard_state));
if (!kbd) {
return NULL;
}
kbd->npadch = -1;
/* This might fail if we're not connected to a tty (e.g. on the Steam Link) */
kbd->keyboard_fd = kbd->console_fd = open("/dev/tty", O_RDONLY);
kbd->shift_state = 0;
kbd->accents = SDL_calloc(sizeof(accentmap_t), 1);
kbd->key_map = SDL_calloc(sizeof(keymap_t), 1);
kbd->kbInfo = SDL_calloc(sizeof(keyboard_info_t), 1);
ioctl(kbd->console_fd, KDGKBINFO, kbd->kbInfo);
if (ioctl(kbd->console_fd, KDGKBSTATE, &flag_state) == 0) {
kbd->ledflagstate = flag_state;
}
if (ioctl(kbd->console_fd, GIO_DEADKEYMAP, kbd->accents) < 0)
{
SDL_free(kbd->accents);
kbd->accents = &accentmap_default_us_acc;
}
if (ioctl(kbd->console_fd, KDGKBMODE, &kbd->old_kbd_mode) == 0) {
/* Set the keyboard in XLATE mode and load the keymaps */
ioctl(kbd->console_fd, KDSKBMODE, (unsigned long)(K_XLATE));
if(!SDL_EVDEV_kbd_load_keymaps(kbd))
{
SDL_free(kbd->key_map);
kbd->key_map = &keymap_default_us_acc;
}
/* Allow inhibiting keyboard mute with env. variable for debugging etc. */
if (getenv("SDL_INPUT_FREEBSD_KEEP_KBD") == NULL) {
/* Take keyboard from console and open the actual keyboard device.
* Ensures that the keystrokes do not leak through to the console.
*/
ioctl(kbd->console_fd, CONS_RELKBD, 1ul);
asprintf(&devicePath, "/dev/kbd%d", kbd->kbInfo->kb_index);
kbd->keyboard_fd = open(devicePath, O_WRONLY);
if (kbd->keyboard_fd == -1)
{
// Give keyboard back.
ioctl(kbd->console_fd, CONS_SETKBD, (unsigned long)(kbd->kbInfo->kb_index));
kbd->keyboard_fd = kbd->console_fd;
}
/* 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);
}
free(devicePath);
}
else kbd->keyboard_fd = kbd->console_fd;
}
return kbd;
}
void
SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *kbd)
{
if (!kbd) {
return;
}
kbd_unregister_emerg_cleanup();
if (kbd->keyboard_fd >= 0) {
/* Restore the original keyboard mode */
ioctl(kbd->keyboard_fd, KDSKBMODE, kbd->old_kbd_mode);
close(kbd->keyboard_fd);
if (kbd->console_fd != kbd->keyboard_fd && kbd->console_fd >= 0)
{
// Give back keyboard.
ioctl(kbd->console_fd, CONS_SETKBD, (unsigned long)(kbd->kbInfo->kb_index));
}
kbd->console_fd = kbd->keyboard_fd = -1;
}
SDL_free(kbd);
}
/*
* Helper Functions.
*/
static void put_queue(SDL_EVDEV_keyboard_state *kbd, uint c)
{
/* c is already part of a UTF-8 sequence and safe to add as a character */
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)
/* 0******* */
put_queue(kbd, c);
else if (c < 0x800) {
/* 110***** 10****** */
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;
/* 1110**** 10****** 10****** */
put_queue(kbd, 0xe0 | (c >> 12));
put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
put_queue(kbd, 0x80 | (c & 0x3f));
} else if (c < 0x110000) {
/* 11110*** 10****** 10****** 10****** */
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));
}
}
/*
* We have a combining character DIACR here, followed by the character CH.
* If the combination occurs in the table, return the corresponding value.
* Otherwise, if CH is a space or equals DIACR, return DIACR.
* Otherwise, conclude that DIACR was not combining after all,
* queue it and return CH.
*/
static unsigned int handle_diacr(SDL_EVDEV_keyboard_state *kbd, unsigned int ch)
{
unsigned int d = kbd->diacr;
unsigned int i;
kbd->diacr = 0;
for (i = 0; i < kbd->accents->n_accs; i++) {
if (kbd->accents->acc[i].accchar == d)
{
for (int j = 0; j < NUM_ACCENTCHARS; ++j) {
if (kbd->accents->acc[i].map[j][0] == 0) /* end of table */
break;
if (kbd->accents->acc[i].map[j][0] == ch)
return kbd->accents->acc[i].map[j][1];
}
}
}
if (ch == ' ' || ch == d) {
put_utf8(kbd, d);
return 0;
}
put_utf8(kbd, d);
return ch;
}
static int vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
return (kbd->ledflagstate & flag) != 0;
}
static void chg_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
kbd->ledflagstate ^= flag;
ioctl(kbd->keyboard_fd, KDSKBSTATE, (unsigned long)(kbd->ledflagstate));
}
/*
* Special function handlers
*/
static void k_self(SDL_EVDEV_keyboard_state *kbd, unsigned int value, char up_flag)
{
if (up_flag)
return; /* no action, if this is a key release */
if (kbd->diacr)
value = handle_diacr(kbd, value);
if (kbd->dead_key_next) {
kbd->dead_key_next = SDL_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_shift(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
int old_state = kbd->shift_state;
if (kbd->rep)
return;
if (up_flag) {
/*
* handle the case that two shift or control
* keys are depressed simultaneously
*/
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);
/* kludge */
if (up_flag && kbd->shift_state != old_state && kbd->npadch != -1) {
put_utf8(kbd, kbd->npadch);
kbd->npadch = -1;
}
}
void
SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode, int down)
{
keymap_t key_map;
struct keyent_t keysym;
unsigned int final_key_state;
unsigned int map_from_key_sym;
key_map = *kbd->key_map;
if (!kbd) {
return;
}
kbd->rep = (down == 2);
if (keycode < NUM_KEYS) {
if (keycode >= 89 && keycode <= 95) {
/* These constitute unprintable language-related keys, so ignore them. */
return;
}
if (keycode > 95)
keycode -= 7;
if (vc_kbd_led(kbd, ALKED) || (kbd->shift_state & 0x8))
{
keycode += ALTGR_OFFSET;
}
keysym = key_map.key[keycode];
} else {
return;
}
final_key_state = kbd->shift_state & 0x7;
if ((keysym.flgs & FLAG_LOCK_C) && vc_kbd_led(kbd, LED_CAP))
final_key_state ^= 0x1;
if ((keysym.flgs & FLAG_LOCK_N) && vc_kbd_led(kbd, LED_NUM))
final_key_state ^= 0x1;
map_from_key_sym = keysym.map[final_key_state];
if ((keysym.spcl & (0x80 >> final_key_state)) || (map_from_key_sym & SPCLKEY)) {
/* Special function.*/
if (map_from_key_sym == 0)
return; /* Nothing to do. */
if (map_from_key_sym & SPCLKEY)
map_from_key_sym &= ~SPCLKEY;
if (map_from_key_sym >= F_ACC && map_from_key_sym <= L_ACC) {
/* Accent function.*/
unsigned int accent_index = map_from_key_sym - F_ACC;
if (kbd->accents->acc[accent_index].accchar != 0) {
k_deadunicode(kbd, kbd->accents->acc[accent_index].accchar, !down);
}
} else {
switch(map_from_key_sym) {
case ASH: /* alt/meta shift */
k_shift(kbd, 3, down == 0);
break;
case LSHA: /* left shift + alt lock */
case RSHA: /* right shift + alt lock */
if (down == 0) chg_vc_kbd_led(kbd, ALKED);
case LSH: /* left shift */
case RSH: /* right shift */
k_shift(kbd, 0, down == 0);
break;
case LCTRA: /* left ctrl + alt lock */
case RCTRA: /* right ctrl + alt lock */
if (down == 0) chg_vc_kbd_led(kbd, ALKED);
case LCTR: /* left ctrl */
case RCTR: /* right ctrl */
k_shift(kbd, 1, down == 0);
break;
case LALTA: /* left alt + alt lock */
case RALTA: /* right alt + alt lock */
if (down == 0) chg_vc_kbd_led(kbd, ALKED);
case LALT: /* left alt */
case RALT: /* right alt */
k_shift(kbd, 2, down == 0);
break;
case ALK: /* alt lock */
if (down == 1) chg_vc_kbd_led(kbd, ALKED);
break;
case CLK: /* caps lock*/
if (down == 1) chg_vc_kbd_led(kbd, CLKED);
break;
case NLK: /* num lock */
if (down == 1) chg_vc_kbd_led(kbd, NLKED);
break;
case SLK: /* scroll lock */
if (down == 1) chg_vc_kbd_led(kbd, SLKED);
break;
default:
return;
}
}
} else {
if (map_from_key_sym == '\n' || map_from_key_sym == '\r') {
if (kbd->diacr) {
kbd->diacr = 0;
return;
}
}
if (map_from_key_sym >= ' ' && map_from_key_sym != 127) {
k_self(kbd, map_from_key_sym, !down);
}
}
if (kbd->text_len > 0) {
kbd->text[kbd->text_len] = '\0';
SDL_SendKeyboardText(kbd->text);
kbd->text_len = 0;
}
}
#endif /* SDL_INPUT_FBSDKBIO */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -819,7 +819,7 @@ SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode, int d
}
}
#else /* !SDL_INPUT_LINUXKD */
#elif !defined(SDL_INPUT_FBSDKBIO) /* !SDL_INPUT_LINUXKD */
SDL_EVDEV_keyboard_state *
SDL_EVDEV_kbd_init(void)