Gonna get straight to the point, I wrote a small function which works quite well for saving the user’s current Input mapping for their keyboard, here it is:
public void SaveKeyboardMappings()
{
var dictionary = new Dictionary<StringName, Array<InputEventKey>>();
foreach (StringName action in InputMap.GetActions())
{
string actionAsString = action.ToString();
if (actionAsString.Contains("ui") ||
actionAsString.Contains("DEBUG")) continue;
Array<InputEvent> events = InputMap.ActionGetEvents(action);
var arrayOfKeys = new Array<InputEventKey>();
foreach (InputEvent inputEvent in events)
{
if (inputEvent is InputEventKey inputEventKey)
{
arrayOfKeys.Add(inputEventKey);
}
}
dictionary.Add(action, arrayOfKeys);
}
string jsonString = Json.Stringify(dictionary);
// TODO: Write to file
}
However, when it comes to saving the controller mappings, I’m not sure how to proceed, since the controller has two different classes for handling Input events, one called InputEventJoypadMotion and another called InputEventJoypadButton.
Something tells me simply using the base abstract class of “InputEvent” is a bad idea, but are there any tips on how to solve this and save the controller mappings in a different file, in a similar way I do with the keyboard mappings?
I think I do something very similar. You have to test for both motion and button unfortunately.
Here is a snippet. And I do a similar filtering based on the action string
func get_project_bindings() -> Dictionary:
var input_actions:Dictionary = {}
for action in get_input_actions():
input_actions[action] = {JOYPAD_EVENT:null,MOUSE_KEYBOARD_EVENT:null}
var events = InputMap.action_get_events(action)
if events.is_empty():
continue
for event in events:
if event is InputEventJoypadButton or event is InputEventJoypadMotion:
input_actions[action][JOYPAD_EVENT] = event
else:
input_actions[action][MOUSE_KEYBOARD_EVENT] = event
print(name,": found actions, ", input_actions.size())
return input_actions
In my setup I allow two input events per action, a keyboard/mouse and a motion/button event.
When the UI updates the binding I keep a dictionary updated and save it to file.
Here is my update snippets
func update_input_bindings():
print(name,": update input bindings...")
# debug_print(bindings,"update_input_bindings")
if bindings.is_empty():
print(name,": no bindings!!! ", bindings.size(), bindings)
return
for action in bindings.keys():
if InputMap.has_action(action):
InputMap.erase_action(action)
InputMap.add_action(action)
if bindings[action][MOUSE_KEYBOARD_EVENT]:
InputMap.action_add_event(action, bindings[action][MOUSE_KEYBOARD_EVENT])
if bindings[action][JOYPAD_EVENT]:
InputMap.action_add_event(action, bindings[action][JOYPAD_EVENT])
print(name,": actions updated ", bindings.size())
func set_binding(action:String, new_event:InputEvent):
if not bindings.has(action):
print(name, ": binding failed action not found, ", action)
return
if new_event is InputEventJoypadButton or\
new_event is InputEventJoypadMotion:
bindings[action][JOYPAD_EVENT] = new_event
elif new_event is InputEventKey or\
new_event is InputEventMouseButton:
bindings[action][MOUSE_KEYBOARD_EVENT] = new_event
update_and_save()
action_updated.emit(action)
If you intend to deploy on Steam, just be aware they also have an input binder of their own that you could interface with. I think I might myself and I think most of this code will go away because of that.
I thought I’d update this thread real quick with my findings. It is perfectly fine to use the base class for storing events. Currently my function looks like this, and it works flawlessly for saving the input mappings.
public void SaveControllerMappings()
{
var dictionary = new Godot.Collections.Dictionary<StringName, Array<InputEvent>>();
foreach (StringName action in InputRemapHelper.GetActionsWithoutDebugOrDefaults())
{
Array<InputEvent> events = InputMap.ActionGetEvents(action);
var arrayOfInputEvents = new Array<InputEvent>();
foreach (InputEvent inputEvent in events)
{
if (inputEvent is InputEventJoypadButton or InputEventJoypadMotion)
{
arrayOfInputEvents.Add(inputEvent);
}
}
dictionary.Add(action, arrayOfInputEvents);
}
string jsonString = Json.Stringify(dictionary);
File.WriteAllText(ControllerMappingsFilePath, jsonString);
Log.Information("Controller mappings saved successfully!");
}