diff --git a/test/gamepadutils.c b/test/gamepadutils.c index c2239d640..d3c2f1240 100644 --- a/test/gamepadutils.c +++ b/test/gamepadutils.c @@ -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; } diff --git a/test/testcontroller.c b/test/testcontroller.c index 666f24a5b..d8e67159e 100644 --- a/test/testcontroller.c +++ b/test/testcontroller.c @@ -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);