From 30f41c02aec763d32e62351452da9ef582bc3472 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 6 Mar 2026 13:30:59 -0800 Subject: Move contrib libraries to contrib repo --- contrib/SDL-3.2.8/test/gamepadutils.c | 2972 --------------------------------- 1 file changed, 2972 deletions(-) delete mode 100644 contrib/SDL-3.2.8/test/gamepadutils.c (limited to 'contrib/SDL-3.2.8/test/gamepadutils.c') diff --git a/contrib/SDL-3.2.8/test/gamepadutils.c b/contrib/SDL-3.2.8/test/gamepadutils.c deleted file mode 100644 index 910887f..0000000 --- a/contrib/SDL-3.2.8/test/gamepadutils.c +++ /dev/null @@ -1,2972 +0,0 @@ -/* - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely. -*/ -#include -#include - -#include "gamepadutils.h" -#include "gamepad_front.h" -#include "gamepad_back.h" -#include "gamepad_face_abxy.h" -#include "gamepad_face_bayx.h" -#include "gamepad_face_sony.h" -#include "gamepad_battery.h" -#include "gamepad_battery_wired.h" -#include "gamepad_touchpad.h" -#include "gamepad_button.h" -#include "gamepad_button_small.h" -#include "gamepad_axis.h" -#include "gamepad_axis_arrow.h" -#include "gamepad_button_background.h" -#include "gamepad_wired.h" -#include "gamepad_wireless.h" - - -/* This is indexed by gamepad element */ -static const struct -{ - int x; - int y; -} button_positions[] = { - { 413, 190 }, /* SDL_GAMEPAD_BUTTON_SOUTH */ - { 456, 156 }, /* SDL_GAMEPAD_BUTTON_EAST */ - { 372, 159 }, /* SDL_GAMEPAD_BUTTON_WEST */ - { 415, 127 }, /* SDL_GAMEPAD_BUTTON_NORTH */ - { 199, 157 }, /* SDL_GAMEPAD_BUTTON_BACK */ - { 257, 153 }, /* SDL_GAMEPAD_BUTTON_GUIDE */ - { 314, 157 }, /* SDL_GAMEPAD_BUTTON_START */ - { 98, 177 }, /* SDL_GAMEPAD_BUTTON_LEFT_STICK */ - { 331, 254 }, /* SDL_GAMEPAD_BUTTON_RIGHT_STICK */ - { 102, 65 }, /* SDL_GAMEPAD_BUTTON_LEFT_SHOULDER */ - { 421, 61 }, /* SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER */ - { 179, 213 }, /* SDL_GAMEPAD_BUTTON_DPAD_UP */ - { 179, 274 }, /* SDL_GAMEPAD_BUTTON_DPAD_DOWN */ - { 141, 242 }, /* SDL_GAMEPAD_BUTTON_DPAD_LEFT */ - { 211, 242 }, /* SDL_GAMEPAD_BUTTON_DPAD_RIGHT */ - { 257, 199 }, /* SDL_GAMEPAD_BUTTON_MISC1 */ - { 157, 160 }, /* SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1 */ - { 355, 160 }, /* SDL_GAMEPAD_BUTTON_LEFT_PADDLE1 */ - { 157, 200 }, /* SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2 */ - { 355, 200 }, /* SDL_GAMEPAD_BUTTON_LEFT_PADDLE2 */ -}; - -/* This is indexed by gamepad element */ -static const struct -{ - int x; - int y; - double angle; -} axis_positions[] = { - { 99, 178, 270.0 }, /* SDL_GAMEPAD_ELEMENT_AXIS_LEFTX_NEGATIVE */ - { 99, 178, 90.0 }, /* SDL_GAMEPAD_ELEMENT_AXIS_LEFTX_POSITIVE */ - { 99, 178, 0.0 }, /* SDL_GAMEPAD_ELEMENT_AXIS_LEFTY_NEGATIVE */ - { 99, 178, 180.0 }, /* SDL_GAMEPAD_ELEMENT_AXIS_LEFTY_POSITIVE */ - { 331, 256, 270.0 }, /* SDL_GAMEPAD_ELEMENT_AXIS_RIGHTX_NEGATIVE */ - { 331, 256, 90.0 }, /* SDL_GAMEPAD_ELEMENT_AXIS_RIGHTX_POSITIVE */ - { 331, 256, 0.0 }, /* SDL_GAMEPAD_ELEMENT_AXIS_RIGHTY_NEGATIVE */ - { 331, 256, 180.0 }, /* SDL_GAMEPAD_ELEMENT_AXIS_RIGHTY_POSITIVE */ - { 116, 5, 180.0 }, /* SDL_GAMEPAD_ELEMENT_AXIS_LEFT_TRIGGER */ - { 400, 5, 180.0 }, /* SDL_GAMEPAD_ELEMENT_AXIS_RIGHT_TRIGGER */ -}; - -static SDL_FRect touchpad_area = { - 148.0f, 20.0f, 216.0f, 118.0f -}; - -typedef struct -{ - bool down; - float x; - float y; - float pressure; -} GamepadTouchpadFinger; - -struct GamepadImage -{ - SDL_Renderer *renderer; - SDL_Texture *front_texture; - SDL_Texture *back_texture; - SDL_Texture *face_abxy_texture; - SDL_Texture *face_bayx_texture; - SDL_Texture *face_sony_texture; - SDL_Texture *connection_texture[2]; - SDL_Texture *battery_texture[2]; - SDL_Texture *touchpad_texture; - SDL_Texture *button_texture; - SDL_Texture *axis_texture; - float gamepad_width; - float gamepad_height; - float face_width; - float face_height; - float connection_width; - float connection_height; - float battery_width; - float battery_height; - float touchpad_width; - float touchpad_height; - float button_width; - float button_height; - float axis_width; - float axis_height; - - float x; - float y; - bool showing_front; - bool showing_touchpad; - SDL_GamepadType type; - ControllerDisplayMode display_mode; - - bool elements[SDL_GAMEPAD_ELEMENT_MAX]; - - SDL_JoystickConnectionState connection_state; - SDL_PowerState battery_state; - int battery_percent; - - int num_fingers; - GamepadTouchpadFinger *fingers; -}; - -static SDL_Texture *CreateTexture(SDL_Renderer *renderer, unsigned char *data, unsigned int len) -{ - SDL_Texture *texture = NULL; - SDL_Surface *surface; - SDL_IOStream *src = SDL_IOFromConstMem(data, len); - if (src) { - surface = SDL_LoadBMP_IO(src, true); - if (surface) { - texture = SDL_CreateTextureFromSurface(renderer, surface); - SDL_DestroySurface(surface); - } - } - return texture; -} - -GamepadImage *CreateGamepadImage(SDL_Renderer *renderer) -{ - GamepadImage *ctx = SDL_calloc(1, sizeof(*ctx)); - if (ctx) { - ctx->renderer = renderer; - ctx->front_texture = CreateTexture(renderer, gamepad_front_bmp, gamepad_front_bmp_len); - ctx->back_texture = CreateTexture(renderer, gamepad_back_bmp, gamepad_back_bmp_len); - SDL_GetTextureSize(ctx->front_texture, &ctx->gamepad_width, &ctx->gamepad_height); - - ctx->face_abxy_texture = CreateTexture(renderer, gamepad_face_abxy_bmp, gamepad_face_abxy_bmp_len); - ctx->face_bayx_texture = CreateTexture(renderer, gamepad_face_bayx_bmp, gamepad_face_bayx_bmp_len); - ctx->face_sony_texture = CreateTexture(renderer, gamepad_face_sony_bmp, gamepad_face_sony_bmp_len); - SDL_GetTextureSize(ctx->face_abxy_texture, &ctx->face_width, &ctx->face_height); - - ctx->connection_texture[0] = CreateTexture(renderer, gamepad_wired_bmp, gamepad_wired_bmp_len); - ctx->connection_texture[1] = CreateTexture(renderer, gamepad_wireless_bmp, gamepad_wireless_bmp_len); - SDL_GetTextureSize(ctx->connection_texture[0], &ctx->connection_width, &ctx->connection_height); - - ctx->battery_texture[0] = CreateTexture(renderer, gamepad_battery_bmp, gamepad_battery_bmp_len); - ctx->battery_texture[1] = CreateTexture(renderer, gamepad_battery_wired_bmp, gamepad_battery_wired_bmp_len); - SDL_GetTextureSize(ctx->battery_texture[0], &ctx->battery_width, &ctx->battery_height); - - ctx->touchpad_texture = CreateTexture(renderer, gamepad_touchpad_bmp, gamepad_touchpad_bmp_len); - SDL_GetTextureSize(ctx->touchpad_texture, &ctx->touchpad_width, &ctx->touchpad_height); - - ctx->button_texture = CreateTexture(renderer, gamepad_button_bmp, gamepad_button_bmp_len); - SDL_GetTextureSize(ctx->button_texture, &ctx->button_width, &ctx->button_height); - SDL_SetTextureColorMod(ctx->button_texture, 10, 255, 21); - - ctx->axis_texture = CreateTexture(renderer, gamepad_axis_bmp, gamepad_axis_bmp_len); - SDL_GetTextureSize(ctx->axis_texture, &ctx->axis_width, &ctx->axis_height); - SDL_SetTextureColorMod(ctx->axis_texture, 10, 255, 21); - - ctx->showing_front = true; - } - return ctx; -} - -void SetGamepadImagePosition(GamepadImage *ctx, float x, float y) -{ - if (!ctx) { - return; - } - - ctx->x = x; - ctx->y = y; -} - -void GetGamepadImageArea(GamepadImage *ctx, SDL_FRect *area) -{ - if (!ctx) { - SDL_zerop(area); - return; - } - - area->x = ctx->x; - area->y = ctx->y; - area->w = ctx->gamepad_width; - area->h = ctx->gamepad_height; - if (ctx->showing_touchpad) { - area->h += ctx->touchpad_height; - } -} - -void GetGamepadTouchpadArea(GamepadImage *ctx, SDL_FRect *area) -{ - if (!ctx) { - SDL_zerop(area); - return; - } - - area->x = ctx->x + (ctx->gamepad_width - ctx->touchpad_width) / 2 + touchpad_area.x; - area->y = ctx->y + ctx->gamepad_height + touchpad_area.y; - area->w = touchpad_area.w; - area->h = touchpad_area.h; -} - -void SetGamepadImageShowingFront(GamepadImage *ctx, bool showing_front) -{ - if (!ctx) { - return; - } - - ctx->showing_front = showing_front; -} - -SDL_GamepadType GetGamepadImageType(GamepadImage *ctx) -{ - if (!ctx) { - return SDL_GAMEPAD_TYPE_UNKNOWN; - } - - return ctx->type; -} - -void SetGamepadImageDisplayMode(GamepadImage *ctx, ControllerDisplayMode display_mode) -{ - if (!ctx) { - return; - } - - ctx->display_mode = display_mode; -} - -float GetGamepadImageButtonWidth(GamepadImage *ctx) -{ - if (!ctx) { - return 0; - } - - return ctx->button_width; -} - -float GetGamepadImageButtonHeight(GamepadImage *ctx) -{ - if (!ctx) { - return 0; - } - - return ctx->button_height; -} - -float GetGamepadImageAxisWidth(GamepadImage *ctx) -{ - if (!ctx) { - return 0; - } - - return ctx->axis_width; -} - -float GetGamepadImageAxisHeight(GamepadImage *ctx) -{ - if (!ctx) { - return 0; - } - - return ctx->axis_height; -} - -int GetGamepadImageElementAt(GamepadImage *ctx, float x, float y) -{ - SDL_FPoint point; - int i; - - if (!ctx) { - return SDL_GAMEPAD_ELEMENT_INVALID; - } - - point.x = x; - point.y = y; - - if (ctx->showing_front) { - for (i = 0; i < SDL_arraysize(axis_positions); ++i) { - const int element = SDL_GAMEPAD_BUTTON_COUNT + i; - SDL_FRect rect; - - if (element == SDL_GAMEPAD_ELEMENT_AXIS_LEFT_TRIGGER || - element == SDL_GAMEPAD_ELEMENT_AXIS_RIGHT_TRIGGER) { - rect.w = ctx->axis_width; - rect.h = ctx->axis_height; - rect.x = ctx->x + axis_positions[i].x - rect.w / 2; - rect.y = ctx->y + axis_positions[i].y - rect.h / 2; - if (SDL_PointInRectFloat(&point, &rect)) { - if (element == SDL_GAMEPAD_ELEMENT_AXIS_LEFT_TRIGGER) { - return SDL_GAMEPAD_ELEMENT_AXIS_LEFT_TRIGGER; - } else { - return SDL_GAMEPAD_ELEMENT_AXIS_RIGHT_TRIGGER; - } - } - } else if (element == SDL_GAMEPAD_ELEMENT_AXIS_LEFTX_POSITIVE) { - rect.w = ctx->button_width * 2.0f; - rect.h = ctx->button_height * 2.0f; - rect.x = ctx->x + button_positions[SDL_GAMEPAD_BUTTON_LEFT_STICK].x - rect.w / 2; - rect.y = ctx->y + button_positions[SDL_GAMEPAD_BUTTON_LEFT_STICK].y - rect.h / 2; - if (SDL_PointInRectFloat(&point, &rect)) { - float delta_x, delta_y; - float delta_squared; - float thumbstick_radius = ctx->button_width * 0.1f; - - delta_x = (x - (ctx->x + button_positions[SDL_GAMEPAD_BUTTON_LEFT_STICK].x)); - delta_y = (y - (ctx->y + button_positions[SDL_GAMEPAD_BUTTON_LEFT_STICK].y)); - delta_squared = (delta_x * delta_x) + (delta_y * delta_y); - if (delta_squared > (thumbstick_radius * thumbstick_radius)) { - float angle = SDL_atan2f(delta_y, delta_x) + SDL_PI_F; - if (angle < SDL_PI_F * 0.25f) { - return SDL_GAMEPAD_ELEMENT_AXIS_LEFTX_NEGATIVE; - } else if (angle < SDL_PI_F * 0.75f) { - return SDL_GAMEPAD_ELEMENT_AXIS_LEFTY_NEGATIVE; - } else if (angle < SDL_PI_F * 1.25f) { - return SDL_GAMEPAD_ELEMENT_AXIS_LEFTX_POSITIVE; - } else if (angle < SDL_PI_F * 1.75f) { - return SDL_GAMEPAD_ELEMENT_AXIS_LEFTY_POSITIVE; - } else { - return SDL_GAMEPAD_ELEMENT_AXIS_LEFTX_NEGATIVE; - } - } - } - } else if (element == SDL_GAMEPAD_ELEMENT_AXIS_RIGHTX_POSITIVE) { - rect.w = ctx->button_width * 2.0f; - rect.h = ctx->button_height * 2.0f; - rect.x = ctx->x + button_positions[SDL_GAMEPAD_BUTTON_RIGHT_STICK].x - rect.w / 2; - rect.y = ctx->y + button_positions[SDL_GAMEPAD_BUTTON_RIGHT_STICK].y - rect.h / 2; - if (SDL_PointInRectFloat(&point, &rect)) { - float delta_x, delta_y; - float delta_squared; - float thumbstick_radius = ctx->button_width * 0.1f; - - delta_x = (x - (ctx->x + button_positions[SDL_GAMEPAD_BUTTON_RIGHT_STICK].x)); - delta_y = (y - (ctx->y + button_positions[SDL_GAMEPAD_BUTTON_RIGHT_STICK].y)); - delta_squared = (delta_x * delta_x) + (delta_y * delta_y); - if (delta_squared > (thumbstick_radius * thumbstick_radius)) { - float angle = SDL_atan2f(delta_y, delta_x) + SDL_PI_F; - if (angle < SDL_PI_F * 0.25f) { - return SDL_GAMEPAD_ELEMENT_AXIS_RIGHTX_NEGATIVE; - } else if (angle < SDL_PI_F * 0.75f) { - return SDL_GAMEPAD_ELEMENT_AXIS_RIGHTY_NEGATIVE; - } else if (angle < SDL_PI_F * 1.25f) { - return SDL_GAMEPAD_ELEMENT_AXIS_RIGHTX_POSITIVE; - } else if (angle < SDL_PI_F * 1.75f) { - return SDL_GAMEPAD_ELEMENT_AXIS_RIGHTY_POSITIVE; - } else { - return SDL_GAMEPAD_ELEMENT_AXIS_RIGHTX_NEGATIVE; - } - } - } - } - } - } - - for (i = 0; i < SDL_arraysize(button_positions); ++i) { - bool on_front = true; - - if (i >= SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1 && i <= SDL_GAMEPAD_BUTTON_LEFT_PADDLE2) { - on_front = false; - } - if (on_front == ctx->showing_front) { - SDL_FRect rect; - rect.x = ctx->x + button_positions[i].x - ctx->button_width / 2; - rect.y = ctx->y + button_positions[i].y - ctx->button_height / 2; - rect.w = ctx->button_width; - rect.h = ctx->button_height; - if (SDL_PointInRectFloat(&point, &rect)) { - return (SDL_GamepadButton)i; - } - } - } - return SDL_GAMEPAD_ELEMENT_INVALID; -} - -void ClearGamepadImage(GamepadImage *ctx) -{ - if (!ctx) { - return; - } - - SDL_zeroa(ctx->elements); -} - -void SetGamepadImageElement(GamepadImage *ctx, int element, bool active) -{ - if (!ctx) { - return; - } - - ctx->elements[element] = active; -} - -void UpdateGamepadImageFromGamepad(GamepadImage *ctx, SDL_Gamepad *gamepad) -{ - int i; - - if (!ctx) { - return; - } - - ctx->type = SDL_GetGamepadType(gamepad); - char *mapping = SDL_GetGamepadMapping(gamepad); - if (mapping) { - if (SDL_strstr(mapping, "SDL_GAMECONTROLLER_USE_BUTTON_LABELS")) { - /* Just for display purposes */ - ctx->type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO; - } - SDL_free(mapping); - } - - for (i = 0; i < SDL_GAMEPAD_BUTTON_TOUCHPAD; ++i) { - const SDL_GamepadButton button = (SDL_GamepadButton)i; - - SetGamepadImageElement(ctx, button, SDL_GetGamepadButton(gamepad, button)); - } - - for (i = 0; i < SDL_GAMEPAD_AXIS_COUNT; ++i) { - const SDL_GamepadAxis axis = (SDL_GamepadAxis)i; - const Sint16 deadzone = 8000; /* !!! FIXME: real deadzone */ - const Sint16 value = SDL_GetGamepadAxis(gamepad, axis); - switch (i) { - case SDL_GAMEPAD_AXIS_LEFTX: - SetGamepadImageElement(ctx, SDL_GAMEPAD_ELEMENT_AXIS_LEFTX_NEGATIVE, (value < -deadzone)); - SetGamepadImageElement(ctx, SDL_GAMEPAD_ELEMENT_AXIS_LEFTX_POSITIVE, (value > deadzone)); - break; - case SDL_GAMEPAD_AXIS_RIGHTX: - SetGamepadImageElement(ctx, SDL_GAMEPAD_ELEMENT_AXIS_RIGHTX_NEGATIVE, (value < -deadzone)); - SetGamepadImageElement(ctx, SDL_GAMEPAD_ELEMENT_AXIS_RIGHTX_POSITIVE, (value > deadzone)); - break; - case SDL_GAMEPAD_AXIS_LEFTY: - SetGamepadImageElement(ctx, SDL_GAMEPAD_ELEMENT_AXIS_LEFTY_NEGATIVE, (value < -deadzone)); - SetGamepadImageElement(ctx, SDL_GAMEPAD_ELEMENT_AXIS_LEFTY_POSITIVE, (value > deadzone)); - break; - case SDL_GAMEPAD_AXIS_RIGHTY: - SetGamepadImageElement(ctx, SDL_GAMEPAD_ELEMENT_AXIS_RIGHTY_NEGATIVE, (value < -deadzone)); - SetGamepadImageElement(ctx, SDL_GAMEPAD_ELEMENT_AXIS_RIGHTY_POSITIVE, (value > deadzone)); - break; - case SDL_GAMEPAD_AXIS_LEFT_TRIGGER: - SetGamepadImageElement(ctx, SDL_GAMEPAD_ELEMENT_AXIS_LEFT_TRIGGER, (value > deadzone)); - break; - case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER: - SetGamepadImageElement(ctx, SDL_GAMEPAD_ELEMENT_AXIS_RIGHT_TRIGGER, (value > deadzone)); - break; - default: - break; - } - } - - ctx->connection_state = SDL_GetGamepadConnectionState(gamepad); - ctx->battery_state = SDL_GetGamepadPowerInfo(gamepad, &ctx->battery_percent); - - if (SDL_GetNumGamepadTouchpads(gamepad) > 0) { - int num_fingers = SDL_GetNumGamepadTouchpadFingers(gamepad, 0); - if (num_fingers != ctx->num_fingers) { - GamepadTouchpadFinger *fingers = (GamepadTouchpadFinger *)SDL_realloc(ctx->fingers, num_fingers * sizeof(*fingers)); - if (fingers) { - ctx->fingers = fingers; - ctx->num_fingers = num_fingers; - } else { - num_fingers = SDL_min(ctx->num_fingers, num_fingers); - } - } - for (i = 0; i < num_fingers; ++i) { - GamepadTouchpadFinger *finger = &ctx->fingers[i]; - - SDL_GetGamepadTouchpadFinger(gamepad, 0, i, &finger->down, &finger->x, &finger->y, &finger->pressure); - } - ctx->showing_touchpad = true; - } else { - if (ctx->fingers) { - SDL_free(ctx->fingers); - ctx->fingers = NULL; - ctx->num_fingers = 0; - } - ctx->showing_touchpad = false; - } -} - -void RenderGamepadImage(GamepadImage *ctx) -{ - SDL_FRect dst; - int i; - - if (!ctx) { - return; - } - - dst.x = ctx->x; - dst.y = ctx->y; - dst.w = ctx->gamepad_width; - dst.h = ctx->gamepad_height; - - if (ctx->showing_front) { - SDL_RenderTexture(ctx->renderer, ctx->front_texture, NULL, &dst); - } else { - SDL_RenderTexture(ctx->renderer, ctx->back_texture, NULL, &dst); - } - - for (i = 0; i < SDL_arraysize(button_positions); ++i) { - if (ctx->elements[i]) { - SDL_GamepadButton button_position = (SDL_GamepadButton)i; - bool on_front = true; - - if (i >= SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1 && i <= SDL_GAMEPAD_BUTTON_LEFT_PADDLE2) { - on_front = false; - } - if (on_front == ctx->showing_front) { - dst.w = ctx->button_width; - dst.h = ctx->button_height; - dst.x = ctx->x + button_positions[button_position].x - dst.w / 2; - dst.y = ctx->y + button_positions[button_position].y - dst.h / 2; - SDL_RenderTexture(ctx->renderer, ctx->button_texture, NULL, &dst); - } - } - } - - if (ctx->showing_front) { - dst.x = ctx->x + 363; - dst.y = ctx->y + 118; - dst.w = ctx->face_width; - dst.h = ctx->face_height; - - switch (SDL_GetGamepadButtonLabelForType(ctx->type, SDL_GAMEPAD_BUTTON_SOUTH)) { - case SDL_GAMEPAD_BUTTON_LABEL_A: - SDL_RenderTexture(ctx->renderer, ctx->face_abxy_texture, NULL, &dst); - break; - case SDL_GAMEPAD_BUTTON_LABEL_B: - SDL_RenderTexture(ctx->renderer, ctx->face_bayx_texture, NULL, &dst); - break; - case SDL_GAMEPAD_BUTTON_LABEL_CROSS: - SDL_RenderTexture(ctx->renderer, ctx->face_sony_texture, NULL, &dst); - break; - default: - break; - } - } - - if (ctx->showing_front) { - for (i = 0; i < SDL_arraysize(axis_positions); ++i) { - const int element = SDL_GAMEPAD_BUTTON_COUNT + i; - if (ctx->elements[element]) { - const double angle = axis_positions[i].angle; - dst.w = ctx->axis_width; - dst.h = ctx->axis_height; - dst.x = ctx->x + axis_positions[i].x - dst.w / 2; - dst.y = ctx->y + axis_positions[i].y - dst.h / 2; - SDL_RenderTextureRotated(ctx->renderer, ctx->axis_texture, NULL, &dst, angle, NULL, SDL_FLIP_NONE); - } - } - } - - if (ctx->display_mode == CONTROLLER_MODE_TESTING) { - dst.x = ctx->x + ctx->gamepad_width - ctx->battery_width - 4 - ctx->connection_width; - dst.y = ctx->y; - dst.w = ctx->connection_width; - dst.h = ctx->connection_height; - - switch (ctx->connection_state) { - case SDL_JOYSTICK_CONNECTION_WIRED: - SDL_RenderTexture(ctx->renderer, ctx->connection_texture[0], NULL, &dst); - break; - case SDL_JOYSTICK_CONNECTION_WIRELESS: - SDL_RenderTexture(ctx->renderer, ctx->connection_texture[1], NULL, &dst); - break; - default: - break; - } - } - - if (ctx->display_mode == CONTROLLER_MODE_TESTING && - ctx->battery_state != SDL_POWERSTATE_NO_BATTERY && - ctx->battery_state != SDL_POWERSTATE_UNKNOWN) { - Uint8 r, g, b, a; - SDL_FRect fill; - - dst.x = ctx->x + ctx->gamepad_width - ctx->battery_width; - dst.y = ctx->y; - dst.w = ctx->battery_width; - dst.h = ctx->battery_height; - - SDL_GetRenderDrawColor(ctx->renderer, &r, &g, &b, &a); - if (ctx->battery_percent > 40) { - SDL_SetRenderDrawColor(ctx->renderer, 0x00, 0xD4, 0x50, 0xFF); - } else if (ctx->battery_percent > 10) { - SDL_SetRenderDrawColor(ctx->renderer, 0xFF, 0xC7, 0x00, 0xFF); - } else { - SDL_SetRenderDrawColor(ctx->renderer, 0xC8, 0x1D, 0x13, 0xFF); - } - - fill = dst; - fill.x += 2; - fill.y += 2; - fill.h -= 4; - fill.w = 25.0f * (ctx->battery_percent / 100.0f); - SDL_RenderFillRect(ctx->renderer, &fill); - SDL_SetRenderDrawColor(ctx->renderer, r, g, b, a); - - if (ctx->battery_state == SDL_POWERSTATE_ON_BATTERY) { - SDL_RenderTexture(ctx->renderer, ctx->battery_texture[0], NULL, &dst); - } else { - SDL_RenderTexture(ctx->renderer, ctx->battery_texture[1], NULL, &dst); - } - } - - if (ctx->display_mode == CONTROLLER_MODE_TESTING && ctx->showing_touchpad) { - dst.x = ctx->x + (ctx->gamepad_width - ctx->touchpad_width) / 2; - dst.y = ctx->y + ctx->gamepad_height; - dst.w = ctx->touchpad_width; - dst.h = ctx->touchpad_height; - SDL_RenderTexture(ctx->renderer, ctx->touchpad_texture, NULL, &dst); - - for (i = 0; i < ctx->num_fingers; ++i) { - GamepadTouchpadFinger *finger = &ctx->fingers[i]; - - if (finger->down) { - dst.x = ctx->x + (ctx->gamepad_width - ctx->touchpad_width) / 2; - dst.x += touchpad_area.x + finger->x * touchpad_area.w; - dst.x -= ctx->button_width / 2; - dst.y = ctx->y + ctx->gamepad_height; - dst.y += touchpad_area.y + finger->y * touchpad_area.h; - dst.y -= ctx->button_height / 2; - dst.w = ctx->button_width; - dst.h = ctx->button_height; - SDL_SetTextureAlphaMod(ctx->button_texture, (Uint8)(finger->pressure * SDL_ALPHA_OPAQUE)); - SDL_RenderTexture(ctx->renderer, ctx->button_texture, NULL, &dst); - SDL_SetTextureAlphaMod(ctx->button_texture, SDL_ALPHA_OPAQUE); - } - } - } -} - -void DestroyGamepadImage(GamepadImage *ctx) -{ - if (ctx) { - int i; - - SDL_DestroyTexture(ctx->front_texture); - SDL_DestroyTexture(ctx->back_texture); - SDL_DestroyTexture(ctx->face_abxy_texture); - SDL_DestroyTexture(ctx->face_bayx_texture); - SDL_DestroyTexture(ctx->face_sony_texture); - for (i = 0; i < SDL_arraysize(ctx->battery_texture); ++i) { - SDL_DestroyTexture(ctx->battery_texture[i]); - } - SDL_DestroyTexture(ctx->touchpad_texture); - SDL_DestroyTexture(ctx->button_texture); - SDL_DestroyTexture(ctx->axis_texture); - SDL_free(ctx); - } -} - - -static const char *gamepad_button_names[] = { - "South", - "East", - "West", - "North", - "Back", - "Guide", - "Start", - "Left Stick", - "Right Stick", - "Left Shoulder", - "Right Shoulder", - "DPAD Up", - "DPAD Down", - "DPAD Left", - "DPAD Right", - "Misc1", - "Right Paddle 1", - "Left Paddle 1", - "Right Paddle 2", - "Left Paddle 2", - "Touchpad", - "Misc2", - "Misc3", - "Misc4", - "Misc5", - "Misc6", -}; -SDL_COMPILE_TIME_ASSERT(gamepad_button_names, SDL_arraysize(gamepad_button_names) == SDL_GAMEPAD_BUTTON_COUNT); - -static const char *gamepad_axis_names[] = { - "LeftX", - "LeftY", - "RightX", - "RightY", - "Left Trigger", - "Right Trigger", -}; -SDL_COMPILE_TIME_ASSERT(gamepad_axis_names, SDL_arraysize(gamepad_axis_names) == SDL_GAMEPAD_AXIS_COUNT); - -struct GamepadDisplay -{ - SDL_Renderer *renderer; - SDL_Texture *button_texture; - SDL_Texture *arrow_texture; - float button_width; - float button_height; - float arrow_width; - float arrow_height; - - float accel_data[3]; - float gyro_data[3]; - Uint64 last_sensor_update; - - ControllerDisplayMode display_mode; - int element_highlighted; - bool element_pressed; - int element_selected; - - SDL_FRect area; -}; - -GamepadDisplay *CreateGamepadDisplay(SDL_Renderer *renderer) -{ - GamepadDisplay *ctx = SDL_calloc(1, sizeof(*ctx)); - if (ctx) { - ctx->renderer = renderer; - - ctx->button_texture = CreateTexture(renderer, gamepad_button_small_bmp, gamepad_button_small_bmp_len); - SDL_GetTextureSize(ctx->button_texture, &ctx->button_width, &ctx->button_height); - - ctx->arrow_texture = CreateTexture(renderer, gamepad_axis_arrow_bmp, gamepad_axis_arrow_bmp_len); - SDL_GetTextureSize(ctx->arrow_texture, &ctx->arrow_width, &ctx->arrow_height); - - ctx->element_highlighted = SDL_GAMEPAD_ELEMENT_INVALID; - ctx->element_selected = SDL_GAMEPAD_ELEMENT_INVALID; - } - return ctx; -} - -void SetGamepadDisplayDisplayMode(GamepadDisplay *ctx, ControllerDisplayMode display_mode) -{ - if (!ctx) { - return; - } - - ctx->display_mode = display_mode; -} - -void SetGamepadDisplayArea(GamepadDisplay *ctx, const SDL_FRect *area) -{ - if (!ctx) { - return; - } - - SDL_copyp(&ctx->area, area); -} - -static bool GetBindingString(const char *label, const char *mapping, char *text, size_t size) -{ - char *key; - char *value, *end; - size_t length; - bool found = false; - - *text = '\0'; - - if (!mapping) { - return false; - } - - key = SDL_strstr(mapping, label); - while (key && size > 1) { - if (found) { - *text++ = ','; - *text = '\0'; - --size; - } else { - found = true; - } - value = key + SDL_strlen(label); - end = SDL_strchr(value, ','); - if (end) { - length = (end - value); - } else { - length = SDL_strlen(value); - } - if (length >= size) { - length = size - 1; - } - SDL_memcpy(text, value, length); - text[length] = '\0'; - text += length; - size -= length; - key = SDL_strstr(value, label); - } - return found; -} - -static bool GetButtonBindingString(SDL_GamepadButton button, const char *mapping, char *text, size_t size) -{ - char label[32]; - bool baxy_mapping = false; - - if (!mapping) { - return false; - } - - SDL_snprintf(label, sizeof(label), ",%s:", SDL_GetGamepadStringForButton(button)); - if (GetBindingString(label, mapping, text, size)) { - return true; - } - - /* Try the legacy button names */ - if (SDL_strstr(mapping, ",hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1") != NULL) { - baxy_mapping = true; - } - switch (button) { - case SDL_GAMEPAD_BUTTON_SOUTH: - if (baxy_mapping) { - return GetBindingString(",b:", mapping, text, size); - } else { - return GetBindingString(",a:", mapping, text, size); - } - case SDL_GAMEPAD_BUTTON_EAST: - if (baxy_mapping) { - return GetBindingString(",a:", mapping, text, size); - } else { - return GetBindingString(",b:", mapping, text, size); - } - case SDL_GAMEPAD_BUTTON_WEST: - if (baxy_mapping) { - return GetBindingString(",y:", mapping, text, size); - } else { - return GetBindingString(",x:", mapping, text, size); - } - case SDL_GAMEPAD_BUTTON_NORTH: - if (baxy_mapping) { - return GetBindingString(",x:", mapping, text, size); - } else { - return GetBindingString(",y:", mapping, text, size); - } - default: - return false; - } -} - -static bool GetAxisBindingString(SDL_GamepadAxis axis, int direction, const char *mapping, char *text, size_t size) -{ - char label[32]; - - /* Check for explicit half-axis */ - if (direction < 0) { - SDL_snprintf(label, sizeof(label), ",-%s:", SDL_GetGamepadStringForAxis(axis)); - } else { - SDL_snprintf(label, sizeof(label), ",+%s:", SDL_GetGamepadStringForAxis(axis)); - } - if (GetBindingString(label, mapping, text, size)) { - return true; - } - - /* Get the binding for the whole axis and split it if necessary */ - SDL_snprintf(label, sizeof(label), ",%s:", SDL_GetGamepadStringForAxis(axis)); - if (!GetBindingString(label, mapping, text, size)) { - return false; - } - if (axis != SDL_GAMEPAD_AXIS_LEFT_TRIGGER && axis != SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) { - if (*text == 'a') { - /* Split the axis */ - size_t length = SDL_strlen(text) + 1; - if ((length + 1) <= size) { - SDL_memmove(text + 1, text, length); - if (text[SDL_strlen(text) - 1] == '~') { - direction *= -1; - text[SDL_strlen(text) - 1] = '\0'; - } - if (direction > 0) { - *text = '+'; - } else { - *text = '-'; - } - } - } - } - return true; -} - -void SetGamepadDisplayHighlight(GamepadDisplay *ctx, int element, bool pressed) -{ - if (!ctx) { - return; - } - - ctx->element_highlighted = element; - ctx->element_pressed = pressed; -} - -void SetGamepadDisplaySelected(GamepadDisplay *ctx, int element) -{ - if (!ctx) { - return; - } - - ctx->element_selected = element; -} - -int GetGamepadDisplayElementAt(GamepadDisplay *ctx, SDL_Gamepad *gamepad, float x, float y) -{ - int i; - const float margin = 8.0f; - const float center = ctx->area.w / 2.0f; - const float arrow_extent = 48.0f; - SDL_FPoint point; - SDL_FRect rect; - - if (!ctx) { - return SDL_GAMEPAD_ELEMENT_INVALID; - } - - point.x = x; - point.y = y; - - rect.x = ctx->area.x + margin; - rect.y = ctx->area.y + margin + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2; - rect.w = ctx->area.w - (margin * 2); - rect.h = ctx->button_height; - - for (i = 0; i < SDL_GAMEPAD_BUTTON_COUNT; ++i) { - SDL_GamepadButton button = (SDL_GamepadButton)i; - - if (ctx->display_mode == CONTROLLER_MODE_TESTING && - !SDL_GamepadHasButton(gamepad, button)) { - continue; - } - - - if (SDL_PointInRectFloat(&point, &rect)) { - return i; - } - - rect.y += ctx->button_height + 2.0f; - } - - for (i = 0; i < SDL_GAMEPAD_AXIS_COUNT; ++i) { - SDL_GamepadAxis axis = (SDL_GamepadAxis)i; - SDL_FRect area; - - if (ctx->display_mode == CONTROLLER_MODE_TESTING && - !SDL_GamepadHasAxis(gamepad, axis)) { - continue; - } - - area.x = rect.x + center + 2.0f; - area.y = rect.y + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2; - area.w = ctx->arrow_width + arrow_extent; - area.h = ctx->button_height; - - if (SDL_PointInRectFloat(&point, &area)) { - switch (axis) { - case SDL_GAMEPAD_AXIS_LEFTX: - return SDL_GAMEPAD_ELEMENT_AXIS_LEFTX_NEGATIVE; - case SDL_GAMEPAD_AXIS_LEFTY: - return SDL_GAMEPAD_ELEMENT_AXIS_LEFTY_NEGATIVE; - case SDL_GAMEPAD_AXIS_RIGHTX: - return SDL_GAMEPAD_ELEMENT_AXIS_RIGHTX_NEGATIVE; - case SDL_GAMEPAD_AXIS_RIGHTY: - return SDL_GAMEPAD_ELEMENT_AXIS_RIGHTY_NEGATIVE; - default: - break; - } - } - - area.x += area.w; - - if (SDL_PointInRectFloat(&point, &area)) { - switch (axis) { - case SDL_GAMEPAD_AXIS_LEFTX: - return SDL_GAMEPAD_ELEMENT_AXIS_LEFTX_POSITIVE; - case SDL_GAMEPAD_AXIS_LEFTY: - return SDL_GAMEPAD_ELEMENT_AXIS_LEFTY_POSITIVE; - case SDL_GAMEPAD_AXIS_RIGHTX: - return SDL_GAMEPAD_ELEMENT_AXIS_RIGHTX_POSITIVE; - case SDL_GAMEPAD_AXIS_RIGHTY: - return SDL_GAMEPAD_ELEMENT_AXIS_RIGHTY_POSITIVE; - case SDL_GAMEPAD_AXIS_LEFT_TRIGGER: - return SDL_GAMEPAD_ELEMENT_AXIS_LEFT_TRIGGER; - case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER: - return SDL_GAMEPAD_ELEMENT_AXIS_RIGHT_TRIGGER; - default: - break; - } - } - - rect.y += ctx->button_height + 2.0f; - } - return SDL_GAMEPAD_ELEMENT_INVALID; -} - -static void RenderGamepadElementHighlight(GamepadDisplay *ctx, int element, const SDL_FRect *area) -{ - if (element == ctx->element_highlighted || element == ctx->element_selected) { - Uint8 r, g, b, a; - - SDL_GetRenderDrawColor(ctx->renderer, &r, &g, &b, &a); - - if (element == ctx->element_highlighted) { - if (ctx->element_pressed) { - SDL_SetRenderDrawColor(ctx->renderer, PRESSED_COLOR); - } else { - SDL_SetRenderDrawColor(ctx->renderer, HIGHLIGHT_COLOR); - } - } else { - SDL_SetRenderDrawColor(ctx->renderer, SELECTED_COLOR); - } - SDL_RenderFillRect(ctx->renderer, area); - - SDL_SetRenderDrawColor(ctx->renderer, r, g, b, a); - } -} - -void RenderGamepadDisplay(GamepadDisplay *ctx, SDL_Gamepad *gamepad) -{ - float x, y; - int i; - char text[128], binding[32]; - const float margin = 8.0f; - const float center = ctx->area.w / 2.0f; - const float arrow_extent = 48.0f; - SDL_FRect dst, rect, highlight; - Uint8 r, g, b, a; - char *mapping; - bool has_accel; - bool has_gyro; - - if (!ctx) { - return; - } - - SDL_GetRenderDrawColor(ctx->renderer, &r, &g, &b, &a); - - mapping = SDL_GetGamepadMapping(gamepad); - - x = ctx->area.x + margin; - y = ctx->area.y + margin; - - for (i = 0; i < SDL_GAMEPAD_BUTTON_COUNT; ++i) { - SDL_GamepadButton button = (SDL_GamepadButton)i; - - if (ctx->display_mode == CONTROLLER_MODE_TESTING && - !SDL_GamepadHasButton(gamepad, button)) { - continue; - } - - highlight.x = x; - highlight.y = y + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2; - highlight.w = ctx->area.w - (margin * 2); - highlight.h = ctx->button_height; - RenderGamepadElementHighlight(ctx, i, &highlight); - - SDL_snprintf(text, sizeof(text), "%s:", gamepad_button_names[i]); - SDLTest_DrawString(ctx->renderer, x + center - SDL_strlen(text) * FONT_CHARACTER_SIZE, y, text); - - if (SDL_GetGamepadButton(gamepad, button)) { - SDL_SetTextureColorMod(ctx->button_texture, 10, 255, 21); - } else { - SDL_SetTextureColorMod(ctx->button_texture, 255, 255, 255); - } - - dst.x = x + center + 2.0f; - dst.y = y + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2; - dst.w = ctx->button_width; - dst.h = ctx->button_height; - SDL_RenderTexture(ctx->renderer, ctx->button_texture, NULL, &dst); - - if (ctx->display_mode == CONTROLLER_MODE_BINDING) { - if (GetButtonBindingString(button, mapping, binding, sizeof(binding))) { - dst.x += dst.w + 2 * margin; - SDLTest_DrawString(ctx->renderer, dst.x, y, binding); - } - } - - y += ctx->button_height + 2.0f; - } - - for (i = 0; i < SDL_GAMEPAD_AXIS_COUNT; ++i) { - SDL_GamepadAxis axis = (SDL_GamepadAxis)i; - bool has_negative = (axis != SDL_GAMEPAD_AXIS_LEFT_TRIGGER && axis != SDL_GAMEPAD_AXIS_RIGHT_TRIGGER); - Sint16 value; - - if (ctx->display_mode == CONTROLLER_MODE_TESTING && - !SDL_GamepadHasAxis(gamepad, axis)) { - continue; - } - - value = SDL_GetGamepadAxis(gamepad, axis); - - SDL_snprintf(text, sizeof(text), "%s:", gamepad_axis_names[i]); - SDLTest_DrawString(ctx->renderer, x + center - SDL_strlen(text) * FONT_CHARACTER_SIZE, y, text); - - highlight.x = x + center + 2.0f; - highlight.y = y + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2; - highlight.w = ctx->arrow_width + arrow_extent; - highlight.h = ctx->button_height; - - switch (axis) { - case SDL_GAMEPAD_AXIS_LEFTX: - RenderGamepadElementHighlight(ctx, SDL_GAMEPAD_ELEMENT_AXIS_LEFTX_NEGATIVE, &highlight); - break; - case SDL_GAMEPAD_AXIS_LEFTY: - RenderGamepadElementHighlight(ctx, SDL_GAMEPAD_ELEMENT_AXIS_LEFTY_NEGATIVE, &highlight); - break; - case SDL_GAMEPAD_AXIS_RIGHTX: - RenderGamepadElementHighlight(ctx, SDL_GAMEPAD_ELEMENT_AXIS_RIGHTX_NEGATIVE, &highlight); - break; - case SDL_GAMEPAD_AXIS_RIGHTY: - RenderGamepadElementHighlight(ctx, SDL_GAMEPAD_ELEMENT_AXIS_RIGHTY_NEGATIVE, &highlight); - break; - default: - break; - } - - highlight.x += highlight.w; - - switch (axis) { - case SDL_GAMEPAD_AXIS_LEFTX: - RenderGamepadElementHighlight(ctx, SDL_GAMEPAD_ELEMENT_AXIS_LEFTX_POSITIVE, &highlight); - break; - case SDL_GAMEPAD_AXIS_LEFTY: - RenderGamepadElementHighlight(ctx, SDL_GAMEPAD_ELEMENT_AXIS_LEFTY_POSITIVE, &highlight); - break; - case SDL_GAMEPAD_AXIS_RIGHTX: - RenderGamepadElementHighlight(ctx, SDL_GAMEPAD_ELEMENT_AXIS_RIGHTX_POSITIVE, &highlight); - break; - case SDL_GAMEPAD_AXIS_RIGHTY: - RenderGamepadElementHighlight(ctx, SDL_GAMEPAD_ELEMENT_AXIS_RIGHTY_POSITIVE, &highlight); - break; - case SDL_GAMEPAD_AXIS_LEFT_TRIGGER: - RenderGamepadElementHighlight(ctx, SDL_GAMEPAD_ELEMENT_AXIS_LEFT_TRIGGER, &highlight); - break; - case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER: - RenderGamepadElementHighlight(ctx, SDL_GAMEPAD_ELEMENT_AXIS_RIGHT_TRIGGER, &highlight); - break; - default: - break; - } - - dst.x = x + center + 2.0f; - dst.y = y + FONT_CHARACTER_SIZE / 2 - ctx->arrow_height / 2; - dst.w = ctx->arrow_width; - dst.h = ctx->arrow_height; - - if (has_negative) { - if (value == SDL_MIN_SINT16) { - SDL_SetTextureColorMod(ctx->arrow_texture, 10, 255, 21); - } else { - SDL_SetTextureColorMod(ctx->arrow_texture, 255, 255, 255); - } - SDL_RenderTextureRotated(ctx->renderer, ctx->arrow_texture, NULL, &dst, 0.0f, NULL, SDL_FLIP_HORIZONTAL); - } - - dst.x += ctx->arrow_width; - - SDL_SetRenderDrawColor(ctx->renderer, 200, 200, 200, SDL_ALPHA_OPAQUE); - rect.x = dst.x + arrow_extent - 2.0f; - rect.y = dst.y; - rect.w = 4.0f; - rect.h = ctx->arrow_height; - SDL_RenderFillRect(ctx->renderer, &rect); - SDL_SetRenderDrawColor(ctx->renderer, r, g, b, a); - - if (value < 0) { - SDL_SetRenderDrawColor(ctx->renderer, 8, 200, 16, SDL_ALPHA_OPAQUE); - rect.w = ((float)value / SDL_MIN_SINT16) * arrow_extent; - rect.x = dst.x + arrow_extent - rect.w; - rect.y = dst.y + ctx->arrow_height * 0.25f; - rect.h = ctx->arrow_height / 2.0f; - SDL_RenderFillRect(ctx->renderer, &rect); - } - - if (ctx->display_mode == CONTROLLER_MODE_BINDING && has_negative) { - if (GetAxisBindingString(axis, -1, mapping, binding, sizeof(binding))) { - float text_x; - - SDL_SetRenderDrawColor(ctx->renderer, r, g, b, a); - text_x = dst.x + arrow_extent / 2 - (FONT_CHARACTER_SIZE * SDL_strlen(binding)) / 2; - SDLTest_DrawString(ctx->renderer, text_x, y, binding); - } - } - - dst.x += arrow_extent; - - if (value > 0) { - SDL_SetRenderDrawColor(ctx->renderer, 8, 200, 16, SDL_ALPHA_OPAQUE); - rect.w = ((float)value / SDL_MAX_SINT16) * arrow_extent; - rect.x = dst.x; - rect.y = dst.y + ctx->arrow_height * 0.25f; - rect.h = ctx->arrow_height / 2.0f; - SDL_RenderFillRect(ctx->renderer, &rect); - } - - if (ctx->display_mode == CONTROLLER_MODE_BINDING) { - if (GetAxisBindingString(axis, 1, mapping, binding, sizeof(binding))) { - float text_x; - - SDL_SetRenderDrawColor(ctx->renderer, r, g, b, a); - text_x = dst.x + arrow_extent / 2 - (FONT_CHARACTER_SIZE * SDL_strlen(binding)) / 2; - SDLTest_DrawString(ctx->renderer, text_x, y, binding); - } - } - - dst.x += arrow_extent; - - if (value == SDL_MAX_SINT16) { - SDL_SetTextureColorMod(ctx->arrow_texture, 10, 255, 21); - } else { - SDL_SetTextureColorMod(ctx->arrow_texture, 255, 255, 255); - } - SDL_RenderTexture(ctx->renderer, ctx->arrow_texture, NULL, &dst); - - SDL_SetRenderDrawColor(ctx->renderer, r, g, b, a); - - y += ctx->button_height + 2.0f; - } - - if (ctx->display_mode == CONTROLLER_MODE_TESTING) { - if (SDL_GetNumGamepadTouchpads(gamepad) > 0) { - int num_fingers = SDL_GetNumGamepadTouchpadFingers(gamepad, 0); - for (i = 0; i < num_fingers; ++i) { - bool down; - float finger_x, finger_y, finger_pressure; - - if (!SDL_GetGamepadTouchpadFinger(gamepad, 0, i, &down, &finger_x, &finger_y, &finger_pressure)) { - continue; - } - - SDL_snprintf(text, sizeof(text), "Touch finger %d:", i); - SDLTest_DrawString(ctx->renderer, x + center - SDL_strlen(text) * FONT_CHARACTER_SIZE, y, text); - - if (down) { - SDL_SetTextureColorMod(ctx->button_texture, 10, 255, 21); - } else { - SDL_SetTextureColorMod(ctx->button_texture, 255, 255, 255); - } - - dst.x = x + center + 2.0f; - dst.y = y + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2; - dst.w = ctx->button_width; - dst.h = ctx->button_height; - SDL_RenderTexture(ctx->renderer, ctx->button_texture, NULL, &dst); - - if (down) { - SDL_snprintf(text, sizeof(text), "(%.2f,%.2f)", finger_x, finger_y); - SDLTest_DrawString(ctx->renderer, x + center + ctx->button_width + 4.0f, y, text); - } - - y += ctx->button_height + 2.0f; - } - } - - has_accel = SDL_GamepadHasSensor(gamepad, SDL_SENSOR_ACCEL); - has_gyro = SDL_GamepadHasSensor(gamepad, SDL_SENSOR_GYRO); - if (has_accel || has_gyro) { - const int SENSOR_UPDATE_INTERVAL_MS = 100; - Uint64 now = SDL_GetTicks(); - - if (now >= ctx->last_sensor_update + SENSOR_UPDATE_INTERVAL_MS) { - if (has_accel) { - SDL_GetGamepadSensorData(gamepad, SDL_SENSOR_ACCEL, ctx->accel_data, SDL_arraysize(ctx->accel_data)); - } - if (has_gyro) { - SDL_GetGamepadSensorData(gamepad, SDL_SENSOR_GYRO, ctx->gyro_data, SDL_arraysize(ctx->gyro_data)); - } - ctx->last_sensor_update = now; - } - - if (has_accel) { - SDL_strlcpy(text, "Accelerometer:", sizeof(text)); - SDLTest_DrawString(ctx->renderer, x + center - SDL_strlen(text) * FONT_CHARACTER_SIZE, y, text); - SDL_snprintf(text, sizeof(text), "(%.2f,%.2f,%.2f)", ctx->accel_data[0], ctx->accel_data[1], ctx->accel_data[2]); - SDLTest_DrawString(ctx->renderer, x + center + 2.0f, y, text); - - y += ctx->button_height + 2.0f; - } - - if (has_gyro) { - SDL_strlcpy(text, "Gyro:", sizeof(text)); - SDLTest_DrawString(ctx->renderer, x + center - SDL_strlen(text) * FONT_CHARACTER_SIZE, y, text); - SDL_snprintf(text, sizeof(text), "(%.2f,%.2f,%.2f)", ctx->gyro_data[0], ctx->gyro_data[1], ctx->gyro_data[2]); - SDLTest_DrawString(ctx->renderer, x + center + 2.0f, y, text); - - y += ctx->button_height + 2.0f; - } - } - } - SDL_free(mapping); -} - -void DestroyGamepadDisplay(GamepadDisplay *ctx) -{ - if (!ctx) { - return; - } - - SDL_DestroyTexture(ctx->button_texture); - SDL_DestroyTexture(ctx->arrow_texture); - SDL_free(ctx); -} - -struct GamepadTypeDisplay -{ - SDL_Renderer *renderer; - - int type_highlighted; - bool type_pressed; - int type_selected; - SDL_GamepadType real_type; - - SDL_FRect area; -}; - -GamepadTypeDisplay *CreateGamepadTypeDisplay(SDL_Renderer *renderer) -{ - GamepadTypeDisplay *ctx = SDL_calloc(1, sizeof(*ctx)); - if (ctx) { - ctx->renderer = renderer; - - ctx->type_highlighted = SDL_GAMEPAD_TYPE_UNSELECTED; - ctx->type_selected = SDL_GAMEPAD_TYPE_UNSELECTED; - ctx->real_type = SDL_GAMEPAD_TYPE_UNKNOWN; - } - return ctx; -} - -void SetGamepadTypeDisplayArea(GamepadTypeDisplay *ctx, const SDL_FRect *area) -{ - if (!ctx) { - return; - } - - SDL_copyp(&ctx->area, area); -} - -void SetGamepadTypeDisplayHighlight(GamepadTypeDisplay *ctx, int type, bool pressed) -{ - if (!ctx) { - return; - } - - ctx->type_highlighted = type; - ctx->type_pressed = pressed; -} - -void SetGamepadTypeDisplaySelected(GamepadTypeDisplay *ctx, int type) -{ - if (!ctx) { - return; - } - - ctx->type_selected = type; -} - -void SetGamepadTypeDisplayRealType(GamepadTypeDisplay *ctx, SDL_GamepadType type) -{ - if (!ctx) { - return; - } - - ctx->real_type = type; -} - -int GetGamepadTypeDisplayAt(GamepadTypeDisplay *ctx, float x, float y) -{ - int i; - const float margin = 8.0f; - const float line_height = 16.0f; - SDL_FRect highlight; - SDL_FPoint point; - - if (!ctx) { - return SDL_GAMEPAD_TYPE_UNSELECTED; - } - - point.x = x; - point.y = y; - - x = ctx->area.x + margin; - y = ctx->area.y + margin; - - for (i = SDL_GAMEPAD_TYPE_UNKNOWN; i < SDL_GAMEPAD_TYPE_COUNT; ++i) { - highlight.x = x; - highlight.y = y; - highlight.w = ctx->area.w - (margin * 2); - highlight.h = line_height; - - if (SDL_PointInRectFloat(&point, &highlight)) { - return i; - } - - y += line_height; - } - return SDL_GAMEPAD_TYPE_UNSELECTED; -} - -static void RenderGamepadTypeHighlight(GamepadTypeDisplay *ctx, int type, const SDL_FRect *area) -{ - if (type == ctx->type_highlighted || type == ctx->type_selected) { - Uint8 r, g, b, a; - - SDL_GetRenderDrawColor(ctx->renderer, &r, &g, &b, &a); - - if (type == ctx->type_highlighted) { - if (ctx->type_pressed) { - SDL_SetRenderDrawColor(ctx->renderer, PRESSED_COLOR); - } else { - SDL_SetRenderDrawColor(ctx->renderer, HIGHLIGHT_COLOR); - } - } else { - SDL_SetRenderDrawColor(ctx->renderer, SELECTED_COLOR); - } - SDL_RenderFillRect(ctx->renderer, area); - - SDL_SetRenderDrawColor(ctx->renderer, r, g, b, a); - } -} - -void RenderGamepadTypeDisplay(GamepadTypeDisplay *ctx) -{ - float x, y; - int i; - char text[128]; - const float margin = 8.0f; - const float line_height = 16.0f; - SDL_FPoint dst; - SDL_FRect highlight; - - if (!ctx) { - return; - } - - x = ctx->area.x + margin; - y = ctx->area.y + margin; - - for (i = SDL_GAMEPAD_TYPE_UNKNOWN; i < SDL_GAMEPAD_TYPE_COUNT; ++i) { - highlight.x = x; - highlight.y = y; - highlight.w = ctx->area.w - (margin * 2); - highlight.h = line_height; - RenderGamepadTypeHighlight(ctx, i, &highlight); - - if (i == SDL_GAMEPAD_TYPE_UNKNOWN) { - if (ctx->real_type == SDL_GAMEPAD_TYPE_UNKNOWN || - ctx->real_type == SDL_GAMEPAD_TYPE_STANDARD) { - SDL_strlcpy(text, "Auto (Standard)", sizeof(text)); - } else { - SDL_snprintf(text, sizeof(text), "Auto (%s)", GetGamepadTypeString(ctx->real_type)); - } - } else if (i == SDL_GAMEPAD_TYPE_STANDARD) { - SDL_strlcpy(text, "Standard", sizeof(text)); - } else { - SDL_strlcpy(text, GetGamepadTypeString((SDL_GamepadType)i), sizeof(text)); - } - - dst.x = x + margin; - dst.y = y + line_height / 2 - FONT_CHARACTER_SIZE / 2; - SDLTest_DrawString(ctx->renderer, dst.x, dst.y, text); - - y += line_height; - } -} - -void DestroyGamepadTypeDisplay(GamepadTypeDisplay *ctx) -{ - if (!ctx) { - return; - } - - SDL_free(ctx); -} - - -struct JoystickDisplay -{ - SDL_Renderer *renderer; - SDL_Texture *button_texture; - SDL_Texture *arrow_texture; - float button_width; - float button_height; - float arrow_width; - float arrow_height; - - SDL_FRect area; - - char *element_highlighted; - bool element_pressed; -}; - -JoystickDisplay *CreateJoystickDisplay(SDL_Renderer *renderer) -{ - JoystickDisplay *ctx = SDL_calloc(1, sizeof(*ctx)); - if (ctx) { - ctx->renderer = renderer; - - ctx->button_texture = CreateTexture(renderer, gamepad_button_small_bmp, gamepad_button_small_bmp_len); - SDL_GetTextureSize(ctx->button_texture, &ctx->button_width, &ctx->button_height); - - ctx->arrow_texture = CreateTexture(renderer, gamepad_axis_arrow_bmp, gamepad_axis_arrow_bmp_len); - SDL_GetTextureSize(ctx->arrow_texture, &ctx->arrow_width, &ctx->arrow_height); - } - return ctx; -} - -void SetJoystickDisplayArea(JoystickDisplay *ctx, const SDL_FRect *area) -{ - if (!ctx) { - return; - } - - SDL_copyp(&ctx->area, area); -} - -char *GetJoystickDisplayElementAt(JoystickDisplay *ctx, SDL_Joystick *joystick, float x, float y) -{ - SDL_FPoint point; - int i; - int nbuttons = SDL_GetNumJoystickButtons(joystick); - int naxes = SDL_GetNumJoystickAxes(joystick); - int nhats = SDL_GetNumJoystickHats(joystick); - char text[32]; - const float margin = 8.0f; - const float center = 80.0f; - const float arrow_extent = 48.0f; - SDL_FRect dst, highlight; - char *element = NULL; - - if (!ctx) { - return NULL; - } - - point.x = x; - point.y = y; - - x = ctx->area.x + margin; - y = ctx->area.y + margin; - - if (nbuttons > 0) { - y += FONT_LINE_HEIGHT + 2; - - for (i = 0; i < nbuttons; ++i) { - highlight.x = x; - highlight.y = y + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2; - highlight.w = center - (margin * 2); - highlight.h = ctx->button_height; - if (SDL_PointInRectFloat(&point, &highlight)) { - SDL_asprintf(&element, "b%d", i); - return element; - } - - y += ctx->button_height + 2; - } - } - - x = ctx->area.x + margin + center + margin; - y = ctx->area.y + margin; - - if (naxes > 0) { - y += FONT_LINE_HEIGHT + 2; - - for (i = 0; i < naxes; ++i) { - SDL_snprintf(text, sizeof(text), "%d:", i); - - highlight.x = x + FONT_CHARACTER_SIZE * SDL_strlen(text) + 2.0f; - highlight.y = y + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2; - highlight.w = ctx->arrow_width + arrow_extent; - highlight.h = ctx->button_height; - if (SDL_PointInRectFloat(&point, &highlight)) { - SDL_asprintf(&element, "-a%d", i); - return element; - } - - highlight.x += highlight.w; - if (SDL_PointInRectFloat(&point, &highlight)) { - SDL_asprintf(&element, "+a%d", i); - return element; - } - - y += ctx->button_height + 2; - } - } - - y += FONT_LINE_HEIGHT + 2; - - if (nhats > 0) { - y += FONT_LINE_HEIGHT + 2 + 1.5f * ctx->button_height - FONT_CHARACTER_SIZE / 2; - - for (i = 0; i < nhats; ++i) { - SDL_snprintf(text, sizeof(text), "%d:", i); - - dst.x = x + FONT_CHARACTER_SIZE * SDL_strlen(text) + 2; - dst.y = y + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2; - dst.w = ctx->button_width; - dst.h = ctx->button_height; - if (SDL_PointInRectFloat(&point, &dst)) { - SDL_asprintf(&element, "h%d.%d", i, SDL_HAT_LEFT); - return element; - } - - dst.x += ctx->button_width; - dst.y -= ctx->button_height; - if (SDL_PointInRectFloat(&point, &dst)) { - SDL_asprintf(&element, "h%d.%d", i, SDL_HAT_UP); - return element; - } - - dst.y += ctx->button_height * 2; - if (SDL_PointInRectFloat(&point, &dst)) { - SDL_asprintf(&element, "h%d.%d", i, SDL_HAT_DOWN); - return element; - } - - dst.x += ctx->button_width; - dst.y = y + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2; - if (SDL_PointInRectFloat(&point, &dst)) { - SDL_asprintf(&element, "h%d.%d", i, SDL_HAT_RIGHT); - return element; - } - - y += 3 * ctx->button_height + 2; - } - } - return NULL; -} - -void SetJoystickDisplayHighlight(JoystickDisplay *ctx, const char *element, bool pressed) -{ - if (ctx->element_highlighted) { - SDL_free(ctx->element_highlighted); - ctx->element_highlighted = NULL; - ctx->element_pressed = false; - } - - if (element) { - ctx->element_highlighted = SDL_strdup(element); - ctx->element_pressed = pressed; - } -} - -static void RenderJoystickButtonHighlight(JoystickDisplay *ctx, int button, const SDL_FRect *area) -{ - if (!ctx->element_highlighted || *ctx->element_highlighted != 'b') { - return; - } - - if (SDL_atoi(ctx->element_highlighted + 1) == button) { - Uint8 r, g, b, a; - - SDL_GetRenderDrawColor(ctx->renderer, &r, &g, &b, &a); - - if (ctx->element_pressed) { - SDL_SetRenderDrawColor(ctx->renderer, PRESSED_COLOR); - } else { - SDL_SetRenderDrawColor(ctx->renderer, HIGHLIGHT_COLOR); - } - SDL_RenderFillRect(ctx->renderer, area); - - SDL_SetRenderDrawColor(ctx->renderer, r, g, b, a); - } -} - -static void RenderJoystickAxisHighlight(JoystickDisplay *ctx, int axis, int direction, const SDL_FRect *area) -{ - char prefix = (direction < 0 ? '-' : '+'); - - if (!ctx->element_highlighted || - ctx->element_highlighted[0] != prefix || - ctx->element_highlighted[1] != 'a') { - return; - } - - if (SDL_atoi(ctx->element_highlighted + 2) == axis) { - Uint8 r, g, b, a; - - SDL_GetRenderDrawColor(ctx->renderer, &r, &g, &b, &a); - - if (ctx->element_pressed) { - SDL_SetRenderDrawColor(ctx->renderer, PRESSED_COLOR); - } else { - SDL_SetRenderDrawColor(ctx->renderer, HIGHLIGHT_COLOR); - } - SDL_RenderFillRect(ctx->renderer, area); - - SDL_SetRenderDrawColor(ctx->renderer, r, g, b, a); - } -} - -static bool SetupJoystickHatHighlight(JoystickDisplay *ctx, int hat, int direction) -{ - if (!ctx->element_highlighted || *ctx->element_highlighted != 'h') { - return false; - } - - if (SDL_atoi(ctx->element_highlighted + 1) == hat && - ctx->element_highlighted[2] == '.' && - SDL_atoi(ctx->element_highlighted + 3) == direction) { - if (ctx->element_pressed) { - SDL_SetTextureColorMod(ctx->button_texture, PRESSED_TEXTURE_MOD); - } else { - SDL_SetTextureColorMod(ctx->button_texture, HIGHLIGHT_TEXTURE_MOD); - } - return true; - } - return false; -} - -void RenderJoystickDisplay(JoystickDisplay *ctx, SDL_Joystick *joystick) -{ - float x, y; - int i; - int nbuttons = SDL_GetNumJoystickButtons(joystick); - int naxes = SDL_GetNumJoystickAxes(joystick); - int nhats = SDL_GetNumJoystickHats(joystick); - char text[32]; - const float margin = 8.0f; - const float center = 80.0f; - const float arrow_extent = 48.0f; - SDL_FRect dst, rect, highlight; - Uint8 r, g, b, a; - - if (!ctx) { - return; - } - - SDL_GetRenderDrawColor(ctx->renderer, &r, &g, &b, &a); - - x = ctx->area.x + margin; - y = ctx->area.y + margin; - - if (nbuttons > 0) { - SDLTest_DrawString(ctx->renderer, x, y, "BUTTONS"); - y += FONT_LINE_HEIGHT + 2; - - for (i = 0; i < nbuttons; ++i) { - highlight.x = x; - highlight.y = y + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2; - highlight.w = center - (margin * 2); - highlight.h = ctx->button_height; - RenderJoystickButtonHighlight(ctx, i, &highlight); - - SDL_snprintf(text, sizeof(text), "%2d:", i); - SDLTest_DrawString(ctx->renderer, x, y, text); - - if (SDL_GetJoystickButton(joystick, (Uint8)i)) { - SDL_SetTextureColorMod(ctx->button_texture, 10, 255, 21); - } else { - SDL_SetTextureColorMod(ctx->button_texture, 255, 255, 255); - } - - dst.x = x + FONT_CHARACTER_SIZE * SDL_strlen(text) + 2; - dst.y = y + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2; - dst.w = ctx->button_width; - dst.h = ctx->button_height; - SDL_RenderTexture(ctx->renderer, ctx->button_texture, NULL, &dst); - - y += ctx->button_height + 2; - } - } - - x = ctx->area.x + margin + center + margin; - y = ctx->area.y + margin; - - if (naxes > 0) { - SDLTest_DrawString(ctx->renderer, x, y, "AXES"); - y += FONT_LINE_HEIGHT + 2; - - for (i = 0; i < naxes; ++i) { - Sint16 value = SDL_GetJoystickAxis(joystick, i); - - SDL_snprintf(text, sizeof(text), "%d:", i); - SDLTest_DrawString(ctx->renderer, x, y, text); - - highlight.x = x + FONT_CHARACTER_SIZE * SDL_strlen(text) + 2.0f; - highlight.y = y + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2; - highlight.w = ctx->arrow_width + arrow_extent; - highlight.h = ctx->button_height; - RenderJoystickAxisHighlight(ctx, i, -1, &highlight); - - highlight.x += highlight.w; - RenderJoystickAxisHighlight(ctx, i, 1, &highlight); - - dst.x = x + FONT_CHARACTER_SIZE * SDL_strlen(text) + 2.0f; - dst.y = y + FONT_CHARACTER_SIZE / 2 - ctx->arrow_height / 2; - dst.w = ctx->arrow_width; - dst.h = ctx->arrow_height; - - if (value == SDL_MIN_SINT16) { - SDL_SetTextureColorMod(ctx->arrow_texture, 10, 255, 21); - } else { - SDL_SetTextureColorMod(ctx->arrow_texture, 255, 255, 255); - } - SDL_RenderTextureRotated(ctx->renderer, ctx->arrow_texture, NULL, &dst, 0.0f, NULL, SDL_FLIP_HORIZONTAL); - - dst.x += ctx->arrow_width; - - SDL_SetRenderDrawColor(ctx->renderer, 200, 200, 200, SDL_ALPHA_OPAQUE); - rect.x = dst.x + arrow_extent - 2.0f; - rect.y = dst.y; - rect.w = 4.0f; - rect.h = ctx->arrow_height; - SDL_RenderFillRect(ctx->renderer, &rect); - SDL_SetRenderDrawColor(ctx->renderer, r, g, b, a); - - if (value < 0) { - SDL_SetRenderDrawColor(ctx->renderer, 8, 200, 16, SDL_ALPHA_OPAQUE); - rect.w = ((float)value / SDL_MIN_SINT16) * arrow_extent; - rect.x = dst.x + arrow_extent - rect.w; - rect.y = dst.y + ctx->arrow_height * 0.25f; - rect.h = ctx->arrow_height / 2.0f; - SDL_RenderFillRect(ctx->renderer, &rect); - } - - dst.x += arrow_extent; - - if (value > 0) { - SDL_SetRenderDrawColor(ctx->renderer, 8, 200, 16, SDL_ALPHA_OPAQUE); - rect.w = ((float)value / SDL_MAX_SINT16) * arrow_extent; - rect.x = dst.x; - rect.y = dst.y + ctx->arrow_height * 0.25f; - rect.h = ctx->arrow_height / 2.0f; - SDL_RenderFillRect(ctx->renderer, &rect); - } - - dst.x += arrow_extent; - - if (value == SDL_MAX_SINT16) { - SDL_SetTextureColorMod(ctx->arrow_texture, 10, 255, 21); - } else { - SDL_SetTextureColorMod(ctx->arrow_texture, 255, 255, 255); - } - SDL_RenderTexture(ctx->renderer, ctx->arrow_texture, NULL, &dst); - - SDL_SetRenderDrawColor(ctx->renderer, r, g, b, a); - - y += ctx->button_height + 2; - } - } - - y += FONT_LINE_HEIGHT + 2; - - if (nhats > 0) { - SDLTest_DrawString(ctx->renderer, x, y, "HATS"); - y += FONT_LINE_HEIGHT + 2 + 1.5f * ctx->button_height - FONT_CHARACTER_SIZE / 2; - - for (i = 0; i < nhats; ++i) { - Uint8 value = SDL_GetJoystickHat(joystick, i); - - SDL_snprintf(text, sizeof(text), "%d:", i); - SDLTest_DrawString(ctx->renderer, x, y, text); - - if (value & SDL_HAT_LEFT) { - SDL_SetTextureColorMod(ctx->button_texture, 10, 255, 21); - } else if (!SetupJoystickHatHighlight(ctx, i, SDL_HAT_LEFT)) { - SDL_SetTextureColorMod(ctx->button_texture, 255, 255, 255); - } - - dst.x = x + FONT_CHARACTER_SIZE * SDL_strlen(text) + 2; - dst.y = y + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2; - dst.w = ctx->button_width; - dst.h = ctx->button_height; - SDL_RenderTexture(ctx->renderer, ctx->button_texture, NULL, &dst); - - if (value & SDL_HAT_UP) { - SDL_SetTextureColorMod(ctx->button_texture, 10, 255, 21); - } else if (!SetupJoystickHatHighlight(ctx, i, SDL_HAT_UP)) { - SDL_SetTextureColorMod(ctx->button_texture, 255, 255, 255); - } - - dst.x += ctx->button_width; - dst.y -= ctx->button_height; - SDL_RenderTexture(ctx->renderer, ctx->button_texture, NULL, &dst); - - if (value & SDL_HAT_DOWN) { - SDL_SetTextureColorMod(ctx->button_texture, 10, 255, 21); - } else if (!SetupJoystickHatHighlight(ctx, i, SDL_HAT_DOWN)) { - SDL_SetTextureColorMod(ctx->button_texture, 255, 255, 255); - } - - dst.y += ctx->button_height * 2; - SDL_RenderTexture(ctx->renderer, ctx->button_texture, NULL, &dst); - - if (value & SDL_HAT_RIGHT) { - SDL_SetTextureColorMod(ctx->button_texture, 10, 255, 21); - } else if (!SetupJoystickHatHighlight(ctx, i, SDL_HAT_RIGHT)) { - SDL_SetTextureColorMod(ctx->button_texture, 255, 255, 255); - } - - dst.x += ctx->button_width; - dst.y = y + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2; - SDL_RenderTexture(ctx->renderer, ctx->button_texture, NULL, &dst); - - y += 3 * ctx->button_height + 2; - } - } -} - -void DestroyJoystickDisplay(JoystickDisplay *ctx) -{ - if (!ctx) { - return; - } - - SDL_DestroyTexture(ctx->button_texture); - SDL_DestroyTexture(ctx->arrow_texture); - SDL_free(ctx); -} - - -struct GamepadButton -{ - SDL_Renderer *renderer; - SDL_Texture *background; - float background_width; - float background_height; - - SDL_FRect area; - - char *label; - float label_width; - float label_height; - - bool highlight; - bool pressed; -}; - -GamepadButton *CreateGamepadButton(SDL_Renderer *renderer, const char *label) -{ - GamepadButton *ctx = SDL_calloc(1, sizeof(*ctx)); - if (ctx) { - ctx->renderer = renderer; - - ctx->background = CreateTexture(renderer, gamepad_button_background_bmp, gamepad_button_background_bmp_len); - SDL_GetTextureSize(ctx->background, &ctx->background_width, &ctx->background_height); - - ctx->label = SDL_strdup(label); - ctx->label_width = (float)(FONT_CHARACTER_SIZE * SDL_strlen(label)); - ctx->label_height = (float)FONT_CHARACTER_SIZE; - } - return ctx; -} - -void SetGamepadButtonArea(GamepadButton *ctx, const SDL_FRect *area) -{ - if (!ctx) { - return; - } - - SDL_copyp(&ctx->area, area); -} - -void GetGamepadButtonArea(GamepadButton *ctx, SDL_FRect *area) -{ - if (!ctx) { - SDL_zerop(area); - return; - } - - SDL_copyp(area, &ctx->area); -} - -void SetGamepadButtonHighlight(GamepadButton *ctx, bool highlight, bool pressed) -{ - if (!ctx) { - return; - } - - ctx->highlight = highlight; - if (highlight) { - ctx->pressed = pressed; - } else { - ctx->pressed = false; - } -} - -float GetGamepadButtonLabelWidth(GamepadButton *ctx) -{ - if (!ctx) { - return 0; - } - - return ctx->label_width; -} - -float GetGamepadButtonLabelHeight(GamepadButton *ctx) -{ - if (!ctx) { - return 0; - } - - return ctx->label_height; -} - -bool GamepadButtonContains(GamepadButton *ctx, float x, float y) -{ - SDL_FPoint point; - - if (!ctx) { - return false; - } - - point.x = x; - point.y = y; - return SDL_PointInRectFloat(&point, &ctx->area); -} - -void RenderGamepadButton(GamepadButton *ctx) -{ - SDL_FRect src, dst; - float one_third_src_width; - float one_third_src_height; - - if (!ctx) { - return; - } - - one_third_src_width = ctx->background_width / 3; - one_third_src_height = ctx->background_height / 3; - - if (ctx->pressed) { - SDL_SetTextureColorMod(ctx->background, PRESSED_TEXTURE_MOD); - } else if (ctx->highlight) { - SDL_SetTextureColorMod(ctx->background, HIGHLIGHT_TEXTURE_MOD); - } else { - SDL_SetTextureColorMod(ctx->background, 255, 255, 255); - } - - /* Top left */ - src.x = 0.0f; - src.y = 0.0f; - src.w = one_third_src_width; - src.h = one_third_src_height; - dst.x = ctx->area.x; - dst.y = ctx->area.y; - dst.w = src.w; - dst.h = src.h; - SDL_RenderTexture(ctx->renderer, ctx->background, &src, &dst); - - /* Bottom left */ - src.y = ctx->background_height - src.h; - dst.y = ctx->area.y + ctx->area.h - dst.h; - SDL_RenderTexture(ctx->renderer, ctx->background, &src, &dst); - - /* Bottom right */ - src.x = ctx->background_width - src.w; - dst.x = ctx->area.x + ctx->area.w - dst.w; - SDL_RenderTexture(ctx->renderer, ctx->background, &src, &dst); - - /* Top right */ - src.y = 0.0f; - dst.y = ctx->area.y; - SDL_RenderTexture(ctx->renderer, ctx->background, &src, &dst); - - /* Left */ - src.x = 0.0f; - src.y = one_third_src_height; - dst.x = ctx->area.x; - dst.y = ctx->area.y + one_third_src_height; - dst.w = one_third_src_width; - dst.h = ctx->area.h - 2 * one_third_src_height; - SDL_RenderTexture(ctx->renderer, ctx->background, &src, &dst); - - /* Right */ - src.x = ctx->background_width - one_third_src_width; - dst.x = ctx->area.x + ctx->area.w - one_third_src_width; - SDL_RenderTexture(ctx->renderer, ctx->background, &src, &dst); - - /* Top */ - src.x = one_third_src_width; - src.y = 0.0f; - dst.x = ctx->area.x + one_third_src_width; - dst.y = ctx->area.y; - dst.w = ctx->area.w - 2 * one_third_src_width; - dst.h = one_third_src_height; - SDL_RenderTexture(ctx->renderer, ctx->background, &src, &dst); - - /* Bottom */ - src.y = ctx->background_height - src.h; - dst.y = ctx->area.y + ctx->area.h - one_third_src_height; - SDL_RenderTexture(ctx->renderer, ctx->background, &src, &dst); - - /* Center */ - src.x = one_third_src_width; - src.y = one_third_src_height; - dst.x = ctx->area.x + one_third_src_width; - dst.y = ctx->area.y + one_third_src_height; - dst.w = ctx->area.w - 2 * one_third_src_width; - dst.h = ctx->area.h - 2 * one_third_src_height; - SDL_RenderTexture(ctx->renderer, ctx->background, &src, &dst); - - /* Label */ - dst.x = ctx->area.x + ctx->area.w / 2 - ctx->label_width / 2; - dst.y = ctx->area.y + ctx->area.h / 2 - ctx->label_height / 2; - SDLTest_DrawString(ctx->renderer, dst.x, dst.y, ctx->label); -} - -void DestroyGamepadButton(GamepadButton *ctx) -{ - if (!ctx) { - return; - } - - SDL_DestroyTexture(ctx->background); - SDL_free(ctx->label); - SDL_free(ctx); -} - - -typedef struct -{ - char *guid; - char *name; - int num_elements; - char **keys; - char **values; -} MappingParts; - -static bool AddMappingKeyValue(MappingParts *parts, char *key, char *value); - -static bool AddMappingHalfAxisValue(MappingParts *parts, const char *key, const char *value, char sign) -{ - char *new_key, *new_value; - - if (SDL_asprintf(&new_key, "%c%s", sign, key) < 0) { - return false; - } - - if (*value && value[SDL_strlen(value) - 1] == '~') { - /* Invert the sign of the bound axis */ - if (sign == '+') { - sign = '-'; - } else { - sign = '+'; - } - } - - if (SDL_asprintf(&new_value, "%c%s", sign, value) < 0) { - SDL_free(new_key); - return false; - } - if (new_value[SDL_strlen(new_value) - 1] == '~') { - new_value[SDL_strlen(new_value) - 1] = '\0'; - } - - return AddMappingKeyValue(parts, new_key, new_value); -} - -static bool AddMappingKeyValue(MappingParts *parts, char *key, char *value) -{ - int axis; - char **new_keys, **new_values; - - if (!key || !value) { - SDL_free(key); - SDL_free(value); - return false; - } - - /* Split axis values for easy binding purposes */ - for (axis = 0; axis < SDL_GAMEPAD_AXIS_LEFT_TRIGGER; ++axis) { - if (SDL_strcmp(key, SDL_GetGamepadStringForAxis((SDL_GamepadAxis)axis)) == 0) { - bool result; - - result = AddMappingHalfAxisValue(parts, key, value, '-') && - AddMappingHalfAxisValue(parts, key, value, '+'); - SDL_free(key); - SDL_free(value); - return result; - } - } - - new_keys = (char **)SDL_realloc(parts->keys, (parts->num_elements + 1) * sizeof(*new_keys)); - if (!new_keys) { - return false; - } - parts->keys = new_keys; - - new_values = (char **)SDL_realloc(parts->values, (parts->num_elements + 1) * sizeof(*new_values)); - if (!new_values) { - return false; - } - parts->values = new_values; - - new_keys[parts->num_elements] = key; - new_values[parts->num_elements] = value; - ++parts->num_elements; - return true; -} - -static void SplitMapping(const char *mapping, MappingParts *parts) -{ - const char *current, *comma, *colon, *key, *value; - char *new_key, *new_value; - - SDL_zerop(parts); - - if (!mapping || !*mapping) { - return; - } - - /* Get the guid */ - current = mapping; - comma = SDL_strchr(current, ','); - if (!comma) { - parts->guid = SDL_strdup(current); - return; - } - parts->guid = SDL_strndup(current, (comma - current)); - current = comma + 1; - - /* Get the name */ - comma = SDL_strchr(current, ','); - if (!comma) { - parts->name = SDL_strdup(current); - return; - } - if (*current != '*') { - parts->name = SDL_strndup(current, (comma - current)); - } - current = comma + 1; - - for (;;) { - colon = SDL_strchr(current, ':'); - if (!colon) { - break; - } - - key = current; - value = colon + 1; - comma = SDL_strchr(value, ','); - - new_key = SDL_strndup(key, (colon - key)); - if (comma) { - new_value = SDL_strndup(value, (comma - value)); - } else { - new_value = SDL_strdup(value); - } - if (!AddMappingKeyValue(parts, new_key, new_value)) { - break; - } - - if (comma) { - current = comma + 1; - } else { - break; - } - } -} - -static int FindMappingKey(const MappingParts *parts, const char *key) -{ - int i; - - if (key) { - for (i = 0; i < parts->num_elements; ++i) { - if (SDL_strcmp(key, parts->keys[i]) == 0) { - return i; - } - } - } - return -1; -} - -static void RemoveMappingValueAt(MappingParts *parts, int index) -{ - SDL_free(parts->keys[index]); - SDL_free(parts->values[index]); - --parts->num_elements; - if (index < parts->num_elements) { - SDL_memmove(&parts->keys[index], &parts->keys[index] + 1, (parts->num_elements - index) * sizeof(parts->keys[index])); - SDL_memmove(&parts->values[index], &parts->values[index] + 1, (parts->num_elements - index) * sizeof(parts->values[index])); - } -} - -static void ConvertBAXYMapping(MappingParts *parts) -{ - int i; - bool baxy_mapping = false; - - for (i = 0; i < parts->num_elements; ++i) { - const char *key = parts->keys[i]; - const char *value = parts->values[i]; - - if (SDL_strcmp(key, "hint") == 0 && - SDL_strcmp(value, "SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1") == 0) { - baxy_mapping = true; - } - } - - if (!baxy_mapping) { - return; - } - - /* Swap buttons, invert hint */ - for (i = 0; i < parts->num_elements; ++i) { - char *key = parts->keys[i]; - char *value = parts->values[i]; - - if (SDL_strcmp(key, "a") == 0) { - parts->keys[i] = SDL_strdup("b"); - SDL_free(key); - } else if (SDL_strcmp(key, "b") == 0) { - parts->keys[i] = SDL_strdup("a"); - SDL_free(key); - } else if (SDL_strcmp(key, "x") == 0) { - parts->keys[i] = SDL_strdup("y"); - SDL_free(key); - } else if (SDL_strcmp(key, "y") == 0) { - parts->keys[i] = SDL_strdup("x"); - SDL_free(key); - } else if (SDL_strcmp(key, "hint") == 0 && - SDL_strcmp(value, "SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1") == 0) { - parts->values[i] = SDL_strdup("!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1"); - SDL_free(value); - } - } -} - -static void UpdateLegacyElements(MappingParts *parts) -{ - ConvertBAXYMapping(parts); -} - -static bool CombineMappingAxes(MappingParts *parts) -{ - int i, matching, axis; - - for (i = 0; i < parts->num_elements; ++i) { - char *key = parts->keys[i]; - char *current_value; - char *matching_key; - char *matching_value; - - if (*key != '-' && *key != '+') { - continue; - } - - for (axis = 0; axis < SDL_GAMEPAD_AXIS_LEFT_TRIGGER; ++axis) { - if (SDL_strcmp(key + 1, SDL_GetGamepadStringForAxis((SDL_GamepadAxis)axis)) == 0) { - /* Look for a matching axis with the opposite sign */ - if (SDL_asprintf(&matching_key, "%c%s", (*key == '-' ? '+' : '-'), key + 1) < 0) { - return false; - } - matching = FindMappingKey(parts, matching_key); - if (matching >= 0) { - /* Check to see if they're bound to the same axis */ - current_value = parts->values[i]; - matching_value = parts->values[matching]; - if (((*current_value == '-' && *matching_value == '+') || - (*current_value == '+' && *matching_value == '-')) && - SDL_strcmp(current_value + 1, matching_value + 1) == 0) { - /* Combine these axes */ - if (*key == *current_value) { - SDL_memmove(current_value, current_value + 1, SDL_strlen(current_value)); - } else { - /* Invert the bound axis */ - SDL_memmove(current_value, current_value + 1, SDL_strlen(current_value)-1); - current_value[SDL_strlen(current_value) - 1] = '~'; - } - SDL_memmove(key, key + 1, SDL_strlen(key)); - RemoveMappingValueAt(parts, matching); - } - } - SDL_free(matching_key); - break; - } - } - } - return true; -} - -typedef struct -{ - MappingParts *parts; - int index; -} MappingSortEntry; - -static int SDLCALL SortMapping(const void *a, const void *b) -{ - MappingSortEntry *A = (MappingSortEntry *)a; - MappingSortEntry *B = (MappingSortEntry *)b; - const char *keyA = A->parts->keys[A->index]; - const char *keyB = B->parts->keys[B->index]; - - return SDL_strcmp(keyA, keyB); -} - -static void MoveSortedEntry(const char *key, MappingSortEntry *sort_order, int num_elements, bool front) -{ - int i; - - for (i = 0; i < num_elements; ++i) { - MappingSortEntry *entry = &sort_order[i]; - if (SDL_strcmp(key, entry->parts->keys[entry->index]) == 0) { - if (front && i != 0) { - MappingSortEntry tmp = sort_order[i]; - SDL_memmove(&sort_order[1], &sort_order[0], sizeof(*sort_order)*i); - sort_order[0] = tmp; - } else if (!front && i != (num_elements - 1)) { - MappingSortEntry tmp = sort_order[i]; - SDL_memmove(&sort_order[i], &sort_order[i + 1], sizeof(*sort_order)*(num_elements - i - 1)); - sort_order[num_elements - 1] = tmp; - } - break; - } - } -} - -static char *JoinMapping(MappingParts *parts) -{ - int i; - size_t length; - char *mapping; - const char *guid; - const char *name; - MappingSortEntry *sort_order; - - UpdateLegacyElements(parts); - CombineMappingAxes(parts); - - guid = parts->guid; - if (!guid || !*guid) { - guid = "*"; - } - - name = parts->name; - if (!name || !*name) { - name = "*"; - } - - length = SDL_strlen(guid) + 1 + SDL_strlen(name) + 1; - for (i = 0; i < parts->num_elements; ++i) { - length += SDL_strlen(parts->keys[i]) + 1; - length += SDL_strlen(parts->values[i]) + 1; - } - length += 1; - - /* The sort order is: crc, platform, type, *, sdk, hint */ - sort_order = SDL_stack_alloc(MappingSortEntry, parts->num_elements); - for (i = 0; i < parts->num_elements; ++i) { - sort_order[i].parts = parts; - sort_order[i].index = i; - } - SDL_qsort(sort_order, parts->num_elements, sizeof(*sort_order), SortMapping); - MoveSortedEntry("type", sort_order, parts->num_elements, true); - MoveSortedEntry("platform", sort_order, parts->num_elements, true); - MoveSortedEntry("crc", sort_order, parts->num_elements, true); - MoveSortedEntry("sdk>=", sort_order, parts->num_elements, false); - MoveSortedEntry("sdk<=", sort_order, parts->num_elements, false); - MoveSortedEntry("hint", sort_order, parts->num_elements, false); - - /* Move platform to the front */ - - mapping = (char *)SDL_malloc(length); - if (mapping) { - *mapping = '\0'; - SDL_strlcat(mapping, guid, length); - SDL_strlcat(mapping, ",", length); - SDL_strlcat(mapping, name, length); - SDL_strlcat(mapping, ",", length); - for (i = 0; i < parts->num_elements; ++i) { - int next = sort_order[i].index; - SDL_strlcat(mapping, parts->keys[next], length); - SDL_strlcat(mapping, ":", length); - SDL_strlcat(mapping, parts->values[next], length); - SDL_strlcat(mapping, ",", length); - } - } - - SDL_stack_free(sort_order); - - return mapping; -} - -static void FreeMappingParts(MappingParts *parts) -{ - int i; - - SDL_free(parts->guid); - SDL_free(parts->name); - for (i = 0; i < parts->num_elements; ++i) { - SDL_free(parts->keys[i]); - SDL_free(parts->values[i]); - } - SDL_free(parts->keys); - SDL_free(parts->values); - SDL_zerop(parts); -} - -/* Create a new mapping from the parts and free the old mapping and parts */ -static char *RecreateMapping(MappingParts *parts, char *mapping) -{ - char *new_mapping = JoinMapping(parts); - if (new_mapping) { - SDL_free(mapping); - mapping = new_mapping; - } - FreeMappingParts(parts); - return mapping; -} - -static const char *GetLegacyKey(const char *key, bool baxy) -{ - if (SDL_strcmp(key, SDL_GetGamepadStringForButton(SDL_GAMEPAD_BUTTON_SOUTH)) == 0) { - if (baxy) { - return "b"; - } else { - return "a"; - } - } - - if (SDL_strcmp(key, SDL_GetGamepadStringForButton(SDL_GAMEPAD_BUTTON_EAST)) == 0) { - if (baxy) { - return "a"; - } else { - return "b"; - } - } - - if (SDL_strcmp(key, SDL_GetGamepadStringForButton(SDL_GAMEPAD_BUTTON_WEST)) == 0) { - if (baxy) { - return "y"; - } else { - return "x"; - } - } - - if (SDL_strcmp(key, SDL_GetGamepadStringForButton(SDL_GAMEPAD_BUTTON_NORTH)) == 0) { - if (baxy) { - return "y"; - } else { - return "x"; - } - } - - return key; -} - -static bool MappingHasKey(const char *mapping, const char *key) -{ - int i; - MappingParts parts; - bool result = false; - - SplitMapping(mapping, &parts); - i = FindMappingKey(&parts, key); - if (i < 0) { - bool baxy_mapping = false; - - if (mapping && SDL_strstr(mapping, ",hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1") != NULL) { - baxy_mapping = true; - } - i = FindMappingKey(&parts, GetLegacyKey(key, baxy_mapping)); - } - if (i >= 0) { - result = true; - } - FreeMappingParts(&parts); - - return result; -} - -static char *GetMappingValue(const char *mapping, const char *key) -{ - int i; - MappingParts parts; - char *value = NULL; - - SplitMapping(mapping, &parts); - i = FindMappingKey(&parts, key); - if (i < 0) { - bool baxy_mapping = false; - - if (mapping && SDL_strstr(mapping, ",hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1") != NULL) { - baxy_mapping = true; - } - i = FindMappingKey(&parts, GetLegacyKey(key, baxy_mapping)); - } - if (i >= 0) { - value = parts.values[i]; - parts.values[i] = NULL; /* So we don't free it */ - } - FreeMappingParts(&parts); - - return value; -} - -static char *SetMappingValue(char *mapping, const char *key, const char *value) -{ - MappingParts parts; - int i; - char *new_key = NULL; - char *new_value = NULL; - char **new_keys = NULL; - char **new_values = NULL; - bool result = false; - - if (!key) { - return mapping; - } - - SplitMapping(mapping, &parts); - i = FindMappingKey(&parts, key); - if (i >= 0) { - new_value = SDL_strdup(value); - if (new_value) { - SDL_free(parts.values[i]); - parts.values[i] = new_value; - result = true; - } - } else { - int count = parts.num_elements; - - new_key = SDL_strdup(key); - if (new_key) { - new_value = SDL_strdup(value); - if (new_value) { - new_keys = (char **)SDL_realloc(parts.keys, (count + 1) * sizeof(*new_keys)); - if (new_keys) { - new_values = (char **)SDL_realloc(parts.values, (count + 1) * sizeof(*new_values)); - if (new_values) { - new_keys[count] = new_key; - new_values[count] = new_value; - parts.num_elements = (count + 1); - parts.keys = new_keys; - parts.values = new_values; - result = true; - } - } - } - } - } - - if (result) { - mapping = RecreateMapping(&parts, mapping); - } else { - SDL_free(new_key); - SDL_free(new_value); - SDL_free(new_keys); - SDL_free(new_values); - } - return mapping; -} - -static char *RemoveMappingValue(char *mapping, const char *key) -{ - MappingParts parts; - int i; - - SplitMapping(mapping, &parts); - i = FindMappingKey(&parts, key); - if (i >= 0) { - RemoveMappingValueAt(&parts, i); - } - return RecreateMapping(&parts, mapping); -} - -bool MappingHasBindings(const char *mapping) -{ - MappingParts parts; - int i; - bool result = false; - - if (!mapping || !*mapping) { - return false; - } - - SplitMapping(mapping, &parts); - for (i = 0; i < SDL_GAMEPAD_BUTTON_COUNT; ++i) { - if (FindMappingKey(&parts, SDL_GetGamepadStringForButton((SDL_GamepadButton)i)) >= 0) { - result = true; - break; - } - } - if (!result) { - for (i = 0; i < SDL_GAMEPAD_AXIS_COUNT; ++i) { - if (FindMappingKey(&parts, SDL_GetGamepadStringForAxis((SDL_GamepadAxis)i)) >= 0) { - result = true; - break; - } - } - } - FreeMappingParts(&parts); - - return result; -} - -bool MappingHasName(const char *mapping) -{ - MappingParts parts; - bool result; - - SplitMapping(mapping, &parts); - result = parts.name ? true : false; - FreeMappingParts(&parts); - return result; -} - -char *GetMappingName(const char *mapping) -{ - MappingParts parts; - char *name; - - SplitMapping(mapping, &parts); - name = parts.name; - parts.name = NULL; /* Don't free the name we're about to return */ - FreeMappingParts(&parts); - return name; -} - -char *SetMappingName(char *mapping, const char *name) -{ - MappingParts parts; - char *new_name, *spot; - size_t length; - - if (!name) { - return mapping; - } - - /* Remove any leading whitespace */ - while (*name && SDL_isspace(*name)) { - ++name; - } - - new_name = SDL_strdup(name); - if (!new_name) { - return mapping; - } - - /* Remove any commas, which are field separators in the mapping */ - length = SDL_strlen(new_name); - while ((spot = SDL_strchr(new_name, ',')) != NULL) { - SDL_memmove(spot, spot + 1, length - (spot - new_name) + 1); - --length; - } - - /* Remove any trailing whitespace */ - while (length > 0 && SDL_isspace(new_name[length - 1])) { - --length; - } - - /* See if we have anything left */ - if (length == 0) { - SDL_free(new_name); - return mapping; - } - - /* null terminate to cut off anything we've trimmed */ - new_name[length] = '\0'; - - SplitMapping(mapping, &parts); - SDL_free(parts.name); - parts.name = new_name; - return RecreateMapping(&parts, mapping); -} - - -const char *GetGamepadTypeString(SDL_GamepadType type) -{ - switch (type) { - case SDL_GAMEPAD_TYPE_XBOX360: - return "Xbox 360"; - case SDL_GAMEPAD_TYPE_XBOXONE: - return "Xbox One"; - case SDL_GAMEPAD_TYPE_PS3: - return "PS3"; - case SDL_GAMEPAD_TYPE_PS4: - return "PS4"; - case SDL_GAMEPAD_TYPE_PS5: - return "PS5"; - case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO: - return "Nintendo Switch"; - case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT: - return "Joy-Con (L)"; - case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT: - return "Joy-Con (R)"; - case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR: - return "Joy-Con Pair"; - default: - return ""; - } -} - -SDL_GamepadType GetMappingType(const char *mapping) -{ - return SDL_GetGamepadTypeFromString(GetMappingValue(mapping, "type")); -} - -char *SetMappingType(char *mapping, SDL_GamepadType type) -{ - const char *type_string = SDL_GetGamepadStringForType(type); - if (!type_string || type == SDL_GAMEPAD_TYPE_UNKNOWN) { - return RemoveMappingValue(mapping, "type"); - } else { - return SetMappingValue(mapping, "type", type_string); - } -} - -static const char *GetElementKey(int element) -{ - if (element < SDL_GAMEPAD_BUTTON_COUNT) { - return SDL_GetGamepadStringForButton((SDL_GamepadButton)element); - } else { - static char key[16]; - - switch (element) { - case SDL_GAMEPAD_ELEMENT_AXIS_LEFTX_NEGATIVE: - SDL_snprintf(key, sizeof(key), "-%s", SDL_GetGamepadStringForAxis(SDL_GAMEPAD_AXIS_LEFTX)); - break; - case SDL_GAMEPAD_ELEMENT_AXIS_LEFTX_POSITIVE: - SDL_snprintf(key, sizeof(key), "+%s", SDL_GetGamepadStringForAxis(SDL_GAMEPAD_AXIS_LEFTX)); - break; - case SDL_GAMEPAD_ELEMENT_AXIS_LEFTY_NEGATIVE: - SDL_snprintf(key, sizeof(key), "-%s", SDL_GetGamepadStringForAxis(SDL_GAMEPAD_AXIS_LEFTY)); - break; - case SDL_GAMEPAD_ELEMENT_AXIS_LEFTY_POSITIVE: - SDL_snprintf(key, sizeof(key), "+%s", SDL_GetGamepadStringForAxis(SDL_GAMEPAD_AXIS_LEFTY)); - break; - case SDL_GAMEPAD_ELEMENT_AXIS_RIGHTX_NEGATIVE: - SDL_snprintf(key, sizeof(key), "-%s", SDL_GetGamepadStringForAxis(SDL_GAMEPAD_AXIS_RIGHTX)); - break; - case SDL_GAMEPAD_ELEMENT_AXIS_RIGHTX_POSITIVE: - SDL_snprintf(key, sizeof(key), "+%s", SDL_GetGamepadStringForAxis(SDL_GAMEPAD_AXIS_RIGHTX)); - break; - case SDL_GAMEPAD_ELEMENT_AXIS_RIGHTY_NEGATIVE: - SDL_snprintf(key, sizeof(key), "-%s", SDL_GetGamepadStringForAxis(SDL_GAMEPAD_AXIS_RIGHTY)); - break; - case SDL_GAMEPAD_ELEMENT_AXIS_RIGHTY_POSITIVE: - SDL_snprintf(key, sizeof(key), "+%s", SDL_GetGamepadStringForAxis(SDL_GAMEPAD_AXIS_RIGHTY)); - break; - case SDL_GAMEPAD_ELEMENT_AXIS_LEFT_TRIGGER: - return SDL_GetGamepadStringForAxis(SDL_GAMEPAD_AXIS_LEFT_TRIGGER); - case SDL_GAMEPAD_ELEMENT_AXIS_RIGHT_TRIGGER: - return SDL_GetGamepadStringForAxis(SDL_GAMEPAD_AXIS_RIGHT_TRIGGER); - default: - return NULL; - } - return key; - } -} - -bool MappingHasElement(const char *mapping, int element) -{ - const char *key; - - key = GetElementKey(element); - if (!key) { - return false; - } - return MappingHasKey(mapping, key); -} - -char *GetElementBinding(const char *mapping, int element) -{ - const char *key; - - key = GetElementKey(element); - if (!key) { - return NULL; - } - return GetMappingValue(mapping, key); -} - -char *SetElementBinding(char *mapping, int element, const char *binding) -{ - if (binding) { - return SetMappingValue(mapping, GetElementKey(element), binding); - } else { - return RemoveMappingValue(mapping, GetElementKey(element)); - } -} - -int GetElementForBinding(char *mapping, const char *binding) -{ - MappingParts parts; - int i, element; - int result = SDL_GAMEPAD_ELEMENT_INVALID; - - if (!binding) { - return SDL_GAMEPAD_ELEMENT_INVALID; - } - - SplitMapping(mapping, &parts); - for (i = 0; i < parts.num_elements; ++i) { - if (SDL_strcmp(binding, parts.values[i]) == 0) { - for (element = 0; element < SDL_GAMEPAD_ELEMENT_MAX; ++element) { - const char *key = GetElementKey(element); - if (key && SDL_strcmp(key, parts.keys[i]) == 0) { - result = element; - break; - } - } - break; - } - } - FreeMappingParts(&parts); - - return result; -} - -bool MappingHasBinding(const char *mapping, const char *binding) -{ - MappingParts parts; - int i; - bool result = false; - - if (!binding) { - return false; - } - - SplitMapping(mapping, &parts); - for (i = 0; i < parts.num_elements; ++i) { - if (SDL_strcmp(binding, parts.values[i]) == 0) { - result = true; - break; - } - } - FreeMappingParts(&parts); - - return result; -} - -char *ClearMappingBinding(char *mapping, const char *binding) -{ - MappingParts parts; - int i; - bool modified = false; - - if (!binding) { - return mapping; - } - - SplitMapping(mapping, &parts); - for (i = parts.num_elements - 1; i >= 0; --i) { - if (SDL_strcmp(binding, parts.values[i]) == 0) { - RemoveMappingValueAt(&parts, i); - modified = true; - } - } - if (modified) { - return RecreateMapping(&parts, mapping); - } else { - FreeMappingParts(&parts); - return mapping; - } -} -- cgit v1.2.3