diff --git a/configure.ac b/configure.ac index 57d74677d..898f44633 100644 --- a/configure.ac +++ b/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 + #include + #include + #include + #include + ],[ + 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" diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index 49cd0b570..511667909 100644 --- a/include/SDL_config.h.in +++ b/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 diff --git a/src/core/openbsd/SDL_wscons.h b/src/core/openbsd/SDL_wscons.h new file mode 100644 index 000000000..e4600fe5f --- /dev/null +++ b/src/core/openbsd/SDL_wscons.h @@ -0,0 +1,27 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2021 Sam Lantinga + + 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(); + diff --git a/src/core/openbsd/SDL_wscons_kbd.c b/src/core/openbsd/SDL_wscons_kbd.c new file mode 100644 index 000000000..52dfe8a70 --- /dev/null +++ b/src/core/openbsd/SDL_wscons_kbd.c @@ -0,0 +1,817 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2021 Sam Lantinga + + 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 +#include +#include "SDL_scancode.h" +#include "SDL_events.h" +#include "SDL_keyboard.h" +#include "SDL_wscons.h" +#include "SDL_log.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/src/core/openbsd/SDL_wscons_mouse.c b/src/core/openbsd/SDL_wscons_mouse.c new file mode 100644 index 000000000..bda7ca6cc --- /dev/null +++ b/src/core/openbsd/SDL_wscons_mouse.c @@ -0,0 +1,130 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2021 Sam Lantinga + + 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 +#include +#include +#include +#include +#include + +#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); +} diff --git a/src/video/kmsdrm/SDL_kmsdrmevents.c b/src/video/kmsdrm/SDL_kmsdrmevents.c index 584bd217e..87a7a2080 100644 --- a/src/video/kmsdrm/SDL_kmsdrmevents.c +++ b/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 } diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c index ebf643a01..a5f01f317 100644 --- a/src/video/kmsdrm/SDL_kmsdrmvideo.c +++ b/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 */