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_axis.h" | ||||
| #include "gamepad_axis_arrow.h" | ||||
| #include "gamepad_button_background.h" | ||||
|  | ||||
| /* This is indexed by SDL_GamepadButton. */ | ||||
| static const struct | ||||
| @@ -612,6 +613,10 @@ void RenderGamepadDisplay(GamepadDisplay *ctx, SDL_Gamepad *gamepad) | ||||
|     SDL_bool has_accel; | ||||
|     SDL_bool has_gyro; | ||||
|  | ||||
|     if (!ctx) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     SDL_GetRenderDrawColor(ctx->renderer, &r, &g, &b, &a); | ||||
|  | ||||
|     x = ctx->area.x + margin; | ||||
| @@ -776,6 +781,12 @@ void RenderGamepadDisplay(GamepadDisplay *ctx, SDL_Gamepad *gamepad) | ||||
|  | ||||
| void DestroyGamepadDisplay(GamepadDisplay *ctx) | ||||
| { | ||||
|     if (!ctx) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     SDL_DestroyTexture(ctx->button_texture); | ||||
|     SDL_DestroyTexture(ctx->arrow_texture); | ||||
|     SDL_free(ctx); | ||||
| } | ||||
|  | ||||
| @@ -834,6 +845,10 @@ void RenderJoystickDisplay(JoystickDisplay *ctx, SDL_Joystick *joystick) | ||||
|     SDL_FRect dst, rect; | ||||
|     Uint8 r, g, b, a; | ||||
|  | ||||
|     if (!ctx) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     SDL_GetRenderDrawColor(ctx->renderer, &r, &g, &b, &a); | ||||
|  | ||||
|     x = (float)ctx->area.x + margin; | ||||
| @@ -993,6 +1008,195 @@ void RenderJoystickDisplay(JoystickDisplay *ctx, SDL_Joystick *joystick) | ||||
|  | ||||
| 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; | ||||
|     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 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 PANEL_SPACING 25 | ||||
| #define PANEL_WIDTH 250 | ||||
| #define BUTTON_MARGIN 8 | ||||
| #define BUTTON_PADDING 12 | ||||
| #define GAMEPAD_WIDTH 512 | ||||
| #define GAMEPAD_HEIGHT 480 | ||||
|  | ||||
| @@ -49,6 +51,8 @@ static SDL_Renderer *screen = NULL; | ||||
| static GamepadImage *image = NULL; | ||||
| static GamepadDisplay *gamepad_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 done = 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) | ||||
| { | ||||
|     SDL_Event event; | ||||
| @@ -687,18 +718,24 @@ static void loop(void *arg) | ||||
|             if (virtual_joystick) { | ||||
|                 VirtualGamepadMouseDown(event.button.x, event.button.y); | ||||
|             } | ||||
|             SetGamepadButtonHighlight(copy_button, GamepadButtonContains(copy_button, event.button.x, event.button.y)); | ||||
|             break; | ||||
|  | ||||
|         case SDL_EVENT_MOUSE_BUTTON_UP: | ||||
|             if (virtual_joystick) { | ||||
|                 VirtualGamepadMouseUp(event.button.x, event.button.y); | ||||
|             } | ||||
|             if (GamepadButtonContains(copy_button, event.button.x, event.button.y)) { | ||||
|                 CopyMappingToClipboard(); | ||||
|             } | ||||
|             SetGamepadButtonHighlight(copy_button, SDL_FALSE); | ||||
|             break; | ||||
|  | ||||
|         case SDL_EVENT_MOUSE_MOTION: | ||||
|             if (virtual_joystick) { | ||||
|                 VirtualGamepadMouseMotion(event.motion.x, event.motion.y); | ||||
|             } | ||||
|             SetGamepadButtonHighlight(copy_button, event.motion.state && GamepadButtonContains(copy_button, event.motion.x, event.motion.y)); | ||||
|             break; | ||||
|  | ||||
|         case SDL_EVENT_KEY_DOWN: | ||||
| @@ -743,6 +780,8 @@ static void loop(void *arg) | ||||
|         RenderGamepadDisplay(gamepad_elements, gamepad); | ||||
|         RenderJoystickDisplay(joystick_elements, SDL_GetGamepadJoystick(gamepad)); | ||||
|  | ||||
|         RenderGamepadButton(copy_button); | ||||
|  | ||||
|         DrawGamepadInfo(screen); | ||||
|  | ||||
|         /* Update LED based on left thumbstick position */ | ||||
| @@ -811,6 +850,7 @@ int main(int argc, char *argv[]) | ||||
|     int i; | ||||
|     float content_scale; | ||||
|     int screen_width, screen_height; | ||||
|     int button_width, button_height; | ||||
|     int gamepad_index = -1; | ||||
|     SDLTest_CommonState *state; | ||||
|  | ||||
| @@ -924,6 +964,11 @@ int main(int argc, char *argv[]) | ||||
|     joystick_elements = CreateJoystickDisplay(screen); | ||||
|     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 */ | ||||
|     loop(NULL); | ||||
|  | ||||
| @@ -953,6 +998,7 @@ int main(int argc, char *argv[]) | ||||
|     DestroyGamepadImage(image); | ||||
|     DestroyGamepadDisplay(gamepad_elements); | ||||
|     DestroyJoystickDisplay(joystick_elements); | ||||
|     DestroyGamepadButton(copy_button); | ||||
|     SDL_DestroyRenderer(screen); | ||||
|     SDL_DestroyWindow(window); | ||||
|     SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Sam Lantinga
					Sam Lantinga