Browse Source

Fix Input::remove_joy_mapping

Erasing a joypad mapping can invalidate other attached joypads and the fallback mapping guid
MJacred 9 months ago
parent
commit
40832387ce
3 changed files with 31 additions and 3 deletions
  1. 29 1
      core/input/input.cpp
  2. 1 1
      core/input/input.h
  3. 1 1
      doc/classes/Input.xml

+ 29 - 1
core/input/input.cpp

@@ -1712,16 +1712,44 @@ 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;
+				WARN_PRINT_ONCE(vformat("Removed fallback joypad input mapping \"%s\". This could lead to joypads not working as intended.", p_guid));
+			} else 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;
+		int mapping;
+
 		if (joy.uid == p_guid) {
-			_set_joypad_mapping(joy, -1);
+			mapping = -1;
+		} else if (joy.mapping == (fallback_mapping - fallback_mapping_offset)) {
+			// Fix the mapping for the joypad that uses an outdated fallback index.
+			mapping = fallback_mapping;
+		} else {
+			// Re-validate the joypad's correct mapping. Fix it if necessary.
+			mapping = fallback_mapping;
+			for (int i = 0; i < map_db.size(); i++) {
+				if (joy.uid == map_db[i].uid) {
+					mapping = i;
+				}
+			}
 		}
+		_set_joypad_mapping(joy, mapping);
 	}
 }
 

+ 1 - 1
core/input/input.h

@@ -184,7 +184,7 @@ private:
 
 	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;
 

+ 1 - 1
doc/classes/Input.xml

@@ -311,7 +311,7 @@
 			<return type="void" />
 			<param index="0" name="guid" type="String" />
 			<description>
-				Removes all mappings from the internal database that match the given GUID.
+				Removes all mappings from the internal database that match the given GUID. All currently connected joypads that use this GUID will become unmapped.
 			</description>
 		</method>
 		<method name="set_accelerometer">