extends Node const CFG_PATH := "user://controls.pr" const ACTIONS := [ "move_left", "move_right", "move_up", "move_down", "jump", "shoot", "ui_accept", "ui_cancel", ] const LINKED_ACTIONS := { move_left = "ui_left", move_right = "ui_right", move_up = "ui_up", move_down = "ui_down", # jump = "ui_accept", # shoot = "ui_cancel", } var cfg := ConfigFile.new() func _init() -> void: cfg.load(CFG_PATH) _apply_saved_bindings() func get_key(action: String) -> int: var scancode = cfg.get_value(action, "keyboard", -1) if scancode == -1: scancode = _get_default_key(action) return scancode func get_button(action: String) -> int: var button_index = cfg.get_value(action, "gamepad", -1) if button_index == -1: button_index = _get_default_button(action) return button_index func set_key(action: String, scancode: int) -> void: cfg.set_value(action, "keyboard", scancode) _configure_action_key(action) _save_bindings() func set_button(action: String, button_index: int) -> void: cfg.set_value(action, "gamepad", button_index) _configure_action_button(action) _save_bindings() func default_controls() -> void: for action in ACTIONS: set_key(action, _get_default_key(action)) set_button(action, _get_default_button(action)) for button in get_tree().get_nodes_in_group("controls_buttons"): button._update_text() func _save_bindings() -> void: cfg.save(CFG_PATH) func _apply_saved_bindings() -> void: for action in ACTIONS: _configure_action_key(action) _configure_action_button(action) func _configure_action_key(action: String) -> void: var scancode = cfg.get_value(action, "keyboard", -1) if scancode == -1: scancode = _get_default_key(action) _apply_action_key(action, scancode) var linked_action = LINKED_ACTIONS.get(action) if linked_action: _apply_action_key(linked_action, scancode) func _configure_action_button(action: String) -> void: var button_index = cfg.get_value(action, "gamepad", -1) if button_index == -1: button_index = _get_default_button(action) _apply_action_button(action, button_index) var linked_action = LINKED_ACTIONS.get(action) if linked_action: _apply_action_button(linked_action, button_index) ## applies saved keyboard binding for action func _apply_action_key(action: String, scancode: int) -> void: # erase key and button events for event in InputMap.get_action_list(action): if event is InputEventKey and event.physical_scancode != 0: InputMap.action_erase_event(action, event) # apply keyboard binding var key := InputEventKey.new() key.physical_scancode = scancode key.pressed = true InputMap.action_add_event(action, key) ## applies saved gamepad binding for action func _apply_action_button(action: String, button_index: int) -> void: # erase button events for event in InputMap.get_action_list(action): if event is InputEventJoypadButton: InputMap.action_erase_event(action, event) # apply gamepad binding var button := InputEventJoypadButton.new() button.button_index = button_index button.pressed = true InputMap.action_add_event(action, button) ## get first key input from projectsettings func _get_default_key(action: String) -> int: var events: Array = ProjectSettings.get("input/" + action).events for event in events: if event is InputEventKey: return event.physical_scancode return -1 ## get first button input from projectsettings func _get_default_button(action: String) -> int: var events: Array = ProjectSettings.get("input/" + action).events for event in events: if event is InputEventJoypadButton: return event.button_index return -1