prosperon/source/engine/input.c

527 lines
12 KiB
C
Raw Normal View History

2021-11-30 21:29:18 -06:00
#include "input.h"
2022-08-26 09:19:17 -05:00
#include <stdio.h>
#include "script.h"
2022-08-26 09:19:17 -05:00
#include "stb_ds.h"
#include "log.h"
#include "ffi.h"
2023-04-25 16:59:12 -05:00
#include "time.h"
2023-04-28 12:49:18 -05:00
#include "font.h"
2021-11-30 21:29:18 -06:00
int32_t mouseWheelX = 0;
int32_t mouseWheelY = 0;
float deltaT = 0;
cpVect mouse_pos = {0,0};
cpVect mouse_delta = {0,0};
2022-02-06 10:14:57 -06:00
2023-04-25 14:59:26 -05:00
struct joystick {
int id;
GLFWgamepadstate state;
};
2022-08-26 09:19:17 -05:00
static int *downkeys = NULL;
2023-04-25 14:59:26 -05:00
static struct joystick *joysticks = NULL;
2022-08-12 14:03:56 -05:00
static int mquit = 0;
2023-04-19 15:16:35 -05:00
static struct callee pawn_callee;
2023-04-25 16:59:12 -05:00
static struct callee gamepad_callee;
2022-12-19 18:15:38 -06:00
2023-04-28 12:49:18 -05:00
const char *gamepad2str(int btn)
{
switch(btn) {
case GLFW_GAMEPAD_BUTTON_CROSS: return "cross";
case GLFW_GAMEPAD_BUTTON_CIRCLE: return "circle";
case GLFW_GAMEPAD_BUTTON_SQUARE: return "square";
case GLFW_GAMEPAD_BUTTON_TRIANGLE: return "triangle";
case GLFW_GAMEPAD_BUTTON_START: return "start";
case GLFW_GAMEPAD_BUTTON_LEFT_BUMPER: return "lbump";
case GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER: return "rbump";
case GLFW_GAMEPAD_BUTTON_GUIDE: return "guide";
case GLFW_GAMEPAD_BUTTON_BACK: return "back";
case GLFW_GAMEPAD_BUTTON_DPAD_UP: return "dup";
case GLFW_GAMEPAD_BUTTON_DPAD_DOWN: return "ddown";
case GLFW_GAMEPAD_BUTTON_DPAD_LEFT: return "dleft";
case GLFW_GAMEPAD_BUTTON_DPAD_RIGHT: return "dright";
case GLFW_GAMEPAD_BUTTON_LEFT_THUMB: return "lthumb";
case GLFW_GAMEPAD_BUTTON_RIGHT_THUMB: return "rthumb";
}
}
2023-04-19 15:16:35 -05:00
void register_pawn(struct callee c)
{
pawn_callee = c;
2022-12-19 18:15:38 -06:00
}
2023-04-25 16:59:12 -05:00
void register_gamepad(struct callee c)
{
gamepad_callee = c;
}
2023-02-03 13:41:53 -06:00
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;
}
}
2022-02-06 10:14:57 -06:00
static void cursor_pos_cb(GLFWwindow *w, double xpos, double ypos)
{
mouse_delta.x = xpos - mouse_pos.x;
mouse_delta.y = ypos - mouse_pos.y;
mouse_pos.x = xpos;
mouse_pos.y = ypos;
2023-04-19 15:16:35 -05:00
JSValue argv[2];
argv[0] = JS_NewString(js, "input_mouse_pos");
argv[1] = vec2js(mouse_pos);
script_callee(pawn_callee, 2, argv);
JS_FreeValue(js, argv[0]);
JS_FreeValue(js, argv[1]);
2022-02-06 10:14:57 -06:00
}
2023-02-13 08:30:35 -06:00
static void pawn_call_keydown(int key)
{
2023-04-19 15:16:35 -05:00
JSValue argv[2];
argv[0] = JS_NewString(js, "input_num_pressed");
argv[1] = JS_NewInt32(js, key);
script_callee(pawn_callee, 2, argv);
JS_FreeValue(js, argv[0]);
JS_FreeValue(js, argv[1]);
2023-02-13 08:30:35 -06:00
}
2022-02-06 10:14:57 -06:00
static void scroll_cb(GLFWwindow *w, double xoffset, double yoffset)
{
mouseWheelY = yoffset;
mouseWheelX = xoffset;
}
static void mb_cb(GLFWwindow *w, int button, int action, int mods)
{
const char *act = NULL;
const char *btn = NULL;
switch (action) {
case GLFW_PRESS:
act = "pressed";
2023-02-03 13:41:53 -06:00
add_downkey(button);
break;
case GLFW_RELEASE:
act = "released";
2023-02-03 13:41:53 -06:00
rm_downkey(button);
2023-02-08 15:30:12 -06:00
call_input_signal("input_any_released");
break;
case GLFW_REPEAT:
act = "repeat";
break;
}
2023-02-03 13:41:53 -06:00
btn = keyname_extd(button, button);
if (!act || !btn) {
YughError("Tried to call a mouse action that doesn't exist.");
return;
}
char keystr[50] = {'\0'};
snprintf(keystr, 50, "input_%s_%s", btn, act);
call_input_signal(keystr);
}
2023-02-04 22:53:54 -06:00
void set_mouse_mode(int mousemode)
{
glfwSetInputMode(mainwin->window, GLFW_CURSOR, mousemode);
}
2023-02-13 13:35:01 -06:00
void char_cb(GLFWwindow *w, unsigned int codepoint)
{
2023-04-19 15:16:35 -05:00
static char out[2] = {0};
static JSValue argv[2];
out[0] = (char)codepoint;
argv[0] = JS_NewString(js, "input_text");
argv[1] = JS_NewString(js, out);
script_callee(pawn_callee, 2, argv);
JS_FreeValue(js, argv[0]);
JS_FreeValue(js, argv[1]);
2023-02-13 13:35:01 -06:00
}
2023-03-10 13:13:48 -06:00
static GLFWcharfun nukechar;
2023-04-25 14:59:26 -05:00
void joystick_add(int id)
{
struct joystick joy = {0};
joy.id = id;
arrpush(joysticks, joy);
}
void joystick_cb(int jid, int event)
{
YughWarn("IN joystick cb");
if (event == GLFW_CONNECTED) {
for (int i = 0; i < arrlen(joysticks); i++)
if (joysticks[i].id == jid) return;
joystick_add(jid);
} else if (event == GLFW_DISCONNECTED) {
for (int i = 0; i < arrlen(joysticks); i++) {
if (joysticks[i].id == jid) {
arrdelswap(joysticks,i);
return;
}
}
}
}
2023-04-28 12:49:18 -05:00
JSValue jsgamepadstr[15];
JSValue jsaxesstr[4];
2022-02-06 10:14:57 -06:00
void input_init()
{
glfwSetCursorPosCallback(mainwin->window, cursor_pos_cb);
glfwSetScrollCallback(mainwin->window, scroll_cb);
glfwSetMouseButtonCallback(mainwin->window, mb_cb);
2023-04-25 14:59:26 -05:00
glfwSetJoystickCallback(joystick_cb);
2023-03-10 13:13:48 -06:00
nukechar = glfwSetCharCallback(mainwin->window, char_cb);
2023-04-25 14:59:26 -05:00
const char *paddb = slurp_text("data/gamecontrollerdb.txt");
glfwUpdateGamepadMappings(paddb);
free(paddb);
2023-04-28 12:49:18 -05:00
for (int b = 0; b < 15; b++)
jsgamepadstr[b] = str2js(gamepad2str(b));
jsaxesstr[0] = str2js("axis_ljoy");
jsaxesstr[1] = str2js("axis_rjoy");
jsaxesstr[2] = str2js("axis_ltrigger");
jsaxesstr[3] = str2js("axis_rtrigger");
2023-04-25 14:59:26 -05:00
/* Grab all joysticks initially present */
for (int i = 0; i < 16; i++)
if (glfwJoystickPresent(i)) joystick_add(i);
2023-03-10 13:13:48 -06:00
}
void input_to_nuke()
{
glfwSetCharCallback(mainwin->window, nukechar);
}
void input_to_game()
{
glfwSetCharCallback(mainwin->window, char_cb);
2022-08-12 14:03:56 -05:00
}
2022-12-20 08:16:26 -06:00
void call_input_signal(char *signal) {
2023-04-19 15:16:35 -05:00
JSValue s = JS_NewString(js, signal);
JS_Call(js, pawn_callee.fn, pawn_callee.obj, 1, &s);
JS_FreeValue(js, s);
2022-12-20 08:16:26 -06:00
}
2022-12-22 16:58:06 -06:00
const char *keyname_extd(int key, int scancode) {
char keybuf[50];
2023-02-08 15:30:12 -06:00
const char *kkey = NULL;
2022-12-22 16:58:06 -06:00
if (key > 289 && key < 302) {
2023-04-25 14:59:26 -05:00
int num = key-289;
sprintf(keybuf, "f%d", num);
return keybuf;
} else if (key >= 320 && key <= 329) {
int num = key-320;
sprintf(keybuf, "kp%d",num);
return keybuf;
} else {
switch(key) {
case GLFW_KEY_ENTER:
kkey = "enter";
break;
case GLFW_KEY_ESCAPE:
kkey = "escape";
break;
2023-02-06 16:41:47 -06:00
case GLFW_KEY_DELETE:
kkey = "delete";
break;
case GLFW_KEY_INSERT:
kkey = "insert";
break;
case GLFW_KEY_TAB:
kkey = "tab";
break;
case GLFW_KEY_RIGHT:
kkey = "right";
break;
case GLFW_KEY_LEFT:
kkey = "left";
break;
case GLFW_KEY_UP:
kkey = "up";
break;
case GLFW_KEY_DOWN:
kkey = "down";
break;
case GLFW_KEY_LEFT_SHIFT:
kkey = "lshift";
break;
case GLFW_KEY_RIGHT_SHIFT:
kkey = "rshift";
break;
case GLFW_KEY_LEFT_CONTROL:
kkey = "lctrl";
break;
case GLFW_KEY_LEFT_ALT:
kkey = "lalt";
break;
case GLFW_KEY_RIGHT_CONTROL:
kkey = "rctrl";
break;
case GLFW_KEY_RIGHT_ALT:
kkey= "ralt";
break;
case GLFW_KEY_SPACE:
kkey = "space";
break;
2023-02-03 13:41:53 -06:00
case GLFW_MOUSE_BUTTON_RIGHT:
kkey = "rmouse";
break;
case GLFW_MOUSE_BUTTON_LEFT:
kkey = "lmouse";
break;
case GLFW_MOUSE_BUTTON_MIDDLE:
kkey = "mmouse";
break;
2023-02-08 15:30:12 -06:00
case GLFW_KEY_KP_ADD:
kkey = "plus";
break;
case GLFW_KEY_KP_SUBTRACT:
kkey = "minus";
break;
2023-02-10 14:31:59 -06:00
case GLFW_KEY_GRAVE_ACCENT:
kkey = "backtick";
break;
case GLFW_KEY_LEFT_BRACKET:
kkey = "lbracket";
break;
case GLFW_KEY_RIGHT_BRACKET:
kkey = "rbracket";
break;
2023-02-13 13:35:01 -06:00
case GLFW_KEY_BACKSPACE:
kkey = "backspace";
break;
}
2022-12-22 16:58:06 -06:00
if (kkey) return kkey;
}
2023-02-08 15:30:12 -06:00
kkey = glfwGetKeyName(key, scancode);
if (kkey) return kkey;
2022-12-22 16:58:06 -06:00
return "NULL";
}
2022-12-22 16:58:06 -06:00
void call_input_down(int *key) {
char keystr[50] = {'\0'};
snprintf(keystr, 50, "input_%s_down", keyname_extd(*key, 0));
call_input_signal(keystr);
}
2023-04-25 14:59:26 -05:00
const char *axis2str(int axis)
{
switch (axis)
{
case GLFW_GAMEPAD_AXIS_LEFT_X: return "lx";
case GLFW_GAMEPAD_AXIS_LEFT_Y: return "ly";
case GLFW_GAMEPAD_AXIS_RIGHT_X: return "rx";
case GLFW_GAMEPAD_AXIS_RIGHT_Y: return "ry";
case GLFW_GAMEPAD_AXIS_LEFT_TRIGGER: return "ltrigger";
case GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER: return "rtrigger";
}
}
2022-12-22 16:58:06 -06:00
/* This is called once every frame - or more if we want it more! */
void input_poll(double wait)
{
mouse_delta = cpvzero;
2022-12-22 16:58:06 -06:00
mouseWheelX = 0;
mouseWheelY = 0;
2023-04-25 14:59:26 -05:00
glfwPollEvents();
// glfwWaitEventsTimeout(wait);
2022-12-22 16:58:06 -06:00
for (int i = 0; i < arrlen(downkeys); i++)
call_input_down(&downkeys[i]);
2023-04-25 14:59:26 -05:00
for (int i = 0; i < arrlen(joysticks); i++) {
GLFWgamepadstate state;
if (!glfwGetGamepadState(joysticks[i].id, &state)) continue;
2023-04-25 16:59:12 -05:00
JSValue argv[3];
2023-04-28 12:49:18 -05:00
argv[0] = num_cache[joysticks[i].id];
2023-04-25 16:59:12 -05:00
char inputstr[50];
2023-04-25 14:59:26 -05:00
for (int b = 0; b < 15; b++) {
2023-04-28 12:49:18 -05:00
argv[1] = jsgamepadstr[b];
2023-04-25 16:59:12 -05:00
2023-04-25 14:59:26 -05:00
if (state.buttons[b]) {
2023-04-28 12:49:18 -05:00
argv[2] = num_cache[0];
2023-04-25 16:59:12 -05:00
script_callee(gamepad_callee,3,argv);
if (!joysticks[i].state.buttons[b]) {
2023-04-28 12:49:18 -05:00
argv[2] = num_cache[1];
2023-04-25 16:59:12 -05:00
script_callee(gamepad_callee,3,argv);
}
2023-04-25 14:59:26 -05:00
}
else if (!state.buttons[b] && joysticks[i].state.buttons[b]) {
2023-04-28 12:49:18 -05:00
argv[2] = num_cache[2];
2023-04-25 16:59:12 -05:00
script_callee(gamepad_callee,3,argv);
2023-04-25 14:59:26 -05:00
}
}
2023-04-28 12:49:18 -05:00
argv[1] = jsaxesstr[0];
2023-04-25 16:59:12 -05:00
cpVect v;
v.x = state.axes[0];
v.y = -state.axes[1];
argv[2] = vec2js(v);
script_callee(gamepad_callee,3,argv);
2023-04-28 12:49:18 -05:00
JS_FreeValue(js, argv[2]);
2023-04-25 16:59:12 -05:00
2023-04-28 12:49:18 -05:00
argv[1] = jsaxesstr[1];
2023-04-25 16:59:12 -05:00
v.x = state.axes[2];
v.y = -state.axes[3];
argv[2] = vec2js(v);
script_callee(gamepad_callee,3,argv);
2023-04-28 12:49:18 -05:00
JS_FreeValue(js, argv[2]);
2023-04-25 16:59:12 -05:00
2023-04-28 12:49:18 -05:00
argv[1] = jsaxesstr[2];
2023-04-25 16:59:12 -05:00
argv[2] = num2js((state.axes[4]+1)/2);
script_callee(gamepad_callee,3,argv);
2023-04-28 12:49:18 -05:00
JS_FreeValue(js, argv[2]);
2023-04-25 16:59:12 -05:00
2023-04-28 12:49:18 -05:00
argv[1] = jsaxesstr[3];
2023-04-25 16:59:12 -05:00
argv[2] = num2js((state.axes[5]+1)/2);
2023-04-28 12:49:18 -05:00
script_callee(gamepad_callee,3,argv);
JS_FreeValue(js, argv[2]);
2023-04-25 16:59:12 -05:00
2023-04-25 14:59:26 -05:00
joysticks[i].state = state;
}
2022-12-22 16:58:06 -06:00
}
2023-02-13 08:30:35 -06:00
int key_is_num(int key) {
return key <= 57 && key >= 48;
}
2022-12-22 16:58:06 -06:00
void win_key_callback(GLFWwindow *w, int key, int scancode, int action, int mods)
{
char keystr[50] = {'\0'};
2023-02-28 09:40:53 -06:00
char kkey[50] = {'\0'};
snprintf(kkey, 50, "%s", keyname_extd(key,scancode));
2022-08-12 14:03:56 -05:00
switch (action) {
case GLFW_PRESS:
2022-12-22 16:58:06 -06:00
snprintf(keystr, 50, "input_%s_pressed", kkey);
2023-03-17 10:25:35 -05:00
call_input_signal(keystr);
snprintf(keystr,50,"input_%s_pressrep", kkey);
call_input_signal(keystr);
2023-02-03 13:41:53 -06:00
add_downkey(key);
2023-02-10 14:31:59 -06:00
call_input_signal("input_any_pressed");
2023-02-13 08:30:35 -06:00
if (key_is_num(key)) {
pawn_call_keydown(key-48);
}
2022-08-12 14:03:56 -05:00
break;
case GLFW_RELEASE:
2022-12-22 16:58:06 -06:00
snprintf(keystr, 50, "input_%s_released", kkey);
2023-03-17 10:25:35 -05:00
call_input_signal(keystr);
2023-02-03 13:41:53 -06:00
rm_downkey(key);
2023-02-08 15:30:12 -06:00
call_input_signal("input_any_released");
2022-08-12 14:03:56 -05:00
break;
case GLFW_REPEAT:
2022-12-22 16:58:06 -06:00
snprintf(keystr, 50, "input_%s_rep", kkey);
2023-03-17 10:25:35 -05:00
call_input_signal(keystr);
snprintf(keystr,50,"input_%s_pressrep", kkey);
call_input_signal(keystr);
2022-08-12 14:03:56 -05:00
break;
}
2022-02-06 10:14:57 -06:00
}
2021-11-30 21:29:18 -06:00
2022-02-06 10:14:57 -06:00
void cursor_hide()
{
glfwSetInputMode(mainwin->window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
2022-02-06 10:14:57 -06:00
}
2021-11-30 21:29:18 -06:00
2022-02-06 10:14:57 -06:00
void cursor_show()
{
glfwSetInputMode(mainwin->window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
2021-11-30 21:29:18 -06:00
2022-02-06 10:14:57 -06:00
int action_down(int scancode)
{
2022-08-26 09:19:17 -05:00
for (int i = 0; i < arrlen(downkeys); i++) {
if (downkeys[i] == scancode)
return 1;
}
return 0;
2021-11-30 21:29:18 -06:00
}
2022-08-12 14:03:56 -05:00
int action_up(int scancode)
{
2022-08-26 09:19:17 -05:00
int found = 0;
for (int i = 0; i < arrlen(downkeys); i++) {
if (downkeys[i] == scancode) {
found = 1;
break;
}
}
return !found;
}
int want_quit() {
return mquit;
}
void quit() {
YughInfo("Exiting game.");
mquit = 1;
}