Files
fn_registry/cpp/functions/gamedev/input_unified.cpp
T

150 lines
5.4 KiB
C++

#include "input_unified.h"
namespace fn::input {
namespace {
constexpr float STICK_DEADZONE = 0.15f;
constexpr float STICK_MAX = 32767.0f;
float normalize_axis(int16_t v) {
float f = (float)v / STICK_MAX;
if (f > 1.0f) f = 1.0f;
if (f < -1.0f) f = -1.0f;
if (f > -STICK_DEADZONE && f < STICK_DEADZONE) return 0.0f;
return f;
}
// Set logical button + rising-edge flag if transitioning false->true.
void set_btn(bool& held, bool& pressed, bool down) {
if (down && !held) pressed = true;
held = down;
}
void apply_key(InputState& s, SDL_Keycode key, bool down) {
switch (key) {
case SDLK_A: case SDLK_LEFT: set_btn(s.left, s.left_pressed, down); break;
case SDLK_D: case SDLK_RIGHT: set_btn(s.right, s.right_pressed, down); break;
case SDLK_W: case SDLK_UP: set_btn(s.up, s.up_pressed, down); break;
case SDLK_S: case SDLK_DOWN: set_btn(s.down, s.down_pressed, down); break;
case SDLK_SPACE: set_btn(s.action_a, s.a_pressed, down); break;
case SDLK_RETURN: set_btn(s.start, s.start_pressed, down); break;
case SDLK_ESCAPE: set_btn(s.back, s.back_pressed, down); break;
default: break;
}
}
void apply_gpad_button(InputState& s, Uint8 button, bool down) {
switch (button) {
case SDL_GAMEPAD_BUTTON_DPAD_LEFT: set_btn(s.left, s.left_pressed, down); break;
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT: set_btn(s.right, s.right_pressed, down); break;
case SDL_GAMEPAD_BUTTON_DPAD_UP: set_btn(s.up, s.up_pressed, down); break;
case SDL_GAMEPAD_BUTTON_DPAD_DOWN: set_btn(s.down, s.down_pressed, down); break;
case SDL_GAMEPAD_BUTTON_SOUTH: set_btn(s.action_a, s.a_pressed, down); break;
case SDL_GAMEPAD_BUTTON_EAST: set_btn(s.action_b, s.b_pressed, down); break;
case SDL_GAMEPAD_BUTTON_WEST: set_btn(s.action_x, s.x_pressed, down); break;
case SDL_GAMEPAD_BUTTON_NORTH: set_btn(s.action_y, s.y_pressed, down); break;
case SDL_GAMEPAD_BUTTON_START: set_btn(s.start, s.start_pressed, down); break;
case SDL_GAMEPAD_BUTTON_BACK: set_btn(s.back, s.back_pressed, down); break;
default: break;
}
}
int find_touch_slot(InputState& s, int id) {
for (int i = 0; i < s.touch_count; ++i) {
if (s.touches[i].id == id) return i;
}
return -1;
}
} // namespace
void input_begin_frame(InputState& s) {
s.left_pressed = s.right_pressed = s.up_pressed = s.down_pressed = false;
s.a_pressed = s.b_pressed = s.x_pressed = s.y_pressed = false;
s.start_pressed = s.back_pressed = false;
s.m_left_pressed = s.m_right_pressed = false;
}
void input_process_event(InputState& s, const SDL_Event* e) {
if (!e) return;
switch (e->type) {
case SDL_EVENT_KEY_DOWN:
if (!e->key.repeat) apply_key(s, e->key.key, true);
break;
case SDL_EVENT_KEY_UP:
apply_key(s, e->key.key, false);
break;
case SDL_EVENT_MOUSE_MOTION:
s.mx = e->motion.x;
s.my = e->motion.y;
break;
case SDL_EVENT_MOUSE_BUTTON_DOWN:
if (e->button.button == SDL_BUTTON_LEFT) set_btn(s.m_left, s.m_left_pressed, true);
if (e->button.button == SDL_BUTTON_RIGHT) set_btn(s.m_right, s.m_right_pressed, true);
break;
case SDL_EVENT_MOUSE_BUTTON_UP:
if (e->button.button == SDL_BUTTON_LEFT) set_btn(s.m_left, s.m_left_pressed, false);
if (e->button.button == SDL_BUTTON_RIGHT) set_btn(s.m_right, s.m_right_pressed, false);
break;
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
apply_gpad_button(s, e->gbutton.button, true);
break;
case SDL_EVENT_GAMEPAD_BUTTON_UP:
apply_gpad_button(s, e->gbutton.button, false);
break;
case SDL_EVENT_GAMEPAD_AXIS_MOTION: {
float v = normalize_axis(e->gaxis.value);
switch (e->gaxis.axis) {
case SDL_GAMEPAD_AXIS_LEFTX: s.lx = v; break;
case SDL_GAMEPAD_AXIS_LEFTY: s.ly = v; break;
case SDL_GAMEPAD_AXIS_RIGHTX: s.rx = v; break;
case SDL_GAMEPAD_AXIS_RIGHTY: s.ry = v; break;
default: break;
}
break;
}
case SDL_EVENT_GAMEPAD_ADDED:
SDL_OpenGamepad(e->gdevice.which);
break;
case SDL_EVENT_FINGER_DOWN: {
if (s.touch_count < 8) {
auto& t = s.touches[s.touch_count++];
t.id = (int)e->tfinger.fingerID;
t.x = e->tfinger.x;
t.y = e->tfinger.y;
t.pressed = true;
}
break;
}
case SDL_EVENT_FINGER_MOTION: {
int idx = find_touch_slot(s, (int)e->tfinger.fingerID);
if (idx >= 0) {
s.touches[idx].x = e->tfinger.x;
s.touches[idx].y = e->tfinger.y;
}
break;
}
case SDL_EVENT_FINGER_UP: {
int idx = find_touch_slot(s, (int)e->tfinger.fingerID);
if (idx >= 0) {
// compact array
for (int i = idx; i < s.touch_count - 1; ++i) {
s.touches[i] = s.touches[i + 1];
}
s.touch_count--;
s.touches[s.touch_count] = {};
}
break;
}
default: break;
}
}
} // namespace fn::input