class_name InputBindings extends RefCounted ## Key/button remaps persisted through the settings panel. Games keep working ## with the defaults in `project.godot`; only actions the player rebinds are ## rewritten, and remaps never remove mouse or gamepad axis events. const REMAPPABLE := [ "move_forward", "move_back", "move_left", "move_right", "walk_slow", "inspect", "wand", "radio_emergency", "action_menu", ] ## Turn an input event into a storable descriptor, or {} when it is not a key or ## pad button (mouse buttons and axes are deliberately not remappable here). static func descriptor_from_event(event: InputEvent) -> Dictionary: if event is InputEventKey: var key := event as InputEventKey var code := key.physical_keycode if key.physical_keycode != 0 else key.keycode if code == 0: return {} return {"type": "key", "code": int(code)} if event is InputEventJoypadButton: return {"type": "joy", "button": int((event as InputEventJoypadButton).button_index)} return {} static func label_for(descriptor: Dictionary) -> String: match str(descriptor.get("type", "")): "key": return OS.get_keycode_string(int(descriptor.get("code", 0))) "joy": return "Pad %d" % int(descriptor.get("button", 0)) _: return "" ## First key/button currently bound to the action, used to label the UI. static func current_descriptor(action: String) -> Dictionary: if not InputMap.has_action(action): return {} for event in InputMap.action_get_events(action): var descriptor := descriptor_from_event(event) if not descriptor.is_empty(): return descriptor return {} ## Rewrite the actions present in `bindings`. Existing key/button events for ## those actions are replaced; mouse and joypad-axis events are left alone. static func apply(bindings: Dictionary) -> void: for action in bindings.keys(): if not InputMap.has_action(action): continue var descriptor: Dictionary = bindings[action] if descriptor.is_empty(): continue for event in InputMap.action_get_events(action): if event is InputEventKey or event is InputEventJoypadButton: InputMap.action_erase_event(action, event) InputMap.action_add_event(action, event_for(descriptor)) static func event_for(descriptor: Dictionary) -> InputEvent: match str(descriptor.get("type", "")): "joy": var button := InputEventJoypadButton.new() button.button_index = int(descriptor.get("button", 0)) return button _: var key := InputEventKey.new() key.physical_keycode = int(descriptor.get("code", 0)) return key