#include "input.h" #include "ffi.h" #include "font.h" #include "log.h" #include "script.h" #include "stb_ds.h" #include "time.h" #include #include #include #include "resources.h" #include "stb_ds.h" float deltaT = 0; static int mouse_states[3] = {INPUT_UP}; static int key_states[512] = {INPUT_UP}; JSValue jsinput; JSValue jsnum; JSValue jsgamepadstr[15]; JSValue jsaxesstr[4]; JSValue jsinputstate[5]; JSValue jsaxis; JSValue jsany; JSValue jsmouse; JSValue jspos; JSValue jsmove; JSValue jsscroll; cpVect mousewheel = {0,0}; cpVect mouse_pos = {0, 0}; cpVect mouse_delta = {0, 0}; struct joystick { int id; //GLFWgamepadstate state; }; static int *downkeys = NULL; static struct joystick *joysticks = NULL; static int mquit = 0; static struct callee pawn_callee; static struct callee gamepad_callee; static struct { char *key; JSValue value; } *jshash = NULL; JSValue input2js(const char *input) { int idx = shgeti(jshash, input); if (idx != -1) return jshash[idx].value; if (shlen(jshash) == 0) sh_new_arena(jshash); JSValue n = str2js(input); shput(jshash, input, n); return n; } void add_downkey(int key) { for (int i = 0; i < arrlen(downkeys); i++) if (downkeys[i] == key) return; arrput(downkeys, key); } void rm_downkey(int key) { for (int i = 0; i < arrlen(downkeys); i++) if (downkeys[i] == key) { arrdelswap(downkeys, i); return; } } char *mb2str(int btn) { switch(btn) { case 0: return "lm"; break; case 1: return "rm"; break; case 2: return "mm"; break; } return "NULLMOUSE"; } void input_mouse(int btn, int state, uint32_t mod) { char out[16] = {0}; snprintf(out, 16, "%s%s%s%s", mod & SAPP_MODIFIER_CTRL ? "C-" : "", mod & SAPP_MODIFIER_ALT ? "M-" : "", mod & SAPP_MODIFIER_SUPER ? "S-" : "", mb2str(btn) ); JSValue argv[3]; argv[0] = JS_NewString(js, "emacs"); argv[1] = JS_NewString(js, out); argv[2] = jsinputstate[state]; script_callee(pawn_callee, 3, argv); JS_FreeValue(js, argv[0]); JS_FreeValue(js, argv[1]); } void input_mouse_move(float x, float y, float dx, float dy, uint32_t mod) { mouse_pos.x = x; mouse_pos.y = mainwin.height - y; mouse_delta.x = dx; mouse_delta.y = -dy; JSValue argv[4]; argv[0] = jsmouse; argv[1] = jsmove; argv[2] = vec2js(mouse_pos); argv[3] = vec2js(mouse_delta); script_callee(pawn_callee, 4, argv); JS_FreeValue(js, argv[2]); JS_FreeValue(js, argv[3]); } void input_mouse_scroll(float x, float y, uint32_t mod) { mousewheel.x = x; mousewheel.y = y; JSValue argv[4]; argv[0] = jsmouse; char out[16] = {0}; snprintf(out, 16, "%s%s%sscroll", mod & SAPP_MODIFIER_CTRL ? "C-" : "", mod & SAPP_MODIFIER_ALT ? "M-" : "", mod & SAPP_MODIFIER_SUPER ? "S-" : "" ); argv[1] = JS_NewString(js,out); argv[2] = vec2js(mousewheel); script_callee(pawn_callee, 3, argv); JS_FreeValue(js, argv[1]); JS_FreeValue(js, argv[2]); } void input_btn(int btn, int state, uint32_t mod) { char *keystr = keyname_extd(btn); if (strlen(keystr) == 1 && mod & SAPP_MODIFIER_SHIFT) keystr[0] = toupper(keystr[0]); char out[16] = {0}; snprintf(out, 16, "%s%s%s%s", mod & SAPP_MODIFIER_CTRL ? "C-" : "", mod & SAPP_MODIFIER_ALT ? "M-" : "", mod & SAPP_MODIFIER_SUPER ? "S-" : "", keystr ); JSValue argv[3]; argv[1] = JS_NewString(js, out); argv[2] = jsinputstate[state]; argv[0] = JS_NewString(js, "emacs"); script_callee(pawn_callee, 3, argv); JS_FreeValue(js, argv[0]); argv[0] = JS_NewString(js, "action"); script_callee(pawn_callee, 3, argv); JS_FreeValue(js, argv[0]); JS_FreeValue(js, argv[1]); if (state == INPUT_DOWN) { key_states[btn] = INPUT_DOWN; add_downkey(btn); } else if (state == INPUT_UP) { key_states[btn] = INPUT_UP; rm_downkey(btn); } } static const uint32_t UNCHAR_FLAGS = SAPP_MODIFIER_CTRL | SAPP_MODIFIER_ALT | SAPP_MODIFIER_SUPER; void input_key(uint32_t key, uint32_t mod) { if (mod & UNCHAR_FLAGS) return; if (key <= 31 || key >= 127) return; JSValue argv[2]; char s[2] = {key, '\0'}; argv[0] = JS_NewString(js, "char"); argv[1] = JS_NewString(js, s); script_callee(pawn_callee, 2, argv); JS_FreeValue(js, argv[0]); JS_FreeValue(js, argv[1]); } void register_pawn(struct callee c) { pawn_callee = c; } void register_gamepad(struct callee c) { gamepad_callee = c; } static void pawn_call_keydown(int key) { JSValue argv[4]; argv[0] = jsinput; argv[1] = jsnum; argv[2] = jsinputstate[INPUT_DOWN]; /* TODO: Could cache */ argv[3] = JS_NewInt32(js, key); script_callee(pawn_callee, 4, argv); JS_FreeValue(js, argv[3]); } /* 0 free 1 lock */ void set_mouse_mode(int mousemode) { sapp_lock_mouse(mousemode); } void input_init() { jsaxesstr[0] = str2js("ljoy"); jsaxesstr[1] = str2js("rjoy"); jsaxesstr[2] = str2js("ltrigger"); jsaxesstr[3] = str2js("rtrigger"); jsaxis = str2js("axis"); jsinputstate[INPUT_UP] = str2js("released"); jsinputstate[INPUT_REPEAT] = str2js("rep"); jsinputstate[INPUT_DOWN] = str2js("pressed"); jsinputstate[3] = str2js("pressrep"); jsinputstate[4] = str2js("down"); jsinput = str2js("input"); jsnum = str2js("num"); jsany = str2js("any"); jsmouse = str2js("mouse"); jspos = str2js("pos"); jsmove = str2js("move"); jsscroll = str2js("scroll"); for (int i = 0; i < 512; i++) key_states[i] = INPUT_UP; for (int i = 0; i < 3; i++) mouse_states[i] = INPUT_UP; } char keybuf[50]; const char *keyname_extd(int key) { if (key > 289 && key < 302) { int num = key - 289; sprintf(keybuf, "f%d", num); return keybuf; } if (key >= 320 && key <= 329) { int num = key - 320; sprintf(keybuf, "kp%d", num); return keybuf; } switch (key) { case SAPP_KEYCODE_ENTER: return "enter"; case SAPP_KEYCODE_ESCAPE: return "escape"; case SAPP_KEYCODE_DELETE: return "delete"; case SAPP_KEYCODE_INSERT: return "insert"; case SAPP_KEYCODE_TAB: return "tab"; case SAPP_KEYCODE_RIGHT: return "right"; case SAPP_KEYCODE_LEFT: return "left"; case SAPP_KEYCODE_UP: return "up"; case SAPP_KEYCODE_DOWN: return "down"; case SAPP_KEYCODE_LEFT_SHIFT: return "lshift"; case SAPP_KEYCODE_RIGHT_SHIFT: return "rshift"; case SAPP_KEYCODE_LEFT_CONTROL: return "lctrl"; case SAPP_KEYCODE_LEFT_ALT: return "lalt"; case SAPP_KEYCODE_RIGHT_CONTROL: return "rctrl"; case SAPP_KEYCODE_RIGHT_ALT: return "ralt"; case SAPP_KEYCODE_SPACE: return "space"; case SAPP_KEYCODE_KP_ADD: return "plus"; case SAPP_KEYCODE_KP_SUBTRACT: return "minus"; case SAPP_KEYCODE_GRAVE_ACCENT: return "`"; case SAPP_KEYCODE_LEFT_BRACKET: return "lbracket"; case SAPP_KEYCODE_RIGHT_BRACKET: return "rbracket"; case SAPP_KEYCODE_BACKSPACE: return "backspace"; case SAPP_KEYCODE_PAGE_UP: return "pgup"; case SAPP_KEYCODE_PAGE_DOWN: return "pgdown"; } if (key >= 32 && key <=90) { keybuf[0] = tolower(key); keybuf[1] = '\0'; return keybuf; } return "NULL"; } void call_input_down(int *key) { JSValue argv[3]; argv[0] = JS_NewString(js, "emacs"); argv[1] = input2js(keyname_extd(*key)); argv[2] = jsinputstate[4]; script_callee(pawn_callee, 3, argv); JS_FreeValue(js, argv[0]); } /* This is called once every frame - or more if we want it more! */ void input_poll(double wait) { for (int i = 0; i < arrlen(downkeys); i++) call_input_down(&downkeys[i]); } int key_is_num(int key) { return key <= 57 && key >= 48; } void cursor_hide() { sapp_show_mouse(0); } void cursor_show() { sapp_show_mouse(1); } int action_down(int key) { return key_states[key] == INPUT_DOWN; } int action_up(int key) { return key_states[key] == INPUT_UP; } void quit() { sapp_quit(); }