#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);
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 __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 == 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));
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)
{
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)
{
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(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 != NULL) updateMouse(mouseInputData);
}