extends Node class_name InputSettingsModel ## =============================== ## Dependencies ## =============================== const InputSchema = preload("res://__settings/input/InputSchema.gd") const SettingsStorage = preload("res://__settings/SettingStorage.gd") ## =============================== ## Signals ## =============================== signal binding_changed(action: String) signal bindings_applied signal bindings_reverted ## =============================== ## Internal State ## =============================== var _bindings_committed : Dictionary = {} var _bindings_working : Dictionary = {} var _storage := SettingsStorage.new() const SECTION := "input" ## =============================== ## Lifecycle ## =============================== func _ready() -> void: _load() ## =============================== ## Public API (Read) ## =============================== func get_bindings(action: String) -> Array: return _bindings_working.get(action, []).duplicate(true) func get_all_bindings() -> Dictionary: return _bindings_working.duplicate(true) ## =============================== ## Public API (Write) ## =============================== func set_bindings(action: String, bindings: Array) -> void: _bindings_working[action] = bindings emit_signal("binding_changed", action) func add_binding(action: String, binding: Dictionary) -> void: if not _bindings_working.has(action): _bindings_working[action] = [] _bindings_working[action].append(binding) emit_signal("binding_changed", action) func clear_bindings(action: String) -> void: _bindings_working[action] = [] emit_signal("binding_changed", action) ## =============================== ## Transaction ## =============================== func apply() -> void: _bindings_committed = _bindings_working.duplicate(true) _save_to_storage() _apply_to_input_map() emit_signal("bindings_applied") func revert() -> void: _bindings_working = _bindings_committed.duplicate(true) emit_signal("bindings_reverted") func has_unsaved_changes() -> bool: return _bindings_working != _bindings_committed ## =============================== ## Internal ## =============================== func _load() -> void: _storage.load() # 1. defaults _bindings_committed = InputSchema.defaults().duplicate(true) # 2. override from storage for action in _bindings_committed.keys(): var saved = _storage.get_value(SECTION, action, null) if saved != null: _bindings_committed[action] = saved _bindings_working = _bindings_committed.duplicate(true) # 3. apply to engine at startup _apply_to_input_map() func _save_to_storage() -> void: for action in _bindings_committed.keys(): _storage.set_value(SECTION, action, _bindings_committed[action]) _storage.save() func _apply_to_input_map() -> void: for action in _bindings_committed.keys(): if not InputMap.has_action(action): InputMap.add_action(action) InputMap.action_erase_events(action) for binding in _bindings_committed[action]: var event = _binding_to_event(binding) if event: InputMap.action_add_event(action, event) func _binding_to_event(binding: Dictionary) -> InputEvent: match binding.get("type"): "key": var e := InputEventKey.new() e.keycode = binding.get("keycode", 0) return e "mouse": var e := InputEventMouseButton.new() e.button_index = binding.get("button", 0) return e return null