Skip to content

Commit

Permalink
Fix Input::remove_joy_mapping
Browse files Browse the repository at this point in the history
Erasing a joypad mapping can invalidate other attached joypads and the fallback mapping guid
  • Loading branch information
MJacred committed Nov 3, 2024
1 parent 1bffd6c commit 0c33bde
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 3 deletions.
33 changes: 33 additions & 0 deletions core/input/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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<int, Joypad> &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;
}
}
}
Expand All @@ -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)) {
Expand Down
3 changes: 2 additions & 1 deletion core/input/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ class Input : public Object {

HashSet<uint32_t> ignored_device_ids;

int fallback_mapping = -1;
int fallback_mapping = -1; // Index of the guid in map_db.

CursorShape default_shape = CURSOR_ARROW;

Expand Down Expand Up @@ -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();
Expand Down
18 changes: 16 additions & 2 deletions doc/classes/Input.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@
Returns the currently assigned cursor shape (see [enum CursorShape]).
</description>
</method>
<method name="get_fallback_mapping" qualifiers="const">
<return type="String" />
<description>
Returns the current GUID for the fallback mapping, or an empty String. Godot only fills this member automatically for Android.
</description>
</method>
<method name="get_gravity" qualifiers="const">
<return type="Vector3" />
<description>
Expand All @@ -118,7 +124,7 @@
<return type="String" />
<param index="0" name="device" type="int" />
<description>
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].
</description>
</method>
<method name="get_joy_info" qualifiers="const">
Expand All @@ -140,7 +146,7 @@
<return type="String" />
<param index="0" name="device" type="int" />
<description>
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.
</description>
</method>
<method name="get_joy_vibration_duration">
Expand Down Expand Up @@ -309,6 +315,7 @@
<param index="0" name="guid" type="String" />
<description>
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]).
</description>
</method>
<method name="set_accelerometer">
Expand Down Expand Up @@ -342,6 +349,13 @@
[b]Note:[/b] This method generates an [InputEventMouseMotion] to update cursor immediately.
</description>
</method>
<method name="set_fallback_mapping">
<return type="void" />
<param index="0" name="guid" type="String" />
<description>
Sets the GUID for the fallback mapping, which must be known (see [member is_joy_known]). Godot only fills this member automatically for Android.
</description>
</method>
<method name="set_gravity">
<return type="void" />
<param index="0" name="value" type="Vector3" />
Expand Down

0 comments on commit 0c33bde

Please sign in to comment.