From 0c33bde3c77c9dd88972a02378e05f3d7572b09a Mon Sep 17 00:00:00 2001 From: MJacred Date: Sun, 3 Nov 2024 12:41:48 +0100 Subject: [PATCH] Fix Input::remove_joy_mapping Erasing a joypad mapping can invalidate other attached joypads and the fallback mapping guid --- core/input/input.cpp | 33 +++++++++++++++++++++++++++++++++ core/input/input.h | 3 ++- doc/classes/Input.xml | 18 ++++++++++++++++-- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/core/input/input.cpp b/core/input/input.cpp index 4117193c8b73..9312e386ae86 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -149,6 +149,8 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("get_vector", "negative_x", "positive_x", "negative_y", "positive_y", "deadzone"), &Input::get_vector, DEFVAL(-1.0f)); ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false)); ClassDB::bind_method(D_METHOD("remove_joy_mapping", "guid"), &Input::remove_joy_mapping); + ClassDB::bind_method(D_METHOD("set_fallback_mapping", "guid"), &Input::set_fallback_mapping); + ClassDB::bind_method(D_METHOD("get_fallback_mapping"), &Input::get_fallback_mapping); ClassDB::bind_method(D_METHOD("is_joy_known", "device"), &Input::is_joy_known); ClassDB::bind_method(D_METHOD("get_joy_axis", "device", "axis"), &Input::get_joy_axis); ClassDB::bind_method(D_METHOD("get_joy_name", "device"), &Input::get_joy_name); @@ -1693,15 +1695,41 @@ void Input::add_joy_mapping(const String &p_mapping, bool p_update_existing) { } void Input::remove_joy_mapping(const String &p_guid) { + int fallback_mapping_offset = 0; // Fix the fallback, if we invalidate its index. + for (int i = map_db.size() - 1; i >= 0; i--) { if (p_guid == map_db[i].uid) { map_db.remove_at(i); + + if (i == fallback_mapping) { + fallback_mapping = -1; + } + if (i < fallback_mapping) { + fallback_mapping_offset--; + } } } + + if (fallback_mapping_offset < 0) { + fallback_mapping += fallback_mapping_offset; + } + for (KeyValue &E : joy_names) { Joypad &joy = E.value; if (joy.uid == p_guid) { joy.mapping = -1; + } else if (joy.mapping == (fallback_mapping - fallback_mapping_offset)) { + // Fix the mapping for the joypad that uses an outdated fallback index. + joy.mapping = fallback_mapping; + } else { + // Re-validate the joypad's correct mapping. Fix it if necesary. + int mapping = -1; + for (int i = 0; i < map_db.size(); i++) { + if (joy.uid == map_db[i].uid) { + mapping = i; + } + } + joy.mapping = mapping; } } } @@ -1715,6 +1743,11 @@ void Input::set_fallback_mapping(const String &p_guid) { } } +String Input::get_fallback_mapping() const { + ERR_FAIL_COND_V(fallback_mapping == -1, ""); + return map_db[fallback_mapping].uid; +} + //platforms that use the remapping system can override and call to these ones bool Input::is_joy_known(int p_device) { if (joy_names.has(p_device)) { diff --git a/core/input/input.h b/core/input/input.h index a189ae7d9ada..7d08463b69db 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -184,7 +184,7 @@ class Input : public Object { HashSet ignored_device_ids; - int fallback_mapping = -1; + int fallback_mapping = -1; // Index of the guid in map_db. CursorShape default_shape = CURSOR_ARROW; @@ -373,6 +373,7 @@ class Input : public Object { bool should_ignore_device(int p_vendor_id, int p_product_id) const; Dictionary get_joy_info(int p_device) const; void set_fallback_mapping(const String &p_guid); + String get_fallback_mapping() const; #ifdef DEBUG_ENABLED void flush_frame_parsed_events(); diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index 6fe5b7a80229..cdb11b9c4bd5 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -92,6 +92,12 @@ Returns the currently assigned cursor shape (see [enum CursorShape]). + + + + Returns the current GUID for the fallback mapping, or an empty String. Godot only fills this member automatically for Android. + + @@ -118,7 +124,7 @@ - Returns an SDL2-compatible device GUID on platforms that use gamepad remapping, e.g. [code]030000004c050000c405000000010000[/code]. Returns [code]"Default Gamepad"[/code] otherwise. Godot uses the [url=https://github.com/gabomdq/SDL_GameControllerDB]SDL2 game controller database[/url] to determine gamepad names and mappings based on this GUID. + Returns an SDL2-compatible device GUID on platforms that use gamepad remapping, e.g. [code]030000004c050000c405000000010000[/code]. Returns an empty String otherwise. Godot uses the [url=https://github.com/gabomdq/SDL_GameControllerDB]SDL2 game controller database[/url] to determine gamepad names and mappings based on this GUID. Although Godot overwrites [url=https://github.com/godotengine/godot/blob/master/core/input/godotcontrollerdb.txt]some of the GUIDs[/url]. @@ -140,7 +146,7 @@ - Returns the name of the joypad at the specified device index, e.g. [code]PS4 Controller[/code]. Godot uses the [url=https://github.com/gabomdq/SDL_GameControllerDB]SDL2 game controller database[/url] to determine gamepad names. + Returns the name of the joypad at the specified device index, e.g. [code]PS4 Controller[/code]. Godot uses the [url=https://github.com/gabomdq/SDL_GameControllerDB]SDL2 game controller database[/url] to determine gamepad names. Although Godot overwrites [url=https://github.com/godotengine/godot/blob/master/core/input/godotcontrollerdb.txt]some of the names[/url], especially on Windows for XInput devices. @@ -309,6 +315,7 @@ Removes all mappings from the internal database that match the given GUID. + If you didn't set a [member fallback_mapping], then this only affects Android: If the GUID is used as [member fallback_mapping], the fallback will be invalidated. Use [member get_fallback_mapping] before calling this function to check your current setting. Call [member set_fallback_mapping] to set a new fallback GUID, which must be known (see [member is_joy_known]). @@ -342,6 +349,13 @@ [b]Note:[/b] This method generates an [InputEventMouseMotion] to update cursor immediately. + + + + + Sets the GUID for the fallback mapping, which must be known (see [member is_joy_known]). Godot only fills this member automatically for Android. + +