42c14fae59
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
150 lines
5.4 KiB
C++
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
|