mirror of
				https://github.com/libsdl-org/SDL.git
				synced 2025-10-26 12:27:44 +00:00 
			
		
		
		
	Added a button to copy the gamepad mapping to the clipboard
This commit is contained in:
		| @@ -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); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Sam Lantinga
					Sam Lantinga