Forráskód Böngészése

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.
Sam Lantinga 4 éve
szülő
commit
82aafa9aa8

+ 32 - 0
configure.ac

@@ -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"

+ 1 - 0
include/SDL_config.h.in

@@ -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

+ 27 - 0
src/core/openbsd/SDL_wscons.h

@@ -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();
+

+ 817 - 0
src/core/openbsd/SDL_wscons_kbd.c

@@ -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);
+}

+ 130 - 0
src/core/openbsd/SDL_wscons_mouse.c

@@ -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);
+}

+ 4 - 0
src/video/kmsdrm/SDL_kmsdrmevents.c

@@ -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
 
 }

+ 6 - 0
src/video/kmsdrm/SDL_kmsdrmvideo.c

@@ -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 */