| /* |
| Simple DirectMedia Layer |
| Copyright (C) 1997-2024 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" |
| |
| #ifdef __NetBSD__ |
| #define KS_GROUP_Ascii KS_GROUP_Plain |
| #define KS_Cmd_ScrollBack KS_Cmd_ScrollFastUp |
| #define KS_Cmd_ScrollFwd KS_Cmd_ScrollFastDown |
| #endif |
| |
| #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 }, |
| #ifndef __NetBSD__ |
| { { 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 } |
| #endif |
| }; |
| |
| 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_space, SDL_SCANCODE_SPACE }, |
| { 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 }, |
| #if !defined(__NetBSD__) |
| { KS_f21, SDL_SCANCODE_F21 }, |
| { KS_f22, SDL_SCANCODE_F22 }, |
| { KS_f23, SDL_SCANCODE_F23 }, |
| { KS_f24, SDL_SCANCODE_F24 }, |
| #endif |
| { 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; |
| int type; |
| } 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) |
| { |
| #ifdef WSKBDIO_SETVERSION |
| int version = WSKBDIO_EVENT_VERSION; |
| #endif |
| 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 | O_CLOEXEC); |
| 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) { |
| 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)); |
| RETIFIOCTLERR(ioctl(input->fd, WSKBDIO_GTYPE, &input->type)); |
| #ifdef WSKBDIO_SETVERSION |
| 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 (SDL_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); |
| /*SDL_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; |
| } |
| #ifndef __NetBSD__ |
| 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; |
| } |
| #endif |
| 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; |
| #ifndef __NetBSD__ |
| case KS_Mode_Lock: |
| { |
| if (input->lockheldstate[3]) { |
| input->lockheldstate[3] = 0; |
| } |
| } break; |
| #endif |
| 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; |
| } |
| |
| if (input->type == WSKBD_TYPE_USB && events[i].value <= 0xE7) |
| SDL_SendKeyboardKey(type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, (SDL_Scancode)events[i].value); |
| else |
| 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 < SDL_arraysize(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) { |
| updateMouse(mouseInputData); |
| } |
| } |