Fixed bug 5461 - Add rewritten WSCONS driver for OpenBSD

wahil1976

This patch adds a written-from-scratch WSCONS driver for OpenBSD. It does not have hardcoded keymaps, and it features mouse support when wsmux is available.

For this to work, it needs access to the /dev/wskbd* devices which are not available to non-root users by default. Access to those can be granted by changing /etc/fbtab to give the logging user the ownership of those devices.
This commit is contained in:
Sam Lantinga 2021-01-14 14:32:11 -08:00
parent 1adadc7702
commit 82aafa9aa8
7 changed files with 1017 additions and 0 deletions

View File

@ -2679,6 +2679,30 @@ CheckInputKBIO()
fi
}
dnl See if we can use the wscons input driver
CheckInputWSCONS()
{
AC_MSG_CHECKING(for OpenBSD wscons)
use_input_wscons=no
AC_TRY_COMPILE([
#include <sys/time.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsksymdef.h>
#include <dev/wscons/wsksymvar.h>
#include <sys/ioctl.h>
],[
struct wskbd_map_data data;
ioctl(0, WSKBDIO_GETMAP, &data);
],[
use_input_wscons=yes
])
AC_MSG_RESULT($use_input_wscons)
if test x$use_input_wscons = xyes; then
AC_DEFINE(SDL_INPUT_WSCONS, 1, [ ])
SUMMARY_input="${SUMMARY_input} wscons"
fi
}
dnl See if the platform offers libudev for device enumeration and hotplugging.
CheckLibUDev()
{
@ -3596,6 +3620,9 @@ case "$host" in
freebsd)
CheckInputKBIO
;;
openbsd)
CheckInputWSCONS
;;
esac
CheckUSBHID
CheckHIDAPI
@ -3741,6 +3768,11 @@ case "$host" in
SOURCES="$SOURCES $srcdir/src/core/linux/SDL_evdev_kbd.c"
SOURCES="$SOURCES $srcdir/src/core/freebsd/SDL_evdev_kbd_freebsd.c"
fi
# Set up files for wscons input
if test x$use_input_wscons = xyes; then
SOURCES="$SOURCES $srcdir/src/core/openbsd/SDL_wscons_kbd.c"
SOURCES="$SOURCES $srcdir/src/core/openbsd/SDL_wscons_mouse.c"
fi
# Set up other core UNIX files
SOURCES="$SOURCES $srcdir/src/core/linux/SDL_evdev_capabilities.c"
SOURCES="$SOURCES $srcdir/src/core/linux/SDL_threadprio.c"

View File

@ -297,6 +297,7 @@
#undef SDL_INPUT_LINUXEV
#undef SDL_INPUT_FBSDKBIO
#undef SDL_INPUT_LINUXKD
#undef SDL_INPUT_WSCONS
#undef SDL_JOYSTICK_HAIKU
#undef SDL_JOYSTICK_DINPUT
#undef SDL_JOYSTICK_XINPUT

View File

@ -0,0 +1,27 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2021 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.
*/
void SDL_WSCONS_Init();
void SDL_WSCONS_Quit();
void SDL_WSCONS_PumpEvents();

View File

@ -0,0 +1,817 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2021 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 <dev/wscons/wsksymvar.h>
#include <dev/wscons/wsksymdef.h>
#include "SDL_scancode.h"
#include "SDL_events.h"
#include "SDL_keyboard.h"
#include "SDL_wscons.h"
#include "SDL_log.h"
#include <sys/time.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplay_usl_io.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <unistd.h>
#include "../../events/SDL_events_c.h"
#define RETIFIOCTLERR(x) if (x == -1) { free(input); input = NULL; return NULL;}
typedef struct SDL_WSCONS_mouse_input_data SDL_WSCONS_mouse_input_data;
extern SDL_WSCONS_mouse_input_data* SDL_WSCONS_Init_Mouse();
extern void updateMouse(SDL_WSCONS_mouse_input_data* input);
extern void SDL_WSCONS_Quit_Mouse(SDL_WSCONS_mouse_input_data* input);
/* Conversion table courtesy of /usr/src/sys/dev/wscons/wskbdutil.c */
static const unsigned char latin1_to_upper[256] = {
/* 0 8 1 9 2 a 3 b 4 c 5 d 6 e 7 f */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 3 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 3 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 4 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 4 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5 */
0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 6 */
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 6 */
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 7 */
'X', 'Y', 'Z', 0x00, 0x00, 0x00, 0x00, 0x00, /* 7 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d */
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* e */
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* e */
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0x00, /* f */
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* f */
};
/* Compose table courtesy of /usr/src/sys/dev/wscons/wskbdutil.c */
static struct SDL_wscons_compose_tab_s {
keysym_t elem[2];
keysym_t result;
} compose_tab[] = {
{ { KS_plus, KS_plus }, KS_numbersign },
{ { KS_a, KS_a }, KS_at },
{ { KS_parenleft, KS_parenleft }, KS_bracketleft },
{ { KS_slash, KS_slash }, KS_backslash },
{ { KS_parenright, KS_parenright }, KS_bracketright },
{ { KS_parenleft, KS_minus }, KS_braceleft },
{ { KS_slash, KS_minus }, KS_bar },
{ { KS_parenright, KS_minus }, KS_braceright },
{ { KS_exclam, KS_exclam }, KS_exclamdown },
{ { KS_c, KS_slash }, KS_cent },
{ { KS_l, KS_minus }, KS_sterling },
{ { KS_y, KS_minus }, KS_yen },
{ { KS_s, KS_o }, KS_section },
{ { KS_x, KS_o }, KS_currency },
{ { KS_c, KS_o }, KS_copyright },
{ { KS_less, KS_less }, KS_guillemotleft },
{ { KS_greater, KS_greater }, KS_guillemotright },
{ { KS_question, KS_question }, KS_questiondown },
{ { KS_dead_acute, KS_space }, KS_apostrophe },
{ { KS_dead_grave, KS_space }, KS_grave },
{ { KS_dead_tilde, KS_space }, KS_asciitilde },
{ { KS_dead_circumflex, KS_space }, KS_asciicircum },
{ { KS_dead_diaeresis, KS_space }, KS_quotedbl },
{ { KS_dead_cedilla, KS_space }, KS_comma },
{ { KS_dead_circumflex, KS_A }, KS_Acircumflex },
{ { KS_dead_diaeresis, KS_A }, KS_Adiaeresis },
{ { KS_dead_grave, KS_A }, KS_Agrave },
{ { KS_dead_abovering, KS_A }, KS_Aring },
{ { KS_dead_tilde, KS_A }, KS_Atilde },
{ { KS_dead_cedilla, KS_C }, KS_Ccedilla },
{ { KS_dead_acute, KS_E }, KS_Eacute },
{ { KS_dead_circumflex, KS_E }, KS_Ecircumflex },
{ { KS_dead_diaeresis, KS_E }, KS_Ediaeresis },
{ { KS_dead_grave, KS_E }, KS_Egrave },
{ { KS_dead_acute, KS_I }, KS_Iacute },
{ { KS_dead_circumflex, KS_I }, KS_Icircumflex },
{ { KS_dead_diaeresis, KS_I }, KS_Idiaeresis },
{ { KS_dead_grave, KS_I }, KS_Igrave },
{ { KS_dead_tilde, KS_N }, KS_Ntilde },
{ { KS_dead_acute, KS_O }, KS_Oacute },
{ { KS_dead_circumflex, KS_O }, KS_Ocircumflex },
{ { KS_dead_diaeresis, KS_O }, KS_Odiaeresis },
{ { KS_dead_grave, KS_O }, KS_Ograve },
{ { KS_dead_tilde, KS_O }, KS_Otilde },
{ { KS_dead_acute, KS_U }, KS_Uacute },
{ { KS_dead_circumflex, KS_U }, KS_Ucircumflex },
{ { KS_dead_diaeresis, KS_U }, KS_Udiaeresis },
{ { KS_dead_grave, KS_U }, KS_Ugrave },
{ { KS_dead_acute, KS_Y }, KS_Yacute },
{ { KS_dead_acute, KS_a }, KS_aacute },
{ { KS_dead_circumflex, KS_a }, KS_acircumflex },
{ { KS_dead_diaeresis, KS_a }, KS_adiaeresis },
{ { KS_dead_grave, KS_a }, KS_agrave },
{ { KS_dead_abovering, KS_a }, KS_aring },
{ { KS_dead_tilde, KS_a }, KS_atilde },
{ { KS_dead_cedilla, KS_c }, KS_ccedilla },
{ { KS_dead_acute, KS_e }, KS_eacute },
{ { KS_dead_circumflex, KS_e }, KS_ecircumflex },
{ { KS_dead_diaeresis, KS_e }, KS_ediaeresis },
{ { KS_dead_grave, KS_e }, KS_egrave },
{ { KS_dead_acute, KS_i }, KS_iacute },
{ { KS_dead_circumflex, KS_i }, KS_icircumflex },
{ { KS_dead_diaeresis, KS_i }, KS_idiaeresis },
{ { KS_dead_grave, KS_i }, KS_igrave },
{ { KS_dead_tilde, KS_n }, KS_ntilde },
{ { KS_dead_acute, KS_o }, KS_oacute },
{ { KS_dead_circumflex, KS_o }, KS_ocircumflex },
{ { KS_dead_diaeresis, KS_o }, KS_odiaeresis },
{ { KS_dead_grave, KS_o }, KS_ograve },
{ { KS_dead_tilde, KS_o }, KS_otilde },
{ { KS_dead_acute, KS_u }, KS_uacute },
{ { KS_dead_circumflex, KS_u }, KS_ucircumflex },
{ { KS_dead_diaeresis, KS_u }, KS_udiaeresis },
{ { KS_dead_grave, KS_u }, KS_ugrave },
{ { KS_dead_acute, KS_y }, KS_yacute },
{ { KS_dead_diaeresis, KS_y }, KS_ydiaeresis },
{ { KS_quotedbl, KS_A }, KS_Adiaeresis },
{ { KS_quotedbl, KS_E }, KS_Ediaeresis },
{ { KS_quotedbl, KS_I }, KS_Idiaeresis },
{ { KS_quotedbl, KS_O }, KS_Odiaeresis },
{ { KS_quotedbl, KS_U }, KS_Udiaeresis },
{ { KS_quotedbl, KS_a }, KS_adiaeresis },
{ { KS_quotedbl, KS_e }, KS_ediaeresis },
{ { KS_quotedbl, KS_i }, KS_idiaeresis },
{ { KS_quotedbl, KS_o }, KS_odiaeresis },
{ { KS_quotedbl, KS_u }, KS_udiaeresis },
{ { KS_quotedbl, KS_y }, KS_ydiaeresis },
{ { KS_acute, KS_A }, KS_Aacute },
{ { KS_asciicircum, KS_A }, KS_Acircumflex },
{ { KS_grave, KS_A }, KS_Agrave },
{ { KS_asterisk, KS_A }, KS_Aring },
{ { KS_asciitilde, KS_A }, KS_Atilde },
{ { KS_cedilla, KS_C }, KS_Ccedilla },
{ { KS_acute, KS_E }, KS_Eacute },
{ { KS_asciicircum, KS_E }, KS_Ecircumflex },
{ { KS_grave, KS_E }, KS_Egrave },
{ { KS_acute, KS_I }, KS_Iacute },
{ { KS_asciicircum, KS_I }, KS_Icircumflex },
{ { KS_grave, KS_I }, KS_Igrave },
{ { KS_asciitilde, KS_N }, KS_Ntilde },
{ { KS_acute, KS_O }, KS_Oacute },
{ { KS_asciicircum, KS_O }, KS_Ocircumflex },
{ { KS_grave, KS_O }, KS_Ograve },
{ { KS_asciitilde, KS_O }, KS_Otilde },
{ { KS_acute, KS_U }, KS_Uacute },
{ { KS_asciicircum, KS_U }, KS_Ucircumflex },
{ { KS_grave, KS_U }, KS_Ugrave },
{ { KS_acute, KS_Y }, KS_Yacute },
{ { KS_acute, KS_a }, KS_aacute },
{ { KS_asciicircum, KS_a }, KS_acircumflex },
{ { KS_grave, KS_a }, KS_agrave },
{ { KS_asterisk, KS_a }, KS_aring },
{ { KS_asciitilde, KS_a }, KS_atilde },
{ { KS_cedilla, KS_c }, KS_ccedilla },
{ { KS_acute, KS_e }, KS_eacute },
{ { KS_asciicircum, KS_e }, KS_ecircumflex },
{ { KS_grave, KS_e }, KS_egrave },
{ { KS_acute, KS_i }, KS_iacute },
{ { KS_asciicircum, KS_i }, KS_icircumflex },
{ { KS_grave, KS_i }, KS_igrave },
{ { KS_asciitilde, KS_n }, KS_ntilde },
{ { KS_acute, KS_o }, KS_oacute },
{ { KS_asciicircum, KS_o }, KS_ocircumflex },
{ { KS_grave, KS_o }, KS_ograve },
{ { KS_asciitilde, KS_o }, KS_otilde },
{ { KS_acute, KS_u }, KS_uacute },
{ { KS_asciicircum, KS_u }, KS_ucircumflex },
{ { KS_grave, KS_u }, KS_ugrave },
{ { KS_acute, KS_y }, KS_yacute },
{ { KS_dead_caron, KS_space }, KS_L2_caron },
{ { KS_dead_caron, KS_S }, KS_L2_Scaron },
{ { KS_dead_caron, KS_Z }, KS_L2_Zcaron },
{ { KS_dead_caron, KS_s }, KS_L2_scaron },
{ { KS_dead_caron, KS_z }, KS_L2_zcaron }
};
static keysym_t ksym_upcase(keysym_t ksym)
{
if (ksym >= KS_f1 && ksym <= KS_f20)
return(KS_F1 - KS_f1 + ksym);
if (KS_GROUP(ksym) == KS_GROUP_Ascii && ksym <= 0xff &&
latin1_to_upper[ksym] != 0x00)
return(latin1_to_upper[ksym]);
return(ksym);
}
static struct wscons_keycode_to_SDL {
keysym_t sourcekey;
SDL_Scancode targetKey;
} conversion_table[] = {
{KS_Menu, SDL_SCANCODE_APPLICATION},
{KS_Up, SDL_SCANCODE_UP},
{KS_Down, SDL_SCANCODE_DOWN},
{KS_Left, SDL_SCANCODE_LEFT},
{KS_Right, SDL_SCANCODE_RIGHT},
{KS_Hold_Screen, SDL_SCANCODE_SCROLLLOCK},
{KS_Num_Lock, SDL_SCANCODE_NUMLOCKCLEAR},
{KS_Caps_Lock, SDL_SCANCODE_CAPSLOCK},
{KS_BackSpace, SDL_SCANCODE_BACKSPACE},
{KS_Delete, SDL_SCANCODE_BACKSPACE},
{KS_Home, SDL_SCANCODE_HOME},
{KS_End, SDL_SCANCODE_END},
{KS_Pause, SDL_SCANCODE_PAUSE},
{KS_Print_Screen, SDL_SCANCODE_PRINTSCREEN},
{KS_Insert, SDL_SCANCODE_INSERT},
{KS_Escape, SDL_SCANCODE_ESCAPE},
{KS_Return, SDL_SCANCODE_RETURN},
{KS_Linefeed, SDL_SCANCODE_RETURN},
{KS_KP_Delete, SDL_SCANCODE_DELETE},
{KS_KP_Insert, SDL_SCANCODE_INSERT},
{KS_Control_L, SDL_SCANCODE_LCTRL},
{KS_Control_R, SDL_SCANCODE_RCTRL},
{KS_Shift_L, SDL_SCANCODE_LSHIFT},
{KS_Shift_R, SDL_SCANCODE_RSHIFT},
{KS_Alt_L, SDL_SCANCODE_LALT},
{KS_Alt_R, SDL_SCANCODE_RALT},
{KS_grave, SDL_SCANCODE_GRAVE},
{KS_KP_0, SDL_SCANCODE_KP_0},
{KS_KP_1, SDL_SCANCODE_KP_1},
{KS_KP_2, SDL_SCANCODE_KP_2},
{KS_KP_3, SDL_SCANCODE_KP_3},
{KS_KP_4, SDL_SCANCODE_KP_4},
{KS_KP_5, SDL_SCANCODE_KP_5},
{KS_KP_6, SDL_SCANCODE_KP_6},
{KS_KP_7, SDL_SCANCODE_KP_7},
{KS_KP_8, SDL_SCANCODE_KP_8},
{KS_KP_9, SDL_SCANCODE_KP_9},
{KS_KP_Enter, SDL_SCANCODE_KP_ENTER},
{KS_KP_Multiply, SDL_SCANCODE_KP_MULTIPLY},
{KS_KP_Add, SDL_SCANCODE_KP_PLUS},
{KS_KP_Subtract, SDL_SCANCODE_KP_MINUS},
{KS_KP_Divide, SDL_SCANCODE_KP_DIVIDE},
{KS_KP_Up, SDL_SCANCODE_UP},
{KS_KP_Down, SDL_SCANCODE_DOWN},
{KS_KP_Left, SDL_SCANCODE_LEFT},
{KS_KP_Right, SDL_SCANCODE_RIGHT},
{KS_KP_Equal, SDL_SCANCODE_KP_EQUALS},
{KS_f1, SDL_SCANCODE_F1},
{KS_f2, SDL_SCANCODE_F2},
{KS_f3, SDL_SCANCODE_F3},
{KS_f4, SDL_SCANCODE_F4},
{KS_f5, SDL_SCANCODE_F5},
{KS_f6, SDL_SCANCODE_F6},
{KS_f7, SDL_SCANCODE_F7},
{KS_f8, SDL_SCANCODE_F8},
{KS_f9, SDL_SCANCODE_F9},
{KS_f10, SDL_SCANCODE_F10},
{KS_f11, SDL_SCANCODE_F11},
{KS_f12, SDL_SCANCODE_F12},
{KS_f13, SDL_SCANCODE_F13},
{KS_f14, SDL_SCANCODE_F14},
{KS_f15, SDL_SCANCODE_F15},
{KS_f16, SDL_SCANCODE_F16},
{KS_f17, SDL_SCANCODE_F17},
{KS_f18, SDL_SCANCODE_F18},
{KS_f19, SDL_SCANCODE_F19},
{KS_f20, SDL_SCANCODE_F20},
{KS_f21, SDL_SCANCODE_F21},
{KS_f22, SDL_SCANCODE_F22},
{KS_f23, SDL_SCANCODE_F23},
{KS_f24, SDL_SCANCODE_F24},
{KS_Meta_L, SDL_SCANCODE_LGUI},
{KS_Meta_R, SDL_SCANCODE_RGUI},
{KS_Zenkaku_Hankaku, SDL_SCANCODE_LANG5},
{KS_Hiragana_Katakana, SDL_SCANCODE_INTERNATIONAL2},
{KS_yen, SDL_SCANCODE_INTERNATIONAL3},
{KS_Henkan, SDL_SCANCODE_INTERNATIONAL4},
{KS_Muhenkan, SDL_SCANCODE_INTERNATIONAL5},
{KS_KP_Prior, SDL_SCANCODE_PRIOR},
{KS_a, SDL_SCANCODE_A},
{KS_b, SDL_SCANCODE_B},
{KS_c, SDL_SCANCODE_C},
{KS_d, SDL_SCANCODE_D},
{KS_e, SDL_SCANCODE_E},
{KS_f, SDL_SCANCODE_F},
{KS_g, SDL_SCANCODE_G},
{KS_h, SDL_SCANCODE_H},
{KS_i, SDL_SCANCODE_I},
{KS_j, SDL_SCANCODE_J},
{KS_k, SDL_SCANCODE_K},
{KS_l, SDL_SCANCODE_L},
{KS_m, SDL_SCANCODE_M},
{KS_n, SDL_SCANCODE_N},
{KS_o, SDL_SCANCODE_O},
{KS_p, SDL_SCANCODE_P},
{KS_q, SDL_SCANCODE_Q},
{KS_r, SDL_SCANCODE_R},
{KS_s, SDL_SCANCODE_S},
{KS_t, SDL_SCANCODE_T},
{KS_u, SDL_SCANCODE_U},
{KS_v, SDL_SCANCODE_V},
{KS_w, SDL_SCANCODE_W},
{KS_x, SDL_SCANCODE_X},
{KS_y, SDL_SCANCODE_Y},
{KS_z, SDL_SCANCODE_Z},
{KS_0, SDL_SCANCODE_0},
{KS_1, SDL_SCANCODE_1},
{KS_2, SDL_SCANCODE_2},
{KS_3, SDL_SCANCODE_3},
{KS_4, SDL_SCANCODE_4},
{KS_5, SDL_SCANCODE_5},
{KS_6, SDL_SCANCODE_6},
{KS_7, SDL_SCANCODE_7},
{KS_8, SDL_SCANCODE_8},
{KS_9, SDL_SCANCODE_9},
{KS_minus, SDL_SCANCODE_MINUS},
{KS_equal, SDL_SCANCODE_EQUALS},
{KS_Tab, SDL_SCANCODE_TAB},
{KS_KP_Tab, SDL_SCANCODE_KP_TAB},
{KS_apostrophe, SDL_SCANCODE_APOSTROPHE},
{KS_bracketleft, SDL_SCANCODE_LEFTBRACKET},
{KS_bracketright, SDL_SCANCODE_RIGHTBRACKET},
{KS_semicolon, SDL_SCANCODE_SEMICOLON},
{KS_comma, SDL_SCANCODE_COMMA},
{KS_period, SDL_SCANCODE_PERIOD},
{KS_slash, SDL_SCANCODE_SLASH},
{KS_backslash, SDL_SCANCODE_BACKSLASH}
};
typedef struct {
int fd;
struct wskbd_map_data keymap;
int ledstate;
int origledstate;
int shiftstate[4];
int shiftheldstate[8];
int lockheldstate[5];
kbd_t encoding;
char text[128];
unsigned int text_len;
keysym_t composebuffer[2];
unsigned char composelen;
} SDL_WSCONS_input_data;
static SDL_WSCONS_input_data* inputs[4] = {NULL, NULL, NULL, NULL};
static SDL_WSCONS_mouse_input_data* mouseInputData = NULL;
#define IS_CONTROL_HELD (input->shiftstate[2] > 0)
#define IS_ALT_HELD (input->shiftstate[1] > 0)
#define IS_SHIFT_HELD ((input->shiftstate[0] > 0) || (input->ledstate & (1 << 5)))
#define IS_ALTGR_MODE ((input->ledstate & (1 << 4)) || (input->shiftstate[3] > 0))
#define IS_NUMLOCK_ON (input->ledstate & LED_NUM)
#define IS_SCROLLLOCK_ON (input->ledstate & LED_SCR)
#define IS_CAPSLOCK_ON (input->ledstate & LED_CAP)
static SDL_WSCONS_input_data* SDL_WSCONS_Init_Keyboard(const char* dev)
{
SDL_WSCONS_input_data* input = (SDL_WSCONS_input_data*)SDL_calloc(1, sizeof(SDL_WSCONS_input_data));
if (!input) {
return input;
}
input->fd = open(dev,O_RDWR | O_NONBLOCK);
if (input->fd == -1) {
free(input);
input = NULL;
return NULL;
}
input->keymap.map = SDL_calloc(sizeof(struct wscons_keymap), KS_NUMKEYCODES);
if (input->keymap.map == NULL) {
free(input);
return NULL;
}
input->keymap.maplen = KS_NUMKEYCODES;
RETIFIOCTLERR(ioctl(input->fd, WSKBDIO_GETMAP, &input->keymap));
RETIFIOCTLERR(ioctl(input->fd, WSKBDIO_GETLEDS, &input->ledstate));
input->origledstate = input->ledstate;
RETIFIOCTLERR(ioctl(input->fd, WSKBDIO_GETENCODING, &input->encoding));
#ifdef WSKBDIO_SETVERSION
int version = WSKBDIO_EVENT_VERSION;
RETIFIOCTLERR(ioctl(input->fd, WSKBDIO_SETVERSION, &version));
#endif
return input;
}
void SDL_WSCONS_Init()
{
inputs[0] = SDL_WSCONS_Init_Keyboard("/dev/wskbd0");
inputs[1] = SDL_WSCONS_Init_Keyboard("/dev/wskbd1");
inputs[2] = SDL_WSCONS_Init_Keyboard("/dev/wskbd2");
inputs[3] = SDL_WSCONS_Init_Keyboard("/dev/wskbd3");
mouseInputData = SDL_WSCONS_Init_Mouse();
return;
}
void SDL_WSCONS_Quit()
{
int i = 0;
SDL_WSCONS_input_data* input = NULL;
SDL_WSCONS_Quit_Mouse(mouseInputData);
mouseInputData = NULL;
for (i = 0; i < 4; i++) {
input = inputs[i];
if (input) {
if (input->fd != -1 && input->fd != 0) {
ioctl(input->fd,WSKBDIO_SETLEDS, &input->origledstate);
close(input->fd);
input->fd = -1;
}
free(input);
input = NULL;
}
inputs[i] = NULL;
}
}
static void put_queue(SDL_WSCONS_input_data *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_WSCONS_input_data* input, uint c)
{
if (c < 0x80)
/* 0******* */
put_queue(input, c);
else if (c < 0x800) {
/* 110***** 10****** */
put_queue(input, 0xc0 | (c >> 6));
put_queue(input, 0x80 | (c & 0x3f));
} else if (c < 0x10000) {
if (c >= 0xD800 && c <= 0xF500)
return;
if (c == 0xFFFF)
return;
/* 1110**** 10****** 10****** */
put_queue(input, 0xe0 | (c >> 12));
put_queue(input, 0x80 | ((c >> 6) & 0x3f));
put_queue(input, 0x80 | (c & 0x3f));
} else if (c < 0x110000) {
/* 11110*** 10****** 10****** 10****** */
put_queue(input, 0xf0 | (c >> 18));
put_queue(input, 0x80 | ((c >> 12) & 0x3f));
put_queue(input, 0x80 | ((c >> 6) & 0x3f));
put_queue(input, 0x80 | (c & 0x3f));
}
}
static void Translate_to_text(SDL_WSCONS_input_data* input, keysym_t ksym)
{
if (KS_GROUP(ksym) == KS_GROUP_Keypad) {
if (isprint(ksym & 0xFF)) ksym &= 0xFF;
}
switch(ksym) {
case KS_Escape:
case KS_Delete:
case KS_BackSpace:
case KS_Return:
case KS_Linefeed:
/* All of these are unprintable characters. Ignore them */
break;
default:
put_utf8(input, ksym);
break;
}
if (input->text_len > 0) {
input->text[input->text_len] = '\0';
SDL_SendKeyboardText(input->text);
/*memset(input->text, 0, sizeof(input->text));*/
input->text_len = 0;
input->text[0] = 0;
}
}
static void Translate_to_keycode(SDL_WSCONS_input_data* input, int type, keysym_t ksym)
{
struct wscons_keymap keyDesc = input->keymap.map[ksym];
keysym_t* group = &keyDesc.group1[KS_GROUP(keyDesc.group1[0]) == KS_GROUP_Keypad && IS_NUMLOCK_ON ? !IS_SHIFT_HELD : 0];
int i = 0;
/* Check command first, then group[0]*/
switch (keyDesc.command) {
case KS_Cmd_ScrollBack: {
SDL_SendKeyboardKey(type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_PAGEUP);
return;
}
case KS_Cmd_ScrollFwd: {
SDL_SendKeyboardKey(type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_PAGEDOWN);
return;
}
}
for (i = 0; i < sizeof(conversion_table) / sizeof(struct wscons_keycode_to_SDL); i++) {
if (conversion_table[i].sourcekey == group[0]) {
SDL_SendKeyboardKey(type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, conversion_table[i].targetKey);
return;
}
}
SDL_SendKeyboardKey(type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_UNKNOWN);
}
static void updateKeyboard(SDL_WSCONS_input_data* input)
{
struct wscons_event events[64];
int type;
int n,i,gindex,acc_i;
keysym_t *group;
keysym_t ksym, result;
if (!input) return;
if ((n = read(input->fd, events, sizeof(events))) > 0) {
n /= sizeof(struct wscons_event);
for (i = 0; i < n; i++) {
type = events[i].type;
switch(type) {
case WSCONS_EVENT_KEY_DOWN: {
switch (input->keymap.map[events[i].value].group1[0]) {
case KS_Hold_Screen: {
if (input->lockheldstate[0] >= 1) break;
input->ledstate ^= LED_SCR;
ioctl(input->fd, WSKBDIO_SETLEDS, &input->ledstate);
input->lockheldstate[0] = 1;
break;
}
case KS_Num_Lock: {
if (input->lockheldstate[1] >= 1) break;
input->ledstate ^= LED_NUM;
ioctl(input->fd, WSKBDIO_SETLEDS, &input->ledstate);
input->lockheldstate[1] = 1;
break;
}
case KS_Caps_Lock: {
if (input->lockheldstate[2] >= 1) break;
input->ledstate ^= LED_CAP;
ioctl(input->fd, WSKBDIO_SETLEDS, &input->ledstate);
input->lockheldstate[2] = 1;
break;
}
case KS_Mode_Lock: {
if (input->lockheldstate[3] >= 1) break;
input->ledstate ^= 1 << 4;
ioctl(input->fd, WSKBDIO_SETLEDS, &input->ledstate);
input->lockheldstate[3] = 1;
break;
}
case KS_Shift_Lock: {
if (input->lockheldstate[4] >= 1) break;
input->ledstate ^= 1 << 5;
ioctl(input->fd, WSKBDIO_SETLEDS, &input->ledstate);
input->lockheldstate[4] = 1;
break;
}
case KS_Shift_L: {
if (input->shiftheldstate[0]) break;
input->shiftstate[0]++;
input->shiftheldstate[0] = 1;
break;
}
case KS_Shift_R: {
if (input->shiftheldstate[1]) break;
input->shiftstate[0]++;
input->shiftheldstate[1] = 1;
break;
}
case KS_Alt_L: {
if (input->shiftheldstate[2]) break;
input->shiftstate[1]++;
input->shiftheldstate[2] = 1;
break;
}
case KS_Alt_R: {
if (input->shiftheldstate[3]) break;
input->shiftstate[1]++;
input->shiftheldstate[3] = 1;
break;
}
case KS_Control_L: {
if (input->shiftheldstate[4]) break;
input->shiftstate[2]++;
input->shiftheldstate[4] = 1;
break;
}
case KS_Control_R: {
if (input->shiftheldstate[5]) break;
input->shiftstate[2]++;
input->shiftheldstate[5] = 1;
break;
}
case KS_Mode_switch: {
if (input->shiftheldstate[6]) break;
input->shiftstate[3]++;
input->shiftheldstate[6] = 1;
break;
}
}
}
break;
case WSCONS_EVENT_KEY_UP: {
switch(input->keymap.map[events[i].value].group1[0]) {
case KS_Hold_Screen: {
if (input->lockheldstate[0]) input->lockheldstate[0] = 0;
}
break;
case KS_Num_Lock: {
if (input->lockheldstate[1]) input->lockheldstate[1] = 0;
}
break;
case KS_Caps_Lock: {
if (input->lockheldstate[2]) input->lockheldstate[2] = 0;
}
break;
case KS_Mode_Lock: {
if (input->lockheldstate[3]) input->lockheldstate[3] = 0;
}
break;
case KS_Shift_Lock: {
if (input->lockheldstate[4]) input->lockheldstate[4] = 0;
}
break;
case KS_Shift_L: {
input->shiftheldstate[0] = 0;
if (input->shiftstate[0]) input->shiftstate[0]--;
break;
}
case KS_Shift_R: {
input->shiftheldstate[1] = 0;
if (input->shiftstate[0]) input->shiftstate[0]--;
break;
}
case KS_Alt_L: {
input->shiftheldstate[2] = 0;
if (input->shiftstate[1]) input->shiftstate[1]--;
break;
}
case KS_Alt_R: {
input->shiftheldstate[3] = 0;
if (input->shiftstate[1]) input->shiftstate[1]--;
break;
}
case KS_Control_L: {
input->shiftheldstate[4] = 0;
if (input->shiftstate[2]) input->shiftstate[2]--;
break;
}
case KS_Control_R: {
input->shiftheldstate[5] = 0;
if (input->shiftstate[2]) input->shiftstate[2]--;
break;
}
case KS_Mode_switch: {
input->shiftheldstate[6] = 0;
if (input->shiftstate[3]) input->shiftstate[3]--;
break;
}
}
}
break;
case WSCONS_EVENT_ALL_KEYS_UP:
for (i = 0; i < SDL_NUM_SCANCODES; i++) {
SDL_SendKeyboardKey(SDL_RELEASED, i);
}
break;
}
Translate_to_keycode(input, type, events[i].value);
if (type == WSCONS_EVENT_KEY_UP) continue;
if (IS_ALTGR_MODE && !IS_CONTROL_HELD)
group = &input->keymap.map[events[i].value].group2[0];
else
group = &input->keymap.map[events[i].value].group1[0];
if (IS_NUMLOCK_ON && KS_GROUP(group[1]) == KS_GROUP_Keypad) {
gindex = !IS_SHIFT_HELD;
ksym = group[gindex];
} else {
if (IS_CAPSLOCK_ON && !IS_SHIFT_HELD) {
gindex = 0;
ksym = ksym_upcase(group[0]);
} else {
gindex = IS_SHIFT_HELD;
ksym = group[gindex];
}
}
result = KS_voidSymbol;
switch (KS_GROUP(ksym)) {
case KS_GROUP_Ascii:
case KS_GROUP_Keypad:
case KS_GROUP_Function:
result = ksym;
break;
case KS_GROUP_Mod:
if (ksym == KS_Multi_key) {
input->ledstate |= WSKBD_LED_COMPOSE;
ioctl(input->fd,WSKBDIO_SETLEDS, &input->ledstate);
input->composelen = 2;
input->composebuffer[0] = input->composebuffer[1] = 0;
}
break;
case KS_GROUP_Dead:
if (input->composelen == 0) {
input->ledstate |= WSKBD_LED_COMPOSE;
ioctl(input->fd,WSKBDIO_SETLEDS, &input->ledstate);
input->composelen = 1;
input->composebuffer[0] = ksym;
input->composebuffer[1] = 0;
} else result = ksym;
break;
}
if (result == KS_voidSymbol) continue;
if (input->composelen > 0) {
if (input->composelen == 2 && group == &input->keymap.map[events[i].value].group2[0]) {
if (input->keymap.map[events[i].value].group2[gindex] == input->keymap.map[events[i].value].group1[gindex]) {
input->composelen = 0;
input->composebuffer[0] = input->composebuffer[1] = 0;
}
}
if (input->composelen != 0) {
input->composebuffer[2 - input->composelen] = result;
if (--input->composelen == 0) {
result = KS_voidSymbol;
input->ledstate &= ~WSKBD_LED_COMPOSE;
ioctl(input->fd,WSKBDIO_SETLEDS, &input->ledstate);
for (acc_i = 0; acc_i < nitems(compose_tab); acc_i++) {
if ((compose_tab[acc_i].elem[0] == input->composebuffer[0]
&& compose_tab[acc_i].elem[1] == input->composebuffer[1])
|| (compose_tab[acc_i].elem[0] == input->composebuffer[1]
&& compose_tab[acc_i].elem[1] == input->composebuffer[0])) {
result = compose_tab[acc_i].result;
break;
}
}
} else continue;
}
}
if (KS_GROUP(result) == KS_GROUP_Ascii) {
if (IS_CONTROL_HELD) {
if ((result >= KS_at && result <= KS_z) || result == KS_space)
result = result & 0x1f;
else if (result == KS_2)
result = 0x00;
else if (result >= KS_3 && result <= KS_7)
result = KS_Escape + (result - KS_3);
else if (result == KS_8)
result = KS_Delete;
}
if (IS_ALT_HELD) {
if (input->encoding & KB_METAESC) {
Translate_to_keycode(input, WSCONS_EVENT_KEY_DOWN, KS_Escape);
Translate_to_text(input, result);
continue;
} else result |= 0x80;
}
}
Translate_to_text(input,result);
continue;
}
}
}
void SDL_WSCONS_PumpEvents()
{
int i = 0;
for (i = 0; i < 4; i++)
updateKeyboard(inputs[i]);
if (mouseInputData != NULL) updateMouse(mouseInputData);
}

View File

@ -0,0 +1,130 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2021 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 "SDL_events.h"
#include <sys/time.h>
#include <dev/wscons/wsconsio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <fcntl.h>
#include "../../events/SDL_mouse_c.h"
typedef struct SDL_WSCONS_mouse_input_data
{
int fd;
} SDL_WSCONS_mouse_input_data;
SDL_WSCONS_mouse_input_data* SDL_WSCONS_Init_Mouse()
{
SDL_WSCONS_mouse_input_data* mouseInputData = SDL_calloc(1, sizeof(SDL_WSCONS_mouse_input_data));
if (!mouseInputData) return NULL;
mouseInputData->fd = open("/dev/wsmouse",O_RDWR | O_NONBLOCK);
if (mouseInputData->fd == -1) {free(mouseInputData); return NULL; }
ioctl(mouseInputData->fd, WSMOUSEIO_SETMODE, WSMOUSE_COMPAT);
#ifdef WSMOUSEIO_SETVERSION
int version = WSMOUSEIO_EVENT_VERSION;
ioctl(inputData->fd, WSMOUSEIO_SETVERSION, &version);
#endif
return mouseInputData;
}
void updateMouse(SDL_WSCONS_mouse_input_data* inputData)
{
struct wscons_event events[64];
int type;
int n,i;
SDL_Mouse* mouse = SDL_GetMouse();
if ((n = read(inputData->fd, events, sizeof(events))) > 0)
{
n /= sizeof(struct wscons_event);
for (i = 0; i < n; i++)
{
type = events[i].type;
switch(type)
{
case WSCONS_EVENT_MOUSE_DOWN:
{
switch (events[i].value)
{
case 0: /* Left Mouse Button. */
SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, SDL_BUTTON_LEFT);
break;
case 1: /* Middle Mouse Button. */
SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, SDL_BUTTON_MIDDLE);
break;
case 2: /* Right Mouse Button. */
SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, SDL_BUTTON_RIGHT);
break;
}
}
break;
case WSCONS_EVENT_MOUSE_UP:
{
switch (events[i].value)
{
case 0: /* Left Mouse Button. */
SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, SDL_BUTTON_LEFT);
break;
case 1: /* Middle Mouse Button. */
SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, SDL_BUTTON_MIDDLE);
break;
case 2: /* Right Mouse Button. */
SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, SDL_BUTTON_RIGHT);
break;
}
}
break;
case WSCONS_EVENT_MOUSE_DELTA_X:
{
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 1, events[i].value * 2, 0);
break;
}
case WSCONS_EVENT_MOUSE_DELTA_Y:
{
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 1, 0, -events[i].value * 2);
break;
}
case WSCONS_EVENT_MOUSE_DELTA_W:
{
SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0, SDL_MOUSEWHEEL_NORMAL);
break;
}
case WSCONS_EVENT_MOUSE_DELTA_Z:
{
SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, -events[i].value, SDL_MOUSEWHEEL_NORMAL);
break;
}
}
}
}
}
void SDL_WSCONS_Quit_Mouse(SDL_WSCONS_mouse_input_data* inputData)
{
if (!inputData) return;
close(inputData->fd);
free(inputData);
}

View File

@ -28,12 +28,16 @@
#ifdef SDL_INPUT_LINUXEV
#include "../../core/linux/SDL_evdev.h"
#elif defined SDL_INPUT_WSCONS
#include "../../core/openbsd/SDL_wscons.h"
#endif
void KMSDRM_PumpEvents(_THIS)
{
#ifdef SDL_INPUT_LINUXEV
SDL_EVDEV_Poll();
#elif defined SDL_INPUT_WSCONS
SDL_WSCONS_PumpEvents();
#endif
}

View File

@ -34,6 +34,8 @@
#ifdef SDL_INPUT_LINUXEV
#include "../../core/linux/SDL_evdev.h"
#elif defined SDL_INPUT_WSCONS
#include "../../core/openbsd/SDL_wscons.h"
#endif
/* KMS/DRM declarations */
@ -839,6 +841,8 @@ KMSDRM_VideoInit(_THIS)
#ifdef SDL_INPUT_LINUXEV
SDL_EVDEV_Init();
#elif defined(SDL_INPUT_WSCONS)
SDL_WSCONS_Init();
#endif
/* Since we create and show the default cursor on KMSDRM_InitMouse() and
@ -879,6 +883,8 @@ KMSDRM_VideoQuit(_THIS)
#ifdef SDL_INPUT_LINUXEV
SDL_EVDEV_Quit();
#elif defined(SDL_INPUT_WSCONS)
SDL_WSCONS_Quit();
#endif
/* Clear out the window list */