Added the ability to rename your controller

main
Sam Lantinga 2023-07-16 15:11:24 -07:00
parent 08db0e8f64
commit 57820071a4
2 changed files with 167 additions and 20 deletions

View File

@ -2423,7 +2423,7 @@ char *SetMappingName(char *mapping, const char *name)
/* 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);
SDL_memmove(spot, spot + 1, length - (spot - new_name) + 1);
--length;
}

View File

@ -86,6 +86,10 @@ static int binding_element = SDL_GAMEPAD_ELEMENT_INVALID;
static int last_binding_element = SDL_GAMEPAD_ELEMENT_INVALID;
static SDL_bool binding_flow = SDL_FALSE;
static Uint64 binding_advance_time = 0;
static SDL_FRect title_area;
static SDL_bool title_highlighted;
static SDL_bool title_pressed;
static char *controller_name;
static SDL_Joystick *virtual_joystick = NULL;
static SDL_GamepadAxis virtual_axis_active = SDL_GAMEPAD_AXIS_INVALID;
static float virtual_axis_start_x;
@ -203,6 +207,9 @@ static void CyclePS5TriggerEffect(Controller *device)
static void ClearButtonHighlights(void)
{
title_highlighted = SDL_FALSE;
title_pressed = SDL_FALSE;
ClearGamepadImage(image);
SetGamepadDisplayHighlight(gamepad_elements, SDL_GAMEPAD_ELEMENT_INVALID, SDL_FALSE);
SetGamepadButtonHighlight(setup_mapping_button, SDL_FALSE, SDL_FALSE);
@ -220,9 +227,20 @@ static void UpdateButtonHighlights(float x, float y, SDL_bool button_down)
if (display_mode == CONTROLLER_MODE_TESTING) {
SetGamepadButtonHighlight(setup_mapping_button, GamepadButtonContains(setup_mapping_button, x, y), button_down);
} else if (display_mode == CONTROLLER_MODE_BINDING) {
SDL_FPoint point;
int gamepad_highlight_element = SDL_GAMEPAD_ELEMENT_INVALID;
char *joystick_highlight_element;
point.x = x;
point.y = y;
if (SDL_PointInRectFloat(&point, &title_area)) {
title_highlighted = SDL_TRUE;
title_pressed = button_down;
} else {
title_highlighted = SDL_FALSE;
title_pressed = SDL_FALSE;
}
if (controller->joystick != virtual_joystick) {
gamepad_highlight_element = GetGamepadImageElementAt(image, x, y);
}
@ -254,6 +272,20 @@ static int StandardizeAxisValue(int nValue)
}
}
static void RefreshControllerName(void)
{
SDL_free(controller_name);
controller_name = NULL;
if (controller) {
if (controller->gamepad) {
controller_name = SDL_strdup(SDL_GetGamepadName(controller->gamepad));
} else {
controller_name = SDL_strdup(SDL_GetJoystickName(controller->joystick));
}
}
}
static void SetAndFreeGamepadMapping(char *mapping)
{
SDL_SetGamepadMapping(controller->id, mapping);
@ -264,6 +296,10 @@ static void SetCurrentBindingElement(int element, SDL_bool flow)
{
int i;
if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) {
RefreshControllerName();
}
if (element == SDL_GAMEPAD_ELEMENT_INVALID) {
last_binding_element = SDL_GAMEPAD_ELEMENT_INVALID;
} else {
@ -507,6 +543,7 @@ static void PasteMapping(void)
if (MappingHasBindings(mapping)) {
StopBinding();
SetAndFreeGamepadMapping(mapping);
RefreshControllerName();
} else {
/* Not a valid mapping, ignore it */
SDL_free(mapping);
@ -514,6 +551,61 @@ static void PasteMapping(void)
}
}
static void CommitControllerName(void)
{
char *mapping = NULL;
if (controller->mapping) {
mapping = SDL_strdup(controller->mapping);
} else {
mapping = NULL;
}
mapping = SetMappingName(mapping, controller_name);
SetAndFreeGamepadMapping(mapping);
}
static void AddControllerNameText(const char *text)
{
size_t current_length = (controller_name ? SDL_strlen(controller_name) : 0);
size_t text_length = SDL_strlen(text);
size_t size = current_length + text_length + 1;
char *name = (char *)SDL_realloc(controller_name, size);
if (name) {
SDL_memcpy(&name[current_length], text, text_length + 1);
controller_name = name;
}
CommitControllerName();
}
static void BackspaceControllerName(void)
{
size_t length = (controller_name ? SDL_strlen(controller_name) : 0);
if (length > 0) {
controller_name[length - 1] = '\0';
}
CommitControllerName();
}
static void ClearControllerName(void)
{
if (controller_name) {
*controller_name = '\0';
}
CommitControllerName();
}
static void CopyControllerName(void)
{
SDL_SetClipboardText(controller_name);
}
static void PasteControllerName(void)
{
SDL_free(controller_name);
controller_name = SDL_GetClipboardText();
CommitControllerName();
}
static const char *GetBindingInstruction(void)
{
switch (binding_element) {
@ -631,6 +723,8 @@ static void SetController(SDL_JoystickID id)
} else {
controller = NULL;
}
RefreshControllerName();
}
static void HandleGamepadRemapped(SDL_JoystickID id)
@ -644,6 +738,7 @@ static void HandleGamepadRemapped(SDL_JoystickID id)
if (!controllers[i].gamepad) {
controllers[i].gamepad = SDL_OpenGamepad(id);
RefreshControllerName();
}
/* Get the current mapping */
@ -814,7 +909,7 @@ static SDL_bool ShowingFront(void)
break;
}
}
if (SDL_GetModState() & SDL_KMOD_SHIFT) {
if ((SDL_GetModState() & SDL_KMOD_SHIFT) && binding_element != SDL_GAMEPAD_ELEMENT_NAME) {
showing_front = SDL_FALSE;
}
return showing_front;
@ -1002,20 +1097,29 @@ static void DrawGamepadWaiting(SDL_Renderer *renderer)
static void DrawGamepadInfo(SDL_Renderer *renderer)
{
const char *name;
const char *serial;
char text[128];
float x, y;
if (controller->gamepad) {
name = SDL_GetGamepadName(controller->gamepad);
} else {
name = SDL_GetJoystickName(controller->joystick);
if (title_highlighted) {
Uint8 r, g, b, a;
SDL_GetRenderDrawColor(renderer, &r, &g, &b, &a);
if (title_pressed) {
SDL_SetRenderDrawColor(renderer, PRESSED_COLOR);
} else {
SDL_SetRenderDrawColor(renderer, HIGHLIGHT_COLOR);
}
SDL_RenderFillRect(renderer, &title_area);
SDL_SetRenderDrawColor(renderer, r, g, b, a);
}
if (name && *name) {
x = (float)SCREEN_WIDTH / 2 - (FONT_CHARACTER_SIZE * SDL_strlen(name)) / 2;
if (controller_name && *controller_name) {
x = (float)SCREEN_WIDTH / 2 - (FONT_CHARACTER_SIZE * SDL_strlen(controller_name)) / 2;
y = (float)TITLE_HEIGHT / 2 - FONT_CHARACTER_SIZE / 2;
SDLTest_DrawString(renderer, x, y, name);
SDLTest_DrawString(renderer, x, y, controller_name);
}
if (SDL_IsJoystickVirtual(controller->id)) {
@ -1079,12 +1183,16 @@ static void DrawBindingTips(SDL_Renderer *renderer)
y += (FONT_CHARACTER_SIZE + BUTTON_MARGIN);
bound_A = MappingHasElement(controller->mapping, SDL_GAMEPAD_BUTTON_A);
bound_B = MappingHasElement(controller->mapping, SDL_GAMEPAD_BUTTON_B);
if (binding_flow && bound_A && bound_B) {
text = "(press A to skip, B to go back, and ESC to cancel)";
if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) {
text = "(press RETURN to complete)";
} else {
text = "(press SPACE to clear binding and ESC to cancel)";
bound_A = MappingHasElement(controller->mapping, SDL_GAMEPAD_BUTTON_A);
bound_B = MappingHasElement(controller->mapping, SDL_GAMEPAD_BUTTON_B);
if (binding_flow && bound_A && bound_B) {
text = "(press A to skip, B to go back, and ESC to cancel)";
} else {
text = "(press SPACE to clear binding and ESC to cancel)";
}
}
SDLTest_DrawString(renderer, (float)x - (FONT_CHARACTER_SIZE * SDL_strlen(text)) / 2, (float)y, text);
}
@ -1357,6 +1465,8 @@ static void loop(void *arg)
CopyMapping();
} else if (GamepadButtonContains(paste_button, event.button.x, event.button.y)) {
PasteMapping();
} else if (title_pressed) {
SetCurrentBindingElement(SDL_GAMEPAD_ELEMENT_NAME, SDL_FALSE);
} else {
int gamepad_element = SDL_GAMEPAD_ELEMENT_INVALID;
char *joystick_element;
@ -1408,14 +1518,38 @@ static void loop(void *arg)
}
} else if (display_mode == CONTROLLER_MODE_BINDING) {
if (event.key.keysym.sym == SDLK_c && (event.key.keysym.mod & SDL_KMOD_CTRL)) {
CopyMapping();
if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) {
CopyControllerName();
} else {
CopyMapping();
}
} else if (event.key.keysym.sym == SDLK_v && (event.key.keysym.mod & SDL_KMOD_CTRL)) {
PasteMapping();
if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) {
ClearControllerName();
PasteControllerName();
} else {
PasteMapping();
}
} else if (event.key.keysym.sym == SDLK_x && (event.key.keysym.mod & SDL_KMOD_CTRL)) {
CopyMapping();
ClearMapping();
if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) {
CopyControllerName();
ClearControllerName();
} else {
CopyMapping();
ClearMapping();
}
} else if (event.key.keysym.sym == SDLK_SPACE) {
ClearBinding();
if (binding_element != SDL_GAMEPAD_ELEMENT_NAME) {
ClearBinding();
}
} else if (event.key.keysym.sym == SDLK_BACKSPACE) {
if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) {
BackspaceControllerName();
}
} else if (event.key.keysym.sym == SDLK_RETURN) {
if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) {
StopBinding();
}
} else if (event.key.keysym.sym == SDLK_ESCAPE) {
if (binding_element != SDL_GAMEPAD_ELEMENT_INVALID) {
StopBinding();
@ -1425,6 +1559,13 @@ static void loop(void *arg)
}
}
break;
case SDL_EVENT_TEXT_INPUT:
if (display_mode == CONTROLLER_MODE_BINDING) {
if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) {
AddControllerNameText(event.text.text);
}
}
break;
case SDL_EVENT_QUIT:
done = SDL_TRUE;
break;
@ -1594,6 +1735,12 @@ int main(int argc, char *argv[])
SDL_LOGICAL_PRESENTATION_LETTERBOX,
SDL_SCALEMODE_LINEAR);
title_area.w = (float)GAMEPAD_WIDTH;
title_area.h = (float)FONT_CHARACTER_SIZE + 2 * BUTTON_MARGIN;
title_area.x = (float)PANEL_WIDTH + PANEL_SPACING;
title_area.y = (float)TITLE_HEIGHT / 2 - title_area.h / 2;
image = CreateGamepadImage(screen);
if (image == NULL) {
SDL_DestroyRenderer(screen);