Added a button to copy the gamepad mapping to the clipboard
parent
4f122c6e39
commit
4feb2f4b1a
|
@ -26,6 +26,7 @@
|
||||||
#include "gamepad_button_small.h"
|
#include "gamepad_button_small.h"
|
||||||
#include "gamepad_axis.h"
|
#include "gamepad_axis.h"
|
||||||
#include "gamepad_axis_arrow.h"
|
#include "gamepad_axis_arrow.h"
|
||||||
|
#include "gamepad_button_background.h"
|
||||||
|
|
||||||
/* This is indexed by SDL_GamepadButton. */
|
/* This is indexed by SDL_GamepadButton. */
|
||||||
static const struct
|
static const struct
|
||||||
|
@ -612,6 +613,10 @@ void RenderGamepadDisplay(GamepadDisplay *ctx, SDL_Gamepad *gamepad)
|
||||||
SDL_bool has_accel;
|
SDL_bool has_accel;
|
||||||
SDL_bool has_gyro;
|
SDL_bool has_gyro;
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_GetRenderDrawColor(ctx->renderer, &r, &g, &b, &a);
|
SDL_GetRenderDrawColor(ctx->renderer, &r, &g, &b, &a);
|
||||||
|
|
||||||
x = ctx->area.x + margin;
|
x = ctx->area.x + margin;
|
||||||
|
@ -776,6 +781,12 @@ void RenderGamepadDisplay(GamepadDisplay *ctx, SDL_Gamepad *gamepad)
|
||||||
|
|
||||||
void DestroyGamepadDisplay(GamepadDisplay *ctx)
|
void DestroyGamepadDisplay(GamepadDisplay *ctx)
|
||||||
{
|
{
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_DestroyTexture(ctx->button_texture);
|
||||||
|
SDL_DestroyTexture(ctx->arrow_texture);
|
||||||
SDL_free(ctx);
|
SDL_free(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -834,6 +845,10 @@ void RenderJoystickDisplay(JoystickDisplay *ctx, SDL_Joystick *joystick)
|
||||||
SDL_FRect dst, rect;
|
SDL_FRect dst, rect;
|
||||||
Uint8 r, g, b, a;
|
Uint8 r, g, b, a;
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_GetRenderDrawColor(ctx->renderer, &r, &g, &b, &a);
|
SDL_GetRenderDrawColor(ctx->renderer, &r, &g, &b, &a);
|
||||||
|
|
||||||
x = (float)ctx->area.x + margin;
|
x = (float)ctx->area.x + margin;
|
||||||
|
@ -993,6 +1008,195 @@ void RenderJoystickDisplay(JoystickDisplay *ctx, SDL_Joystick *joystick)
|
||||||
|
|
||||||
void DestroyJoystickDisplay(JoystickDisplay *ctx)
|
void DestroyJoystickDisplay(JoystickDisplay *ctx)
|
||||||
{
|
{
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_DestroyTexture(ctx->button_texture);
|
||||||
|
SDL_DestroyTexture(ctx->arrow_texture);
|
||||||
SDL_free(ctx);
|
SDL_free(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct GamepadButton
|
||||||
|
{
|
||||||
|
SDL_Renderer *renderer;
|
||||||
|
SDL_Texture *background;
|
||||||
|
int background_width;
|
||||||
|
int background_height;
|
||||||
|
|
||||||
|
SDL_FRect area;
|
||||||
|
|
||||||
|
char *label;
|
||||||
|
int label_width;
|
||||||
|
int label_height;
|
||||||
|
|
||||||
|
SDL_bool highlight;
|
||||||
|
};
|
||||||
|
|
||||||
|
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_QueryTexture(ctx->background, NULL, NULL, &ctx->background_width, &ctx->background_height);
|
||||||
|
|
||||||
|
ctx->label = SDL_strdup(label);
|
||||||
|
ctx->label_width = (int)(FONT_CHARACTER_SIZE * SDL_strlen(label));
|
||||||
|
ctx->label_height = FONT_CHARACTER_SIZE;
|
||||||
|
}
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetGamepadButtonArea(GamepadButton *ctx, int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->area.x = (float)x;
|
||||||
|
ctx->area.y = (float)y;
|
||||||
|
ctx->area.w = (float)w;
|
||||||
|
ctx->area.h = (float)h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetGamepadButtonHighlight(GamepadButton *ctx, SDL_bool highlight)
|
||||||
|
{
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->highlight = highlight;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetGamepadButtonLabelWidth(GamepadButton *ctx)
|
||||||
|
{
|
||||||
|
if (!ctx) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx->label_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetGamepadButtonLabelHeight(GamepadButton *ctx)
|
||||||
|
{
|
||||||
|
if (!ctx) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx->label_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_bool GamepadButtonContains(GamepadButton *ctx, float x, float y)
|
||||||
|
{
|
||||||
|
SDL_FPoint point;
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
return SDL_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 = (float)ctx->background_width / 3;
|
||||||
|
one_third_src_height = (float)ctx->background_height / 3;
|
||||||
|
|
||||||
|
if (ctx->highlight) {
|
||||||
|
SDL_SetTextureColorMod(ctx->background, 10, 255, 21);
|
||||||
|
} 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 = (float)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 = (float)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 = (float)ctx->area.h - 2 * one_third_src_height;
|
||||||
|
SDL_RenderTexture(ctx->renderer, ctx->background, &src, &dst);
|
||||||
|
|
||||||
|
/* Right */
|
||||||
|
src.x = (float)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 = (float)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 = (float)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);
|
||||||
|
}
|
||||||
|
|
|
@ -54,3 +54,15 @@ extern void SetJoystickDisplayArea(JoystickDisplay *ctx, int x, int y, int w, in
|
||||||
extern void RenderJoystickDisplay(JoystickDisplay *ctx, SDL_Joystick *joystick);
|
extern void RenderJoystickDisplay(JoystickDisplay *ctx, SDL_Joystick *joystick);
|
||||||
extern void DestroyJoystickDisplay(JoystickDisplay *ctx);
|
extern void DestroyJoystickDisplay(JoystickDisplay *ctx);
|
||||||
|
|
||||||
|
/* Simple buttons */
|
||||||
|
|
||||||
|
typedef struct GamepadButton GamepadButton;
|
||||||
|
|
||||||
|
extern GamepadButton *CreateGamepadButton(SDL_Renderer *renderer, const char *label);
|
||||||
|
extern void SetGamepadButtonArea(GamepadButton *ctx, int x, int y, int w, int h);
|
||||||
|
extern void SetGamepadButtonHighlight(GamepadButton *ctx, SDL_bool highlight);
|
||||||
|
extern int GetGamepadButtonLabelWidth(GamepadButton *ctx);
|
||||||
|
extern int GetGamepadButtonLabelHeight(GamepadButton *ctx);
|
||||||
|
extern SDL_bool GamepadButtonContains(GamepadButton *ctx, float x, float y);
|
||||||
|
extern void RenderGamepadButton(GamepadButton *ctx);
|
||||||
|
extern void DestroyGamepadButton(GamepadButton *ctx);
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#define TITLE_HEIGHT 48
|
#define TITLE_HEIGHT 48
|
||||||
#define PANEL_SPACING 25
|
#define PANEL_SPACING 25
|
||||||
#define PANEL_WIDTH 250
|
#define PANEL_WIDTH 250
|
||||||
|
#define BUTTON_MARGIN 8
|
||||||
|
#define BUTTON_PADDING 12
|
||||||
#define GAMEPAD_WIDTH 512
|
#define GAMEPAD_WIDTH 512
|
||||||
#define GAMEPAD_HEIGHT 480
|
#define GAMEPAD_HEIGHT 480
|
||||||
|
|
||||||
|
@ -49,6 +51,8 @@ static SDL_Renderer *screen = NULL;
|
||||||
static GamepadImage *image = NULL;
|
static GamepadImage *image = NULL;
|
||||||
static GamepadDisplay *gamepad_elements = NULL;
|
static GamepadDisplay *gamepad_elements = NULL;
|
||||||
static JoystickDisplay *joystick_elements = NULL;
|
static JoystickDisplay *joystick_elements = NULL;
|
||||||
|
static GamepadButton *copy_button = NULL;
|
||||||
|
static SDL_bool in_copy_button = SDL_FALSE;
|
||||||
static SDL_bool retval = SDL_FALSE;
|
static SDL_bool retval = SDL_FALSE;
|
||||||
static SDL_bool done = SDL_FALSE;
|
static SDL_bool done = SDL_FALSE;
|
||||||
static SDL_bool set_LED = SDL_FALSE;
|
static SDL_bool set_LED = SDL_FALSE;
|
||||||
|
@ -594,6 +598,33 @@ static void DrawGamepadInfo(SDL_Renderer *renderer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void CopyMappingToClipboard()
|
||||||
|
{
|
||||||
|
char *mapping = SDL_GetGamepadMapping(gamepad);
|
||||||
|
if (mapping) {
|
||||||
|
const char *name = SDL_GetGamepadName(gamepad);
|
||||||
|
char *wildcard = SDL_strchr(mapping, '*');
|
||||||
|
if (wildcard && name && *name) {
|
||||||
|
char *text;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
/* Personalize the mapping for this controller */
|
||||||
|
*wildcard++ = '\0';
|
||||||
|
size = SDL_strlen(mapping) + SDL_strlen(name) + SDL_strlen(wildcard) + 1;
|
||||||
|
text = SDL_malloc(size);
|
||||||
|
if (!text) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SDL_snprintf(text, size, "%s%s%s", mapping, name, wildcard);
|
||||||
|
SDL_SetClipboardText(text);
|
||||||
|
SDL_free(text);
|
||||||
|
} else {
|
||||||
|
SDL_SetClipboardText(mapping);
|
||||||
|
}
|
||||||
|
SDL_free(mapping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void loop(void *arg)
|
static void loop(void *arg)
|
||||||
{
|
{
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
|
@ -687,18 +718,24 @@ static void loop(void *arg)
|
||||||
if (virtual_joystick) {
|
if (virtual_joystick) {
|
||||||
VirtualGamepadMouseDown(event.button.x, event.button.y);
|
VirtualGamepadMouseDown(event.button.x, event.button.y);
|
||||||
}
|
}
|
||||||
|
SetGamepadButtonHighlight(copy_button, GamepadButtonContains(copy_button, event.button.x, event.button.y));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||||
if (virtual_joystick) {
|
if (virtual_joystick) {
|
||||||
VirtualGamepadMouseUp(event.button.x, event.button.y);
|
VirtualGamepadMouseUp(event.button.x, event.button.y);
|
||||||
}
|
}
|
||||||
|
if (GamepadButtonContains(copy_button, event.button.x, event.button.y)) {
|
||||||
|
CopyMappingToClipboard();
|
||||||
|
}
|
||||||
|
SetGamepadButtonHighlight(copy_button, SDL_FALSE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_MOUSE_MOTION:
|
case SDL_EVENT_MOUSE_MOTION:
|
||||||
if (virtual_joystick) {
|
if (virtual_joystick) {
|
||||||
VirtualGamepadMouseMotion(event.motion.x, event.motion.y);
|
VirtualGamepadMouseMotion(event.motion.x, event.motion.y);
|
||||||
}
|
}
|
||||||
|
SetGamepadButtonHighlight(copy_button, event.motion.state && GamepadButtonContains(copy_button, event.motion.x, event.motion.y));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_KEY_DOWN:
|
case SDL_EVENT_KEY_DOWN:
|
||||||
|
@ -743,6 +780,8 @@ static void loop(void *arg)
|
||||||
RenderGamepadDisplay(gamepad_elements, gamepad);
|
RenderGamepadDisplay(gamepad_elements, gamepad);
|
||||||
RenderJoystickDisplay(joystick_elements, SDL_GetGamepadJoystick(gamepad));
|
RenderJoystickDisplay(joystick_elements, SDL_GetGamepadJoystick(gamepad));
|
||||||
|
|
||||||
|
RenderGamepadButton(copy_button);
|
||||||
|
|
||||||
DrawGamepadInfo(screen);
|
DrawGamepadInfo(screen);
|
||||||
|
|
||||||
/* Update LED based on left thumbstick position */
|
/* Update LED based on left thumbstick position */
|
||||||
|
@ -811,6 +850,7 @@ int main(int argc, char *argv[])
|
||||||
int i;
|
int i;
|
||||||
float content_scale;
|
float content_scale;
|
||||||
int screen_width, screen_height;
|
int screen_width, screen_height;
|
||||||
|
int button_width, button_height;
|
||||||
int gamepad_index = -1;
|
int gamepad_index = -1;
|
||||||
SDLTest_CommonState *state;
|
SDLTest_CommonState *state;
|
||||||
|
|
||||||
|
@ -924,6 +964,11 @@ int main(int argc, char *argv[])
|
||||||
joystick_elements = CreateJoystickDisplay(screen);
|
joystick_elements = CreateJoystickDisplay(screen);
|
||||||
SetJoystickDisplayArea(joystick_elements, PANEL_WIDTH + PANEL_SPACING + GAMEPAD_WIDTH + PANEL_SPACING, TITLE_HEIGHT, PANEL_WIDTH, GAMEPAD_HEIGHT);
|
SetJoystickDisplayArea(joystick_elements, PANEL_WIDTH + PANEL_SPACING + GAMEPAD_WIDTH + PANEL_SPACING, TITLE_HEIGHT, PANEL_WIDTH, GAMEPAD_HEIGHT);
|
||||||
|
|
||||||
|
copy_button = CreateGamepadButton(screen, "Copy to Clipboard");
|
||||||
|
button_width = GetGamepadButtonLabelWidth(copy_button) + 2 * BUTTON_PADDING;
|
||||||
|
button_height = GetGamepadButtonLabelHeight(copy_button) + 2 * BUTTON_PADDING;
|
||||||
|
SetGamepadButtonArea(copy_button, BUTTON_MARGIN, SCREEN_HEIGHT - BUTTON_MARGIN - button_height, button_width, button_height);
|
||||||
|
|
||||||
/* Process the initial gamepad list */
|
/* Process the initial gamepad list */
|
||||||
loop(NULL);
|
loop(NULL);
|
||||||
|
|
||||||
|
@ -953,6 +998,7 @@ int main(int argc, char *argv[])
|
||||||
DestroyGamepadImage(image);
|
DestroyGamepadImage(image);
|
||||||
DestroyGamepadDisplay(gamepad_elements);
|
DestroyGamepadDisplay(gamepad_elements);
|
||||||
DestroyJoystickDisplay(joystick_elements);
|
DestroyJoystickDisplay(joystick_elements);
|
||||||
|
DestroyGamepadButton(copy_button);
|
||||||
SDL_DestroyRenderer(screen);
|
SDL_DestroyRenderer(screen);
|
||||||
SDL_DestroyWindow(window);
|
SDL_DestroyWindow(window);
|
||||||
SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD);
|
SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD);
|
||||||
|
|
Loading…
Reference in New Issue