6#include <unordered_map>
16 std::array<bool, asw::input::NUM_CONTROLLER_BUTTONS> pressed {
false };
17 std::array<bool, asw::input::NUM_CONTROLLER_BUTTONS> released {
false };
18 std::array<bool, asw::input::NUM_CONTROLLER_BUTTONS> down {
false };
20 bool any_pressed {
false };
21 int last_pressed { -1 };
22 float dead_zone { 0.25F };
24 std::array<float, asw::input::NUM_CONTROLLER_AXES> axis { 0 };
26 SDL_Gamepad* gamepad {
nullptr };
32std::array<SDL_Cursor*, asw::input::NUM_CURSORS>
cursors {
nullptr };
58 if (magnitude <= dead_zone) {
62 return std::min((magnitude - dead_zone) / (1.0F - dead_zone), 1.0F);
75 cont.axis[
static_cast<int>(x_axis)], cont.axis[
static_cast<int>(y_axis)]);
76 const float magnitude = std::hypot(raw.
x, raw.
y);
80 return { 0.0F, 0.0F };
83 return raw * (scaled / magnitude);
93 case ControllerAxis::LeftX:
95 case ControllerAxis::LeftY:
97 case ControllerAxis::RightX:
99 case ControllerAxis::RightY:
102 const float value = cont.axis[
static_cast<int>(axis)];
126 any = action(cont) || any;
138 if (std::isnan(intensity)) {
142 return static_cast<uint16_t
>(std::clamp(intensity, 0.0F, 1.0F) * UINT16_MAX);
148 return SDL_GetBooleanProperty(SDL_GetGamepadProperties(cont.gamepad), property,
false);
156 if (
const char* serial = SDL_GetGamepadSerial(pad); serial !=
nullptr && *serial !=
'\0') {
157 return std::string(
"serial:") + serial;
160 std::array<char, 33> guid { };
161 SDL_GUIDToString(SDL_GetGamepadGUIDForID(
id), guid.data(),
static_cast<int>(guid.size()));
162 return std::string(
"guid:") + guid.data();
174 for (std::size_t i = 0; i <
slot_owner.size(); ++i) {
181 for (std::size_t i = 0; i <
controller.size(); ++i) {
186 for (std::size_t i = 0; i <
controller.size(); ++i) {
219 if (cursor !=
nullptr) {
220 SDL_DestroyCursor(cursor);
229 auto& m_state =
mouse;
232 k_state.any_pressed =
false;
233 k_state.last_pressed = -1;
235 for (
auto& pressed : k_state.pressed) {
239 for (
auto& released : k_state.released) {
243 for (
auto& repeated : k_state.repeated) {
248 m_state.any_pressed =
false;
249 m_state.last_pressed = -1;
250 m_state.change = { 0.0F, 0.0F };
253 for (
auto& pressed : m_state.pressed) {
257 for (
auto& released : m_state.released) {
266 cont.any_pressed =
false;
267 cont.last_pressed = -1;
269 for (
auto& button : cont.pressed) {
273 for (
auto& button : cont.released) {
284 const auto index =
static_cast<size_t>(button);
285 return index <
mouse.down.size() &&
mouse.down[index];
290 const auto index =
static_cast<size_t>(button);
291 return index <
mouse.pressed.size() &&
mouse.pressed[index];
296 const auto index =
static_cast<size_t>(button);
297 return index <
mouse.released.size() &&
mouse.released[index];
302 auto cursor_int =
static_cast<uint32_t
>(cursor);
304 if (cursor_int >=
cursors.size()) {
308 if (
cursors[cursor_int] ==
nullptr) {
309 cursors[cursor_int] = SDL_CreateSystemCursor(
static_cast<SDL_SystemCursor
>(cursor_int));
312 SDL_SetCursor(
cursors[cursor_int]);
329 return window !=
nullptr ? SDL_GetWindowID(window) : 0;
337 SDL_KeyboardEvent key_event { };
338 key_event.type = down ? SDL_EVENT_KEY_DOWN : SDL_EVENT_KEY_UP;
341 =
static_cast<SDL_Scancode
>(
static_cast<std::underlying_type_t<asw::input::Key>
>(key));
342 key_event.down = down;
351 SDL_MouseButtonEvent button_event { };
352 button_event.type = down ? SDL_EVENT_MOUSE_BUTTON_DOWN : SDL_EVENT_MOUSE_BUTTON_UP;
354 button_event.button =
static_cast<uint8_t
>(
355 static_cast<std::underlying_type_t<asw::input::MouseButton>
>(button));
356 button_event.down = down;
357 button_event.clicks = 1;
361 button_event.x =
mouse.position.x;
362 button_event.y =
mouse.position.y;
364 SDL_RenderCoordinatesToWindow(
365 renderer,
mouse.position.x,
mouse.position.y, &button_event.x, &button_event.y);
369 e.button = button_event;
388 auto window_pos = position;
389 auto window_prev =
mouse.position;
391 SDL_RenderCoordinatesToWindow(
392 renderer, position.
x, position.
y, &window_pos.x, &window_pos.y);
393 SDL_RenderCoordinatesToWindow(
394 renderer,
mouse.position.x,
mouse.position.y, &window_prev.x, &window_prev.y);
397 SDL_MouseMotionEvent motion { };
398 motion.type = SDL_EVENT_MOUSE_MOTION;
400 motion.x = window_pos.x;
401 motion.y = window_pos.y;
402 motion.xrel = window_pos.x - window_prev.x;
403 motion.yrel = window_pos.y - window_prev.y;
425 return keyboard.down[
static_cast<int>(key)];
430 return keyboard.pressed[
static_cast<int>(key)];
435 const auto index =
static_cast<int>(key);
441 return keyboard.released[
static_cast<int>(key)];
449 const auto b =
static_cast<int>(button);
455 const auto b =
static_cast<int>(button);
461 const auto b =
static_cast<int>(button);
471 float furthest = 0.0F;
473 const float value =
read_axis(cont, axis);
474 if (std::abs(value) > std::abs(furthest)) {
492 if (std::hypot(value.x, value.y) > std::hypot(furthest.
x, furthest.
y)) {
503 dead_zone = std::clamp(dead_zone, 0.0F, 0.99F);
509 cont.dead_zone = dead_zone;
522 uint32_t index,
float low_frequency,
float high_frequency, uint32_t duration_ms)
528 return SDL_RumbleGamepad(cont.gamepad, low, high, duration_ms);
533 uint32_t index,
float left,
float right, uint32_t duration_ms)
539 return SDL_RumbleGamepadTriggers(
540 cont.gamepad, left_intensity, right_intensity, duration_ms);
554 return has_capability(cont, SDL_PROP_GAMEPAD_CAP_TRIGGER_RUMBLE_BOOLEAN);
610 if (button >=
mouse.pressed.size()) {
614 const auto button_int =
static_cast<int>(button);
615 mouse.pressed[button_int] =
true;
616 mouse.down[button_int] =
true;
617 mouse.any_pressed =
true;
618 mouse.last_pressed = button_int;
624 if (button >=
mouse.released.size()) {
628 const auto button_int =
static_cast<int>(button);
629 mouse.released[button_int] =
true;
630 mouse.down[button_int] =
false;
635 mouse.position.x = x;
636 mouse.position.y = y;
638 mouse.change.x += delta_x;
639 mouse.change.y += delta_y;
650 if (!SDL_IsGamepad(
id)) {
655 auto* opened = SDL_OpenGamepad(
id);
656 if (opened ==
nullptr) {
663 const std::size_t index =
pick_slot(identity);
674 new_controller.gamepad = opened;
676 const char* name = SDL_GetGamepadName(opened);
677 new_controller.name = name !=
nullptr ? name :
"";
680 asw::log::info(
"Gamepad added: {} (ID: {}, index: {})", new_controller.name,
id, index);
691 const auto index = it->second;
712 const auto index = it->second;
717 controller[index].axis[axis] = value / 32768.0F;
731 const auto index = it->second;
750 const auto index = it->second;
Action binding system for the ASW library.
T y
The y component of the vector.
T x
The x component of the vector.
Display and window routines for the ASW library.
Structured logging system.
asw::Renderer * get_renderer()
Get the SDL renderer.
asw::Window * get_window()
Get the SDL window.
void info(const std::string &message)
Log an info message.
void warn(const std::string &message)
Log a warning message.