#include "SDL_internal.h"
#include <dev/wscons/wsksymvar.h>
#include <dev/wscons/wsksymdef.h>
#include "SDL_wscons.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"
#include "../../events/SDL_keyboard_c.h"
#ifdef SDL_PLATFORM_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) { \
SDL_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(void);
extern void updateMouse(SDL_WSCONS_mouse_input_data *input);
extern void SDL_WSCONS_Quit_Mouse(SDL_WSCONS_mouse_input_data *input);
static const unsigned char latin1_to_upper[256] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0x00, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, };
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 SDL_PLATFORM_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 },
#ifndef SDL_PLATFORM_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;
SDL_KeyboardID keyboardID;
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 NULL;
}
input->fd = open(dev, O_RDWR | O_NONBLOCK | O_CLOEXEC);
if (input->fd == -1) {
SDL_free(input);
input = NULL;
return NULL;
}
input->keyboardID = SDL_GetNextObjectID();
SDL_AddKeyboard(input->keyboardID, NULL);
input->keymap.map = SDL_calloc(KS_NUMKEYCODES, sizeof(struct wscons_keymap));
if (!input->keymap.map) {
SDL_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(void)
{
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(void)
{
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;
}
SDL_free(input);
input = NULL;
}
inputs[i] = NULL;
}
}
static void put_queue(SDL_WSCONS_input_data *kbd, uint c)
{
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)
put_queue(input, c);
else if (c < 0x800) {
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;
}
put_queue(input, 0xe0 | (c >> 12));
put_queue(input, 0x80 | ((c >> 6) & 0x3f));
put_queue(input, 0x80 | (c & 0x3f));
} else if (c < 0x110000) {
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:
break;
default:
put_utf8(input, ksym);
break;
}
if (input->text_len > 0) {
input->text[input->text_len] = '\0';
SDL_SendKeyboardText(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, Uint64 timestamp)
{
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;
switch (keyDesc.command) {
case KS_Cmd_ScrollBack:
{
SDL_SendKeyboardKey(timestamp, input->keyboardID, 0, SDL_SCANCODE_PAGEUP, (type == WSCONS_EVENT_KEY_DOWN));
return;
}
case KS_Cmd_ScrollFwd:
{
SDL_SendKeyboardKey(timestamp, input->keyboardID, 0, SDL_SCANCODE_PAGEDOWN, (type == WSCONS_EVENT_KEY_DOWN));
return;
}
default:
break;
}
for (i = 0; i < SDL_arraysize(conversion_table); i++) {
if (conversion_table[i].sourcekey == group[0]) {
SDL_SendKeyboardKey(timestamp, input->keyboardID, group[0], conversion_table[i].targetKey, (type == WSCONS_EVENT_KEY_DOWN));
return;
}
}
SDL_SendKeyboardKey(timestamp, input->keyboardID, group[0], SDL_SCANCODE_UNKNOWN, (type == WSCONS_EVENT_KEY_DOWN));
}
static Uint64 GetEventTimestamp(struct timespec *time)
{
return SDL_GetTicksNS();
}
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++) {
Uint64 timestamp = GetEventTimestamp(&events[i].time);
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 SDL_PLATFORM_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 SDL_PLATFORM_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_SCANCODE_COUNT; i++) {
SDL_SendKeyboardKey(timestamp, input->keyboardID, 0, (SDL_Scancode)i, false);
}
break;
default:
break;
}
if (input->type == WSKBD_TYPE_USB && events[i].value <= 0xE7) {
SDL_SendKeyboardKey(timestamp, input->keyboardID, 0, (SDL_Scancode)events[i].value, (type == WSCONS_EVENT_KEY_DOWN));
} else {
Translate_to_keycode(input, type, events[i].value, timestamp);
}
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, 0);
Translate_to_text(input, result);
continue;
} else {
result |= 0x80;
}
}
}
Translate_to_text(input, result);
continue;
}
}
}
void SDL_WSCONS_PumpEvents(void)
{
int i = 0;
for (i = 0; i < 4; i++) {
updateKeyboard(inputs[i]);
}
if (mouseInputData) {
updateMouse(mouseInputData);
}
}