From fd2477812d60053056f978d27366dd35d02996ee Mon Sep 17 00:00:00 2001 From: Ellie Date: Fri, 25 Apr 2025 17:34:46 +0930 Subject: [PATCH 01/12] Add initial support for keybinds - Still lots to do/rework. --- Mods/Keybinds/ActionUI.gd | 55 ++++++++++ Mods/Keybinds/ActionUI.gd.uid | 1 + Mods/Keybinds/ActionUI.tscn | 80 ++++++++++++++ Mods/Keybinds/ChangeAction.gd | 8 ++ Mods/Keybinds/ChangeAction.gd.uid | 1 + Mods/Keybinds/Keybinds.gd | 167 ++++++++++++++++++++++++++++++ Mods/Keybinds/Keybinds.gd.uid | 1 + Mods/Keybinds/Keybinds.tscn | 42 ++++++++ Mods/Keybinds/SettingsUI.gd | 40 +++++++ Mods/Keybinds/SettingsUI.gd.uid | 1 + Mods/Keybinds/description.txt | 1 + 11 files changed, 397 insertions(+) create mode 100644 Mods/Keybinds/ActionUI.gd create mode 100644 Mods/Keybinds/ActionUI.gd.uid create mode 100644 Mods/Keybinds/ActionUI.tscn create mode 100644 Mods/Keybinds/ChangeAction.gd create mode 100644 Mods/Keybinds/ChangeAction.gd.uid create mode 100644 Mods/Keybinds/Keybinds.gd create mode 100644 Mods/Keybinds/Keybinds.gd.uid create mode 100644 Mods/Keybinds/Keybinds.tscn create mode 100644 Mods/Keybinds/SettingsUI.gd create mode 100644 Mods/Keybinds/SettingsUI.gd.uid create mode 100644 Mods/Keybinds/description.txt diff --git a/Mods/Keybinds/ActionUI.gd b/Mods/Keybinds/ActionUI.gd new file mode 100644 index 00000000..86079eaf --- /dev/null +++ b/Mods/Keybinds/ActionUI.gd @@ -0,0 +1,55 @@ +extends Control +class_name ActionUI + +@export var ui_item : Dictionary = {} +@export var currently_setting : bool = false + +signal on_change_item(action : int, item : Dictionary, old_item : Dictionary) + +func set_item(item : Dictionary) -> void: + # Bind to the UI item. + ui_item = item + + var action : String = item["action_name"] + if item["key"] != -1: + var key_code : Key = item["key"] + #var has_mod : bool = item["modifier"] + #var mod_mask : int = item["modifier_mask"] + # + var input_event = InputEventKey.new() + input_event.physical_keycode = key_code + #input_event.get_modifiers_mask() + #if has_mod: + #if mod_mask & KeyModifierMask.KEY_CODE_MASK: + #pass + var display_bind = OS.get_keycode_string( + DisplayServer.keyboard_get_label_from_physical( + input_event.get_physical_keycode_with_modifiers())) + + %KeybindDisplay.text = display_bind + + %ActionNameTxt.text = action + emit_signal("on_change_item", ChangeAction.INITIAL, item, {}) + +func blank_item() -> void: + ui_item = { + "key": -1, + "action_name": "" + } + +func _on_action_name_txt_text_changed(new_text : String) -> void: + var old_item = ui_item.duplicate() + ui_item["action_name"] = new_text + emit_signal("on_change_item", ChangeAction.ACTION_NAME, ui_item, old_item) + + +func _on_delete_btn_pressed() -> void: + emit_signal("on_change_item", ChangeAction.DELETE, ui_item, {}) + queue_free() + + +func _on_reset_btn_pressed() -> void: + var old_item = ui_item.duplicate() + ui_item["key"] = -1 + emit_signal("on_change_item", ChangeAction.KEY_BIND, ui_item, old_item) + %KeybindDisplay.text = "Empty" diff --git a/Mods/Keybinds/ActionUI.gd.uid b/Mods/Keybinds/ActionUI.gd.uid new file mode 100644 index 00000000..154c25dd --- /dev/null +++ b/Mods/Keybinds/ActionUI.gd.uid @@ -0,0 +1 @@ +uid://dsy8dnqv77moj diff --git a/Mods/Keybinds/ActionUI.tscn b/Mods/Keybinds/ActionUI.tscn new file mode 100644 index 00000000..e5d2210f --- /dev/null +++ b/Mods/Keybinds/ActionUI.tscn @@ -0,0 +1,80 @@ +[gd_scene load_steps=2 format=3 uid="uid://d3tfxmryd30cl"] + +[ext_resource type="Script" uid="uid://dsy8dnqv77moj" path="res://Mods/Keybinds/ActionUI.gd" id="1_kpyqj"] + +[node name="ActionUi" type="Control"] +custom_minimum_size = Vector2(230, 165) +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +script = ExtResource("1_kpyqj") + +[node name="Panel" type="Panel" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="Panel"] +layout_mode = 0 +offset_left = 6.0 +offset_top = 4.0 +offset_right = 225.0 +offset_bottom = 159.0 + +[node name="VBox" type="VBoxContainer" parent="Panel/VBoxContainer"] +layout_mode = 2 +alignment = 1 + +[node name="Label" type="Label" parent="Panel/VBoxContainer/VBox"] +layout_mode = 2 +text = "Action Name" + +[node name="ActionNameTxt" type="LineEdit" parent="Panel/VBoxContainer/VBox"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="VBox2" type="VBoxContainer" parent="Panel/VBoxContainer"] +layout_mode = 2 +alignment = 1 + +[node name="Label" type="Label" parent="Panel/VBoxContainer/VBox2"] +layout_mode = 2 +text = "Keybind" + +[node name="KeybindDisplay" type="LineEdit" parent="Panel/VBoxContainer/VBox2"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +focus_mode = 0 +text = "Empty" +alignment = 1 +editable = false + +[node name="HBoxContainer3" type="HBoxContainer" parent="Panel/VBoxContainer"] +layout_mode = 2 +alignment = 1 + +[node name="SetBtn" type="Button" parent="Panel/VBoxContainer/HBoxContainer3"] +layout_mode = 2 +text = "Set" + +[node name="ResetBtn" type="Button" parent="Panel/VBoxContainer/HBoxContainer3"] +layout_mode = 2 +text = "Reset" + +[node name="DeleteBtn" type="Button" parent="Panel/VBoxContainer/HBoxContainer3"] +layout_mode = 2 +text = "Delete" + +[connection signal="text_changed" from="Panel/VBoxContainer/VBox/ActionNameTxt" to="." method="_on_action_name_txt_text_changed"] +[connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer3/ResetBtn" to="." method="_on_reset_btn_pressed"] +[connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer3/DeleteBtn" to="." method="_on_delete_btn_pressed"] diff --git a/Mods/Keybinds/ChangeAction.gd b/Mods/Keybinds/ChangeAction.gd new file mode 100644 index 00000000..1e4c7fe3 --- /dev/null +++ b/Mods/Keybinds/ChangeAction.gd @@ -0,0 +1,8 @@ +class_name ChangeAction +enum { + UNSET = 1, + DELETE = 2, + INITIAL = 3, + ACTION_NAME = 4, + KEY_BIND = 5 +} diff --git a/Mods/Keybinds/ChangeAction.gd.uid b/Mods/Keybinds/ChangeAction.gd.uid new file mode 100644 index 00000000..c8b0c03c --- /dev/null +++ b/Mods/Keybinds/ChangeAction.gd.uid @@ -0,0 +1 @@ +uid://ba335sykgfxm diff --git a/Mods/Keybinds/Keybinds.gd b/Mods/Keybinds/Keybinds.gd new file mode 100644 index 00000000..2b224efa --- /dev/null +++ b/Mods/Keybinds/Keybinds.gd @@ -0,0 +1,167 @@ +extends Mod_Base +class_name Keybinds + +# List of actions and keys, that will be imported to the input map...? +# [ +# { +# "key" : number_for_key_representation +# "action_name" : "action_name_here" +# } +# +@export var panel : Control = null + +var key_actions : Array = [] +var settings_ui : KeybindSettingUI + +func _ready() -> void: + _add_actions() + + # Remove the temp panel and attach the children to the + # settings window! This way we aren't messing around with + # tracked settings, and instead are simply loading our own UI. + remove_child(panel) + + var new_keybind_button : Button = Button.new() + new_keybind_button.text = "New Keybind" + get_settings_window().add_child(new_keybind_button) + new_keybind_button.pressed.connect(_new_keybind) + + var first_child = panel.get_child(0) + settings_ui = first_child + panel.remove_child(settings_ui) + get_settings_window().add_child(settings_ui) + settings_ui.on_change_item.connect(on_ui_change_item) + settings_ui.size_flags_vertical = Control.SIZE_EXPAND_FILL + + +func _new_keybind() -> void: + settings_ui.add_key_action(null) + +func on_ui_change_item(action : int, item : Dictionary, old_item : Dictionary): + if action == ChangeAction.ACTION_NAME or action == ChangeAction.KEY_BIND: + # Updates should be fine as there is a reference to the item. + # We only have to check if there isn't an item, then add an item. + if action == ChangeAction.ACTION_NAME and _get_key_action_by_item(item) == null: + key_actions.append(item) + _create_action(item) + else: + _update_action(item, old_item) + if action == ChangeAction.DELETE: + # Remove the existing item from our key_actions. + _remove_key_action_by_item(item) + + # Adjust our input map. + var action_event_count = len(InputMap.action_get_events(item["action_name"])) + if action_event_count <= 1: + # Delete the entire action. + print("Deleting the entire action for %s" % item["action_name"]) + InputMap.erase_action(item["action_name"]) + else: + # Delete just our event. + var key_event = _create_key_event(item["key"]) + if key_event != null: + print("Deleting just our event for %s" % item["action_name"]) + InputMap.action_erase_event(item["action_name"], key_event) + + save_settings() + +func _create_key_event(key : int) -> InputEventKey: + if key == -1: + return null + var new_key_event = InputEventKey.new() + new_key_event.physical_keycode = key + return new_key_event + +func _create_action(item : Dictionary) -> void: + var action = item["action_name"] + + # Do not create empty. + if action == "": + return + + print("Creating new action and associated event %s" % action) + var key_event = _create_key_event(item["key"]) + if not InputMap.has_action(action): + InputMap.add_action(action) + else: + # Clear existing events for the action + InputMap.action_erase_events(action) + + # Always add the event to the action, if there is no action it was made. + # existing events for the action have been cleared. + InputMap.action_add_event(action, key_event) + +func _update_action(new_item : Dictionary, old_item : Dictionary) -> void: + if new_item["action_name"] != old_item["action_name"]: + print("New item action name (%s) is different from the old (%s)." % [new_item["action_name"], old_item["action_name"]]) + InputMap.erase_action(old_item["action_name"]) + _create_action(new_item) + elif new_item["key"] != old_item["key"]: + print("New item key is not the same as the old key.") + if old_item["key"] != -1: + print("Old item key is not unassigned. Removing the old item key event.") + var old_key_event = _create_key_event(old_item["key"]) + InputMap.action_erase_event(new_item["action_name"], old_key_event) + + print("Adding event for the action name with the correct key.") + + # We only want to create a new key event if it wasn't reset. + var new_key_event = _create_key_event(new_item["key"]) + if new_key_event != null: + InputMap.action_add_event(new_item["action_name"], new_key_event) + +func _input(event : InputEvent) -> void: + if InputMap.has_action("ping") and event.is_action_pressed("ping"): + print("pong!") + #if event is InputEventKey: + #print("Key pressed") + ##if event.physical_keycode in key_actions: + #var value = _get_key_action_by_input(event.physical_keycode) + #if value == null: + #return + #print(value["action_name"]) + +func _get_key_action_by_input(key : Key): + for item in key_actions: + if item["key"] == key: + return item + return null + +func _get_key_action_by_item(item : Dictionary): + for i in key_actions: + if i["key"] == item["key"] and i["action_name"] == item["action_name"]: + return i + return null + +func _update_key_action_by_item(item : Dictionary, new_item : Dictionary) -> bool: + for i in key_actions: + if i["key"] == item["key"] and i["action_name"] == item["action_name"]: + i["key"] = new_item["key"] + i["action_name"] = new_item["action_name"] + return true + return false + +func _remove_key_action_by_item(item : Dictionary) -> bool: + var index = key_actions.find(item) + if index >= 0: + key_actions.remove_at(index) + return true + return false + +func _add_actions() -> void: + for item in key_actions: + _create_action(item) + +func save_before(_settings_current : Dictionary): + _settings_current["keybinds_key_actions"] = key_actions + print("Saved key actions") + +func load_after(_settings_old : Dictionary, _settings_new : Dictionary): + print("Load after") + + if _settings_new.has("keybinds_key_actions"): + key_actions = _settings_new["keybinds_key_actions"] + print("Loaded key actions") + # Try set initial, it will return if initial has already been set. + settings_ui.set_initial_key_actions(key_actions) + _add_actions() diff --git a/Mods/Keybinds/Keybinds.gd.uid b/Mods/Keybinds/Keybinds.gd.uid new file mode 100644 index 00000000..14bd02cb --- /dev/null +++ b/Mods/Keybinds/Keybinds.gd.uid @@ -0,0 +1 @@ +uid://c47cbmmvkrwvl diff --git a/Mods/Keybinds/Keybinds.tscn b/Mods/Keybinds/Keybinds.tscn new file mode 100644 index 00000000..5070cee7 --- /dev/null +++ b/Mods/Keybinds/Keybinds.tscn @@ -0,0 +1,42 @@ +[gd_scene load_steps=4 format=3 uid="uid://cvokpd5h375w1"] + +[ext_resource type="Script" uid="uid://c47cbmmvkrwvl" path="res://Mods/Keybinds/Keybinds.gd" id="1_8jfd0"] +[ext_resource type="Script" uid="uid://bqviy8gst7123" path="res://Mods/Keybinds/SettingsUI.gd" id="2_hfm7f"] +[ext_resource type="PackedScene" uid="uid://d3tfxmryd30cl" path="res://Mods/Keybinds/ActionUI.tscn" id="3_gqp3c"] + +[node name="Keybinds" type="Node3D" node_paths=PackedStringArray("panel")] +script = ExtResource("1_8jfd0") +panel = NodePath("TempPanel") + +[node name="TempPanel" type="Control" parent="."] +layout_mode = 3 +anchors_preset = 0 +offset_right = 40.0 +offset_bottom = 40.0 + +[node name="SettingsUIContainer" type="ScrollContainer" parent="TempPanel" node_paths=PackedStringArray("attached")] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = 70.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("2_hfm7f") +base = ExtResource("3_gqp3c") +attached = NodePath("FlowContainer") + +[node name="FlowContainer" type="FlowContainer" parent="TempPanel/SettingsUIContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Label" type="Label" parent="TempPanel"] +visible = false +layout_mode = 2 +offset_right = 205.0 +offset_bottom = 101.0 +text = "HELLO LOTS OF TEXT HERE + +Yes Hello! +Yes" diff --git a/Mods/Keybinds/SettingsUI.gd b/Mods/Keybinds/SettingsUI.gd new file mode 100644 index 00000000..eddebe58 --- /dev/null +++ b/Mods/Keybinds/SettingsUI.gd @@ -0,0 +1,40 @@ +extends Node +class_name KeybindSettingUI + +@export var base : PackedScene +@export var attached : Control +@export var has_set_initial : bool = false + +signal on_change_item(action : int, item : Dictionary, old_item : Dictionary) + +## ONLY used for the first initial ready setup of key actions. +func set_initial_key_actions(new_key_actions : Array) -> void: + if has_set_initial: + print("Already set initial key actions") + print("Set new key actions") + _build_ui(new_key_actions) + has_set_initial = true + +func _build_ui(key_actions : Array): + for item in key_actions: + add_key_action(item) + +func add_key_action(item): + # FIXME: Properly handle updates - remove missing, add new. + #if item["action_name"] in built_ui_for: + #print("Already built UI for this one...") + #return + # + var new_item : ActionUI = base.instantiate() + new_item.on_change_item.connect(_on_change_item) + if item != null: + new_item.set_item(item) + else: + new_item.blank_item() + new_item.visible = true + attached.add_child(new_item) + + # FIXME: Multiple events for single action means this may not be correct. + #built_ui_for.append(item["action_name"]) +func _on_change_item(action : int, item : Dictionary, old_item : Dictionary): + emit_signal("on_change_item", action, item, old_item) diff --git a/Mods/Keybinds/SettingsUI.gd.uid b/Mods/Keybinds/SettingsUI.gd.uid new file mode 100644 index 00000000..341bb0a9 --- /dev/null +++ b/Mods/Keybinds/SettingsUI.gd.uid @@ -0,0 +1 @@ +uid://bqviy8gst7123 diff --git a/Mods/Keybinds/description.txt b/Mods/Keybinds/description.txt new file mode 100644 index 00000000..659f734e --- /dev/null +++ b/Mods/Keybinds/description.txt @@ -0,0 +1 @@ +Customise keybinds for various actions across SnekStudio. From 30cdc1d3147da8a1afcbdefa7b90c6efc145f03f Mon Sep 17 00:00:00 2001 From: Ellie Date: Fri, 25 Apr 2025 17:43:36 +0930 Subject: [PATCH 02/12] Add setting of keybind --- Mods/Keybinds/ActionUI.gd | 43 +++++++++++++++++++++++++------------ Mods/Keybinds/ActionUI.tscn | 2 ++ 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/Mods/Keybinds/ActionUI.gd b/Mods/Keybinds/ActionUI.gd index 86079eaf..3d55b756 100644 --- a/Mods/Keybinds/ActionUI.gd +++ b/Mods/Keybinds/ActionUI.gd @@ -13,24 +13,24 @@ func set_item(item : Dictionary) -> void: var action : String = item["action_name"] if item["key"] != -1: var key_code : Key = item["key"] - #var has_mod : bool = item["modifier"] - #var mod_mask : int = item["modifier_mask"] - # - var input_event = InputEventKey.new() - input_event.physical_keycode = key_code - #input_event.get_modifiers_mask() - #if has_mod: - #if mod_mask & KeyModifierMask.KEY_CODE_MASK: - #pass - var display_bind = OS.get_keycode_string( - DisplayServer.keyboard_get_label_from_physical( - input_event.get_physical_keycode_with_modifiers())) - - %KeybindDisplay.text = display_bind + _set_key_bind_display(key_code) %ActionNameTxt.text = action emit_signal("on_change_item", ChangeAction.INITIAL, item, {}) +func _set_key_bind_display(key_code : Key): + var input_event = InputEventKey.new() + input_event.physical_keycode = key_code + #input_event.get_modifiers_mask() + #if has_mod: + #if mod_mask & KeyModifierMask.KEY_CODE_MASK: + #pass + var display_bind = OS.get_keycode_string( + DisplayServer.keyboard_get_label_from_physical( + input_event.get_physical_keycode_with_modifiers())) + + %KeybindDisplay.text = display_bind + func blank_item() -> void: ui_item = { "key": -1, @@ -53,3 +53,18 @@ func _on_reset_btn_pressed() -> void: ui_item["key"] = -1 emit_signal("on_change_item", ChangeAction.KEY_BIND, ui_item, old_item) %KeybindDisplay.text = "Empty" + +func _input(event : InputEvent): + if currently_setting and event is InputEventKey: + currently_setting = false + %SetBtn.text = "Set" + var new_key = event.physical_keycode + var old_item = ui_item.duplicate() + ui_item["key"] = new_key + emit_signal("on_change_item", ChangeAction.KEY_BIND, ui_item, old_item) + _set_key_bind_display(new_key) + +func _on_set_btn_pressed() -> void: + currently_setting = true + if currently_setting: + %SetBtn.text = "Press Key" diff --git a/Mods/Keybinds/ActionUI.tscn b/Mods/Keybinds/ActionUI.tscn index e5d2210f..0eb9ec71 100644 --- a/Mods/Keybinds/ActionUI.tscn +++ b/Mods/Keybinds/ActionUI.tscn @@ -64,6 +64,7 @@ layout_mode = 2 alignment = 1 [node name="SetBtn" type="Button" parent="Panel/VBoxContainer/HBoxContainer3"] +unique_name_in_owner = true layout_mode = 2 text = "Set" @@ -76,5 +77,6 @@ layout_mode = 2 text = "Delete" [connection signal="text_changed" from="Panel/VBoxContainer/VBox/ActionNameTxt" to="." method="_on_action_name_txt_text_changed"] +[connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer3/SetBtn" to="." method="_on_set_btn_pressed"] [connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer3/ResetBtn" to="." method="_on_reset_btn_pressed"] [connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer3/DeleteBtn" to="." method="_on_delete_btn_pressed"] From d28b05f84289dcc80b3f5141424d5bf9ade35c64 Mon Sep 17 00:00:00 2001 From: Ellie Date: Fri, 25 Apr 2025 18:05:42 +0930 Subject: [PATCH 03/12] First cleanup --- Mods/Keybinds/ActionUI.gd | 17 ++++++++-------- Mods/Keybinds/Keybinds.gd | 39 +++++++++++++++---------------------- Mods/Keybinds/SettingsUI.gd | 11 +++-------- 3 files changed, 28 insertions(+), 39 deletions(-) diff --git a/Mods/Keybinds/ActionUI.gd b/Mods/Keybinds/ActionUI.gd index 3d55b756..5a6ff30a 100644 --- a/Mods/Keybinds/ActionUI.gd +++ b/Mods/Keybinds/ActionUI.gd @@ -1,20 +1,22 @@ extends Control class_name ActionUI -@export var ui_item : Dictionary = {} -@export var currently_setting : bool = false +var ui_item : Dictionary = {} +var currently_setting : bool = false signal on_change_item(action : int, item : Dictionary, old_item : Dictionary) +## Load the item to the UI elements. +## Keybind does not have to be set, but must be -1 if not set. func set_item(item : Dictionary) -> void: # Bind to the UI item. ui_item = item - + var action : String = item["action_name"] if item["key"] != -1: var key_code : Key = item["key"] _set_key_bind_display(key_code) - + %ActionNameTxt.text = action emit_signal("on_change_item", ChangeAction.INITIAL, item, {}) @@ -28,9 +30,10 @@ func _set_key_bind_display(key_code : Key): var display_bind = OS.get_keycode_string( DisplayServer.keyboard_get_label_from_physical( input_event.get_physical_keycode_with_modifiers())) - + %KeybindDisplay.text = display_bind +## Set the UI item to be blank. func blank_item() -> void: ui_item = { "key": -1, @@ -42,12 +45,10 @@ func _on_action_name_txt_text_changed(new_text : String) -> void: ui_item["action_name"] = new_text emit_signal("on_change_item", ChangeAction.ACTION_NAME, ui_item, old_item) - func _on_delete_btn_pressed() -> void: emit_signal("on_change_item", ChangeAction.DELETE, ui_item, {}) queue_free() - func _on_reset_btn_pressed() -> void: var old_item = ui_item.duplicate() ui_item["key"] = -1 @@ -63,7 +64,7 @@ func _input(event : InputEvent): ui_item["key"] = new_key emit_signal("on_change_item", ChangeAction.KEY_BIND, ui_item, old_item) _set_key_bind_display(new_key) - + func _on_set_btn_pressed() -> void: currently_setting = true if currently_setting: diff --git a/Mods/Keybinds/Keybinds.gd b/Mods/Keybinds/Keybinds.gd index 2b224efa..a9d8efe7 100644 --- a/Mods/Keybinds/Keybinds.gd +++ b/Mods/Keybinds/Keybinds.gd @@ -1,31 +1,30 @@ extends Mod_Base class_name Keybinds -# List of actions and keys, that will be imported to the input map...? +@export var panel : Control = null + +# List of actions and keys, that will be imported to the input map # [ # { # "key" : number_for_key_representation # "action_name" : "action_name_here" # } -# -@export var panel : Control = null - var key_actions : Array = [] var settings_ui : KeybindSettingUI func _ready() -> void: _add_actions() - + # Remove the temp panel and attach the children to the # settings window! This way we aren't messing around with # tracked settings, and instead are simply loading our own UI. remove_child(panel) - + var new_keybind_button : Button = Button.new() new_keybind_button.text = "New Keybind" get_settings_window().add_child(new_keybind_button) new_keybind_button.pressed.connect(_new_keybind) - + var first_child = panel.get_child(0) settings_ui = first_child panel.remove_child(settings_ui) @@ -49,7 +48,7 @@ func on_ui_change_item(action : int, item : Dictionary, old_item : Dictionary): if action == ChangeAction.DELETE: # Remove the existing item from our key_actions. _remove_key_action_by_item(item) - + # Adjust our input map. var action_event_count = len(InputMap.action_get_events(item["action_name"])) if action_event_count <= 1: @@ -62,16 +61,16 @@ func on_ui_change_item(action : int, item : Dictionary, old_item : Dictionary): if key_event != null: print("Deleting just our event for %s" % item["action_name"]) InputMap.action_erase_event(item["action_name"], key_event) - + save_settings() - + func _create_key_event(key : int) -> InputEventKey: if key == -1: return null var new_key_event = InputEventKey.new() new_key_event.physical_keycode = key return new_key_event - + func _create_action(item : Dictionary) -> void: var action = item["action_name"] @@ -90,7 +89,7 @@ func _create_action(item : Dictionary) -> void: # Always add the event to the action, if there is no action it was made. # existing events for the action have been cleared. InputMap.action_add_event(action, key_event) - + func _update_action(new_item : Dictionary, old_item : Dictionary) -> void: if new_item["action_name"] != old_item["action_name"]: print("New item action name (%s) is different from the old (%s)." % [new_item["action_name"], old_item["action_name"]]) @@ -104,7 +103,7 @@ func _update_action(new_item : Dictionary, old_item : Dictionary) -> void: InputMap.action_erase_event(new_item["action_name"], old_key_event) print("Adding event for the action name with the correct key.") - + # We only want to create a new key event if it wasn't reset. var new_key_event = _create_key_event(new_item["key"]) if new_key_event != null: @@ -120,19 +119,13 @@ func _input(event : InputEvent) -> void: #if value == null: #return #print(value["action_name"]) - -func _get_key_action_by_input(key : Key): - for item in key_actions: - if item["key"] == key: - return item - return null - + func _get_key_action_by_item(item : Dictionary): for i in key_actions: if i["key"] == item["key"] and i["action_name"] == item["action_name"]: return i return null - + func _update_key_action_by_item(item : Dictionary, new_item : Dictionary) -> bool: for i in key_actions: if i["key"] == item["key"] and i["action_name"] == item["action_name"]: @@ -155,10 +148,10 @@ func _add_actions() -> void: func save_before(_settings_current : Dictionary): _settings_current["keybinds_key_actions"] = key_actions print("Saved key actions") - + func load_after(_settings_old : Dictionary, _settings_new : Dictionary): print("Load after") - + if _settings_new.has("keybinds_key_actions"): key_actions = _settings_new["keybinds_key_actions"] print("Loaded key actions") diff --git a/Mods/Keybinds/SettingsUI.gd b/Mods/Keybinds/SettingsUI.gd index eddebe58..3fd1ee27 100644 --- a/Mods/Keybinds/SettingsUI.gd +++ b/Mods/Keybinds/SettingsUI.gd @@ -14,17 +14,14 @@ func set_initial_key_actions(new_key_actions : Array) -> void: print("Set new key actions") _build_ui(new_key_actions) has_set_initial = true - + func _build_ui(key_actions : Array): for item in key_actions: add_key_action(item) +## Create an action UI element for a particular item. +## If the item is null, it will create a blank item. func add_key_action(item): - # FIXME: Properly handle updates - remove missing, add new. - #if item["action_name"] in built_ui_for: - #print("Already built UI for this one...") - #return - # var new_item : ActionUI = base.instantiate() new_item.on_change_item.connect(_on_change_item) if item != null: @@ -34,7 +31,5 @@ func add_key_action(item): new_item.visible = true attached.add_child(new_item) - # FIXME: Multiple events for single action means this may not be correct. - #built_ui_for.append(item["action_name"]) func _on_change_item(action : int, item : Dictionary, old_item : Dictionary): emit_signal("on_change_item", action, item, old_item) From 78c2d3583ff2510c1a02ab408e8a1bd0c098013f Mon Sep 17 00:00:00 2001 From: Ellie Date: Fri, 25 Apr 2025 18:23:41 +0930 Subject: [PATCH 04/12] Restructure to suit core requirements --- Mods/Keybinds/ChangeAction.gd | 8 -------- Mods/Keybinds/Keybinds.gd | 4 +++- Mods/Keybinds/Keybinds.tscn | 15 +++------------ Mods/Keybinds/{ => Resources}/ActionUI.gd | 0 Mods/Keybinds/{ => Resources}/ActionUI.gd.uid | 0 Mods/Keybinds/{ => Resources}/ActionUI.tscn | 2 +- Mods/Keybinds/Resources/ChangeAction.gd | 7 +++++++ Mods/Keybinds/{ => Resources}/ChangeAction.gd.uid | 0 Mods/Keybinds/{ => Resources}/SettingsUI.gd | 0 Mods/Keybinds/{ => Resources}/SettingsUI.gd.uid | 0 10 files changed, 14 insertions(+), 22 deletions(-) delete mode 100644 Mods/Keybinds/ChangeAction.gd rename Mods/Keybinds/{ => Resources}/ActionUI.gd (100%) rename Mods/Keybinds/{ => Resources}/ActionUI.gd.uid (100%) rename Mods/Keybinds/{ => Resources}/ActionUI.tscn (97%) create mode 100644 Mods/Keybinds/Resources/ChangeAction.gd rename Mods/Keybinds/{ => Resources}/ChangeAction.gd.uid (100%) rename Mods/Keybinds/{ => Resources}/SettingsUI.gd (100%) rename Mods/Keybinds/{ => Resources}/SettingsUI.gd.uid (100%) diff --git a/Mods/Keybinds/ChangeAction.gd b/Mods/Keybinds/ChangeAction.gd deleted file mode 100644 index 1e4c7fe3..00000000 --- a/Mods/Keybinds/ChangeAction.gd +++ /dev/null @@ -1,8 +0,0 @@ -class_name ChangeAction -enum { - UNSET = 1, - DELETE = 2, - INITIAL = 3, - ACTION_NAME = 4, - KEY_BIND = 5 -} diff --git a/Mods/Keybinds/Keybinds.gd b/Mods/Keybinds/Keybinds.gd index a9d8efe7..c53fdb78 100644 --- a/Mods/Keybinds/Keybinds.gd +++ b/Mods/Keybinds/Keybinds.gd @@ -80,6 +80,7 @@ func _create_action(item : Dictionary) -> void: print("Creating new action and associated event %s" % action) var key_event = _create_key_event(item["key"]) + if not InputMap.has_action(action): InputMap.add_action(action) else: @@ -88,7 +89,8 @@ func _create_action(item : Dictionary) -> void: # Always add the event to the action, if there is no action it was made. # existing events for the action have been cleared. - InputMap.action_add_event(action, key_event) + if key_event != null: + InputMap.action_add_event(action, key_event) func _update_action(new_item : Dictionary, old_item : Dictionary) -> void: if new_item["action_name"] != old_item["action_name"]: diff --git a/Mods/Keybinds/Keybinds.tscn b/Mods/Keybinds/Keybinds.tscn index 5070cee7..9f5e33a4 100644 --- a/Mods/Keybinds/Keybinds.tscn +++ b/Mods/Keybinds/Keybinds.tscn @@ -1,14 +1,15 @@ [gd_scene load_steps=4 format=3 uid="uid://cvokpd5h375w1"] [ext_resource type="Script" uid="uid://c47cbmmvkrwvl" path="res://Mods/Keybinds/Keybinds.gd" id="1_8jfd0"] -[ext_resource type="Script" uid="uid://bqviy8gst7123" path="res://Mods/Keybinds/SettingsUI.gd" id="2_hfm7f"] -[ext_resource type="PackedScene" uid="uid://d3tfxmryd30cl" path="res://Mods/Keybinds/ActionUI.tscn" id="3_gqp3c"] +[ext_resource type="Script" uid="uid://bqviy8gst7123" path="res://Mods/Keybinds/Resources/SettingsUI.gd" id="2_hfm7f"] +[ext_resource type="PackedScene" uid="uid://d3tfxmryd30cl" path="res://Mods/Keybinds/Resources/ActionUI.tscn" id="3_gqp3c"] [node name="Keybinds" type="Node3D" node_paths=PackedStringArray("panel")] script = ExtResource("1_8jfd0") panel = NodePath("TempPanel") [node name="TempPanel" type="Control" parent="."] +visible = false layout_mode = 3 anchors_preset = 0 offset_right = 40.0 @@ -30,13 +31,3 @@ attached = NodePath("FlowContainer") layout_mode = 2 size_flags_horizontal = 3 size_flags_vertical = 3 - -[node name="Label" type="Label" parent="TempPanel"] -visible = false -layout_mode = 2 -offset_right = 205.0 -offset_bottom = 101.0 -text = "HELLO LOTS OF TEXT HERE - -Yes Hello! -Yes" diff --git a/Mods/Keybinds/ActionUI.gd b/Mods/Keybinds/Resources/ActionUI.gd similarity index 100% rename from Mods/Keybinds/ActionUI.gd rename to Mods/Keybinds/Resources/ActionUI.gd diff --git a/Mods/Keybinds/ActionUI.gd.uid b/Mods/Keybinds/Resources/ActionUI.gd.uid similarity index 100% rename from Mods/Keybinds/ActionUI.gd.uid rename to Mods/Keybinds/Resources/ActionUI.gd.uid diff --git a/Mods/Keybinds/ActionUI.tscn b/Mods/Keybinds/Resources/ActionUI.tscn similarity index 97% rename from Mods/Keybinds/ActionUI.tscn rename to Mods/Keybinds/Resources/ActionUI.tscn index 0eb9ec71..b3dbd052 100644 --- a/Mods/Keybinds/ActionUI.tscn +++ b/Mods/Keybinds/Resources/ActionUI.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=2 format=3 uid="uid://d3tfxmryd30cl"] -[ext_resource type="Script" uid="uid://dsy8dnqv77moj" path="res://Mods/Keybinds/ActionUI.gd" id="1_kpyqj"] +[ext_resource type="Script" uid="uid://dsy8dnqv77moj" path="res://Mods/Keybinds/Resources/ActionUI.gd" id="1_kpyqj"] [node name="ActionUi" type="Control"] custom_minimum_size = Vector2(230, 165) diff --git a/Mods/Keybinds/Resources/ChangeAction.gd b/Mods/Keybinds/Resources/ChangeAction.gd new file mode 100644 index 00000000..c5ac70ed --- /dev/null +++ b/Mods/Keybinds/Resources/ChangeAction.gd @@ -0,0 +1,7 @@ +class_name ChangeAction +enum { + DELETE = 1, + INITIAL = 2, + ACTION_NAME = 3, + KEY_BIND = 4 +} diff --git a/Mods/Keybinds/ChangeAction.gd.uid b/Mods/Keybinds/Resources/ChangeAction.gd.uid similarity index 100% rename from Mods/Keybinds/ChangeAction.gd.uid rename to Mods/Keybinds/Resources/ChangeAction.gd.uid diff --git a/Mods/Keybinds/SettingsUI.gd b/Mods/Keybinds/Resources/SettingsUI.gd similarity index 100% rename from Mods/Keybinds/SettingsUI.gd rename to Mods/Keybinds/Resources/SettingsUI.gd diff --git a/Mods/Keybinds/SettingsUI.gd.uid b/Mods/Keybinds/Resources/SettingsUI.gd.uid similarity index 100% rename from Mods/Keybinds/SettingsUI.gd.uid rename to Mods/Keybinds/Resources/SettingsUI.gd.uid From 8294507d4032a16a3d3dcbfff8f90ad913d6487b Mon Sep 17 00:00:00 2001 From: Ellie Date: Fri, 25 Apr 2025 18:52:19 +0930 Subject: [PATCH 05/12] Add default key actions --- Mods/Keybinds/Keybinds.gd | 61 ++++++++++++++++----------- Mods/Keybinds/Resources/SettingsUI.gd | 4 +- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/Mods/Keybinds/Keybinds.gd b/Mods/Keybinds/Keybinds.gd index c53fdb78..57914ac9 100644 --- a/Mods/Keybinds/Keybinds.gd +++ b/Mods/Keybinds/Keybinds.gd @@ -13,8 +13,6 @@ var key_actions : Array = [] var settings_ui : KeybindSettingUI func _ready() -> void: - _add_actions() - # Remove the temp panel and attach the children to the # settings window! This way we aren't messing around with # tracked settings, and instead are simply loading our own UI. @@ -32,6 +30,9 @@ func _ready() -> void: settings_ui.on_change_item.connect(on_ui_change_item) settings_ui.size_flags_vertical = Control.SIZE_EXPAND_FILL + # Trigger load + var settings = save_settings() + load_settings(settings) func _new_keybind() -> void: settings_ui.add_key_action(null) @@ -53,13 +54,13 @@ func on_ui_change_item(action : int, item : Dictionary, old_item : Dictionary): var action_event_count = len(InputMap.action_get_events(item["action_name"])) if action_event_count <= 1: # Delete the entire action. - print("Deleting the entire action for %s" % item["action_name"]) + print_log("Deleting the entire action for %s" % item["action_name"]) InputMap.erase_action(item["action_name"]) else: # Delete just our event. var key_event = _create_key_event(item["key"]) if key_event != null: - print("Deleting just our event for %s" % item["action_name"]) + print_log("Deleting just our event for %s" % item["action_name"]) InputMap.action_erase_event(item["action_name"], key_event) save_settings() @@ -78,14 +79,11 @@ func _create_action(item : Dictionary) -> void: if action == "": return - print("Creating new action and associated event %s" % action) + print_log("Creating new action and associated event %s" % action) var key_event = _create_key_event(item["key"]) if not InputMap.has_action(action): InputMap.add_action(action) - else: - # Clear existing events for the action - InputMap.action_erase_events(action) # Always add the event to the action, if there is no action it was made. # existing events for the action have been cleared. @@ -94,33 +92,33 @@ func _create_action(item : Dictionary) -> void: func _update_action(new_item : Dictionary, old_item : Dictionary) -> void: if new_item["action_name"] != old_item["action_name"]: - print("New item action name (%s) is different from the old (%s)." % [new_item["action_name"], old_item["action_name"]]) + print_log("New item action name (%s) is different from the old (%s)." % [new_item["action_name"], old_item["action_name"]]) InputMap.erase_action(old_item["action_name"]) _create_action(new_item) elif new_item["key"] != old_item["key"]: - print("New item key is not the same as the old key.") + print_log("New item key is not the same as the old key.") if old_item["key"] != -1: - print("Old item key is not unassigned. Removing the old item key event.") + print_log("Old item key is not unassigned. Removing the old item key event.") var old_key_event = _create_key_event(old_item["key"]) InputMap.action_erase_event(new_item["action_name"], old_key_event) - print("Adding event for the action name with the correct key.") + print_log("Adding event for the action name with the correct key.") # We only want to create a new key event if it wasn't reset. var new_key_event = _create_key_event(new_item["key"]) - if new_key_event != null: + if new_key_event != null and new_item["action_name"] != "": InputMap.action_add_event(new_item["action_name"], new_key_event) func _input(event : InputEvent) -> void: if InputMap.has_action("ping") and event.is_action_pressed("ping"): - print("pong!") + print_log("pong!") #if event is InputEventKey: - #print("Key pressed") + #print_log("Key pressed") ##if event.physical_keycode in key_actions: #var value = _get_key_action_by_input(event.physical_keycode) #if value == null: #return - #print(value["action_name"]) + #print_log(value["action_name"]) func _get_key_action_by_item(item : Dictionary): for i in key_actions: @@ -147,16 +145,31 @@ func _add_actions() -> void: for item in key_actions: _create_action(item) +func _create_initial_actions() -> void: + key_actions = [ + { + "key": KEY_P, + "action_name": "ping" + }, + { + "key": KEY_Y, + "action_name": "ping" + }, + ] + func save_before(_settings_current : Dictionary): _settings_current["keybinds_key_actions"] = key_actions - print("Saved key actions") + print_log("Saved key actions") func load_after(_settings_old : Dictionary, _settings_new : Dictionary): - print("Load after") - - if _settings_new.has("keybinds_key_actions"): + print_log("Load after") + if _settings_new.has("keybinds_key_actions") and len(_settings_new["keybinds_key_actions"]) > 0: key_actions = _settings_new["keybinds_key_actions"] - print("Loaded key actions") - # Try set initial, it will return if initial has already been set. - settings_ui.set_initial_key_actions(key_actions) - _add_actions() + print_log("Loaded key actions.") + else: + # Add default. + print_log("Loading default key actions.") + _create_initial_actions() + # Try set initial, it will return if initial has already been set. + settings_ui.set_initial_key_actions(key_actions) + _add_actions() diff --git a/Mods/Keybinds/Resources/SettingsUI.gd b/Mods/Keybinds/Resources/SettingsUI.gd index 3fd1ee27..3739f90a 100644 --- a/Mods/Keybinds/Resources/SettingsUI.gd +++ b/Mods/Keybinds/Resources/SettingsUI.gd @@ -10,8 +10,8 @@ signal on_change_item(action : int, item : Dictionary, old_item : Dictionary) ## ONLY used for the first initial ready setup of key actions. func set_initial_key_actions(new_key_actions : Array) -> void: if has_set_initial: - print("Already set initial key actions") - print("Set new key actions") + return + _build_ui(new_key_actions) has_set_initial = true From 3a31dcd752982f1708ab5bcca1ced20f30245b99 Mon Sep 17 00:00:00 2001 From: Ellie Date: Fri, 25 Apr 2025 20:19:10 +0930 Subject: [PATCH 06/12] Add global dict for keybind prefix --- Mods/Keybinds/Keybinds.gd | 119 +++++++++++++++++++------- Mods/Keybinds/Resources/SettingsUI.gd | 6 ++ 2 files changed, 93 insertions(+), 32 deletions(-) diff --git a/Mods/Keybinds/Keybinds.gd b/Mods/Keybinds/Keybinds.gd index 57914ac9..afbc8854 100644 --- a/Mods/Keybinds/Keybinds.gd +++ b/Mods/Keybinds/Keybinds.gd @@ -9,10 +9,22 @@ class_name Keybinds # "key" : number_for_key_representation # "action_name" : "action_name_here" # } +# ] var key_actions : Array = [] var settings_ui : KeybindSettingUI +var KEYBIND_PREFIX : String = "kb_" func _ready() -> void: + # Alert all mods that rely on keybinds of the prefix we are using. + var global_dict = get_global_mod_data("Keybinds") + if not global_dict.has("prefix"): + global_dict["prefix"] = KEYBIND_PREFIX + else: + KEYBIND_PREFIX = global_dict["prefix"] + + # Not essential, but allows us to reference it in other mods quickly. + send_global_mod_message("Keybinds", global_dict) + # Remove the temp panel and attach the children to the # settings window! This way we aren't messing around with # tracked settings, and instead are simply loading our own UI. @@ -23,16 +35,20 @@ func _ready() -> void: get_settings_window().add_child(new_keybind_button) new_keybind_button.pressed.connect(_new_keybind) + var load_default_button : Button = Button.new() + load_default_button.text = "Reset Keybinds" + get_settings_window().add_child(load_default_button) + load_default_button.pressed.connect(_load_default) + var first_child = panel.get_child(0) settings_ui = first_child panel.remove_child(settings_ui) get_settings_window().add_child(settings_ui) settings_ui.on_change_item.connect(on_ui_change_item) settings_ui.size_flags_vertical = Control.SIZE_EXPAND_FILL - - # Trigger load - var settings = save_settings() - load_settings(settings) + + # Always make sure we remove previous actions in case there's a double-up. + _remove_actions() func _new_keybind() -> void: settings_ui.add_key_action(null) @@ -41,7 +57,9 @@ func on_ui_change_item(action : int, item : Dictionary, old_item : Dictionary): if action == ChangeAction.ACTION_NAME or action == ChangeAction.KEY_BIND: # Updates should be fine as there is a reference to the item. # We only have to check if there isn't an item, then add an item. - if action == ChangeAction.ACTION_NAME and _get_key_action_by_item(item) == null: + if action == ChangeAction.ACTION_NAME \ + and item["action_name"] != "" \ + and _get_key_action_by_item(item) == null: key_actions.append(item) _create_action(item) else: @@ -51,17 +69,17 @@ func on_ui_change_item(action : int, item : Dictionary, old_item : Dictionary): _remove_key_action_by_item(item) # Adjust our input map. - var action_event_count = len(InputMap.action_get_events(item["action_name"])) + var action_event_count = len(InputMap.action_get_events(KEYBIND_PREFIX + item["action_name"])) if action_event_count <= 1: # Delete the entire action. print_log("Deleting the entire action for %s" % item["action_name"]) - InputMap.erase_action(item["action_name"]) + InputMap.erase_action(KEYBIND_PREFIX + item["action_name"]) else: # Delete just our event. var key_event = _create_key_event(item["key"]) if key_event != null: print_log("Deleting just our event for %s" % item["action_name"]) - InputMap.action_erase_event(item["action_name"], key_event) + InputMap.action_erase_event(KEYBIND_PREFIX + item["action_name"], key_event) save_settings() @@ -74,44 +92,65 @@ func _create_key_event(key : int) -> InputEventKey: func _create_action(item : Dictionary) -> void: var action = item["action_name"] - + # Do not create empty. if action == "": return - + print_log("Creating new action and associated event %s" % action) var key_event = _create_key_event(item["key"]) - if not InputMap.has_action(action): - InputMap.add_action(action) - + if not InputMap.has_action(KEYBIND_PREFIX + action): + InputMap.add_action(KEYBIND_PREFIX + action) + # Always add the event to the action, if there is no action it was made. # existing events for the action have been cleared. if key_event != null: - InputMap.action_add_event(action, key_event) + InputMap.action_add_event(KEYBIND_PREFIX + action, key_event) func _update_action(new_item : Dictionary, old_item : Dictionary) -> void: - if new_item["action_name"] != old_item["action_name"]: - print_log("New item action name (%s) is different from the old (%s)." % [new_item["action_name"], old_item["action_name"]]) - InputMap.erase_action(old_item["action_name"]) + var new_action = new_item["action_name"] + var old_action = old_item["action_name"] + var new_key = new_item["key"] + var old_key = old_item["key"] + + if new_action != old_action: + print_log("New item action name (%s) is different from the old (%s)." % + [new_action, old_action]) + var existing_events = InputMap.action_get_events(KEYBIND_PREFIX + old_action) + if old_action != "" and len(existing_events) < 1: + InputMap.erase_action(KEYBIND_PREFIX + old_action) _create_action(new_item) - elif new_item["key"] != old_item["key"]: + elif new_key != old_key: print_log("New item key is not the same as the old key.") - if old_item["key"] != -1: + if old_key != -1: print_log("Old item key is not unassigned. Removing the old item key event.") - var old_key_event = _create_key_event(old_item["key"]) - InputMap.action_erase_event(new_item["action_name"], old_key_event) + var old_key_event = _create_key_event(old_key) + if new_action == "": + # We need to cycle through all actions and events + # and find where the key is used and remove it. + for action_name in InputMap.get_actions(): + if not action_name.begins_with(KEYBIND_PREFIX): + continue + if not InputMap.event_is_action(old_key_event, action_name, true): + continue + print("Removing orphan event from %s action" % action_name) + InputMap.action_erase_event(action_name, old_key_event) + else: + InputMap.action_erase_event(KEYBIND_PREFIX + new_action, old_key_event) print_log("Adding event for the action name with the correct key.") # We only want to create a new key event if it wasn't reset. - var new_key_event = _create_key_event(new_item["key"]) - if new_key_event != null and new_item["action_name"] != "": - InputMap.action_add_event(new_item["action_name"], new_key_event) + var new_key_event = _create_key_event(new_key) + if new_key_event != null and new_action != "": + InputMap.action_add_event(KEYBIND_PREFIX + new_action, new_key_event) func _input(event : InputEvent) -> void: - if InputMap.has_action("ping") and event.is_action_pressed("ping"): + if InputMap.has_action(KEYBIND_PREFIX + "ping") \ + and event.is_action_pressed(KEYBIND_PREFIX + "ping"): print_log("pong!") + set_status("Pong!") #if event is InputEventKey: #print_log("Key pressed") ##if event.physical_keycode in key_actions: @@ -157,19 +196,35 @@ func _create_initial_actions() -> void: }, ] +func _remove_actions() -> void: + for action_name in InputMap.get_actions(): + # ONLY remove our actions we make. + if not action_name.begins_with(KEYBIND_PREFIX): + continue + InputMap.erase_action(action_name) + +func _load_default() -> void: + _remove_actions() + _create_initial_actions() + _add_actions() + settings_ui.reset() + settings_ui.set_initial_key_actions(key_actions) + func save_before(_settings_current : Dictionary): _settings_current["keybinds_key_actions"] = key_actions print_log("Saved key actions") func load_after(_settings_old : Dictionary, _settings_new : Dictionary): - print_log("Load after") if _settings_new.has("keybinds_key_actions") and len(_settings_new["keybinds_key_actions"]) > 0: key_actions = _settings_new["keybinds_key_actions"] print_log("Loaded key actions.") - else: - # Add default. - print_log("Loading default key actions.") - _create_initial_actions() + # Try set initial, it will return if initial has already been set. - settings_ui.set_initial_key_actions(key_actions) - _add_actions() + if len(key_actions) <= 0: + return + print_log("Attempting to load...") + if not settings_ui.has_set_initial: + print("Initial adding of actions.") + _add_actions() + print_log("Setting up UI...") + settings_ui.set_initial_key_actions(key_actions) diff --git a/Mods/Keybinds/Resources/SettingsUI.gd b/Mods/Keybinds/Resources/SettingsUI.gd index 3739f90a..ba7bd248 100644 --- a/Mods/Keybinds/Resources/SettingsUI.gd +++ b/Mods/Keybinds/Resources/SettingsUI.gd @@ -7,6 +7,12 @@ class_name KeybindSettingUI signal on_change_item(action : int, item : Dictionary, old_item : Dictionary) +## Resets initial state and removes all UI items. +func reset() -> void: + has_set_initial = false + for child in attached.get_children(): + attached.remove_child(child) + ## ONLY used for the first initial ready setup of key actions. func set_initial_key_actions(new_key_actions : Array) -> void: if has_set_initial: From a6bee6e9c97c6ba03aea95644b623bab518568e6 Mon Sep 17 00:00:00 2001 From: Ellie Date: Fri, 25 Apr 2025 20:39:21 +0930 Subject: [PATCH 07/12] Add keybind for model toggle --- Mods/ModelToggle/ModelToggle.gd | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Mods/ModelToggle/ModelToggle.gd b/Mods/ModelToggle/ModelToggle.gd index 48a3bcd3..29939559 100644 --- a/Mods/ModelToggle/ModelToggle.gd +++ b/Mods/ModelToggle/ModelToggle.gd @@ -4,6 +4,8 @@ var model_name : String = "" var redeem_name : String = "" var start_hidden : bool = true var time_until_undo : float = 0.0 +var keybind_action_name : String = "" +var keybind_prefix : String = "" var currently_toggled : bool = false var current_time_until_undo : float = 0.0 @@ -42,6 +44,26 @@ func handle_channel_point_redeem(_redeemer_username, _redeemer_display_name, _re _update_model() +func _input(event: InputEvent) -> void: + if InputMap.has_action(keybind_prefix + keybind_action_name) \ + and event.is_action_pressed(keybind_prefix + keybind_action_name): + print_log("Toggling via keybind.") + currently_toggled = !currently_toggled + _update_model() + +func _handle_global_mod_message(key : String, values : Dictionary): + if not key == "Keybinds": + return + keybind_prefix = values["prefix"] + +func check_configuration() -> PackedStringArray: + var errors : PackedStringArray = [] + + if keybind_prefix == "" and keybind_action_name != "": + errors.append("No Keybinds mod installed. Keybind toggles for moddle toggle will not work.") + + return errors + func _process(delta): if current_time_until_undo > 0.0: @@ -60,6 +82,7 @@ func load_after(_settings_old : Dictionary, _settings_new : Dictionary): func _ready(): add_tracked_setting("start_hidden", "Start hidden") add_tracked_setting("model_name", "Model name") + add_tracked_setting("keybind_action_name", "Toggle keybind action name") add_tracked_setting("redeem_name", "Redeem name", {"is_redeem" : true}) add_tracked_setting("time_until_undo", "Time until reset", {"min": 0.0, "max":24*60}) update_settings_ui() From 731687ef30626b51674728d1be162c2e506a8e11 Mon Sep 17 00:00:00 2001 From: Ellie Date: Fri, 25 Apr 2025 20:41:41 +0930 Subject: [PATCH 08/12] Fix spelling Woooops --- Mods/ModelToggle/ModelToggle.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mods/ModelToggle/ModelToggle.gd b/Mods/ModelToggle/ModelToggle.gd index 29939559..d01829cd 100644 --- a/Mods/ModelToggle/ModelToggle.gd +++ b/Mods/ModelToggle/ModelToggle.gd @@ -60,7 +60,7 @@ func check_configuration() -> PackedStringArray: var errors : PackedStringArray = [] if keybind_prefix == "" and keybind_action_name != "": - errors.append("No Keybinds mod installed. Keybind toggles for moddle toggle will not work.") + errors.append("No Keybinds mod installed. Keybind toggle for model will not work.") return errors From 26695d25ffa9f135c4a34f6efa8763191cc542ba Mon Sep 17 00:00:00 2001 From: Ellie Date: Mon, 26 May 2025 08:52:03 +0930 Subject: [PATCH 09/12] Remove need for mods to monitor input events --- Mods/Keybinds/Keybinds.gd | 17 +++++++++++++---- Mods/ModelToggle/ModelToggle.gd | 16 ++++++---------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/Mods/Keybinds/Keybinds.gd b/Mods/Keybinds/Keybinds.gd index afbc8854..556e6208 100644 --- a/Mods/Keybinds/Keybinds.gd +++ b/Mods/Keybinds/Keybinds.gd @@ -147,10 +147,19 @@ func _update_action(new_item : Dictionary, old_item : Dictionary) -> void: InputMap.action_add_event(KEYBIND_PREFIX + new_action, new_key_event) func _input(event : InputEvent) -> void: - if InputMap.has_action(KEYBIND_PREFIX + "ping") \ - and event.is_action_pressed(KEYBIND_PREFIX + "ping"): - print_log("pong!") - set_status("Pong!") + for action in InputMap.get_actions(): + if event.is_action_pressed(action): + send_global_mod_message("KeybindsActionPressed", + { + "action": action.replace(KEYBIND_PREFIX, ""), + "event": event + }) + + #if InputMap.has_action(KEYBIND_PREFIX + "ping") \ + #and event.is_action_pressed(KEYBIND_PREFIX + "ping"): + #print_log("pong!") + #set_status("Pong!") + #if event is InputEventKey: #print_log("Key pressed") ##if event.physical_keycode in key_actions: diff --git a/Mods/ModelToggle/ModelToggle.gd b/Mods/ModelToggle/ModelToggle.gd index d01829cd..c47ddcbe 100644 --- a/Mods/ModelToggle/ModelToggle.gd +++ b/Mods/ModelToggle/ModelToggle.gd @@ -44,22 +44,18 @@ func handle_channel_point_redeem(_redeemer_username, _redeemer_display_name, _re _update_model() -func _input(event: InputEvent) -> void: - if InputMap.has_action(keybind_prefix + keybind_action_name) \ - and event.is_action_pressed(keybind_prefix + keybind_action_name): +func _handle_global_mod_message(key : String, values : Dictionary): + if key == "KeybindsActionPressed" and values["action"] == keybind_action_name: print_log("Toggling via keybind.") currently_toggled = !currently_toggled _update_model() - -func _handle_global_mod_message(key : String, values : Dictionary): - if not key == "Keybinds": - return - keybind_prefix = values["prefix"] + elif key == "Keybinds": + keybind_prefix = values["prefix"] func check_configuration() -> PackedStringArray: var errors : PackedStringArray = [] - - if keybind_prefix == "" and keybind_action_name != "": + var global_dict = get_global_mod_data("Keybinds") + if global_dict.get("prefix", "") == "" and keybind_action_name != "": errors.append("No Keybinds mod installed. Keybind toggle for model will not work.") return errors From c76d3c276cd3b1cea0906c8e928a83003d058a03 Mon Sep 17 00:00:00 2001 From: Ellie Date: Sat, 31 May 2025 18:42:01 +0930 Subject: [PATCH 10/12] Add support for modifier + key --- Mods/Keybinds/Keybinds.gd | 41 ++++++++++++++++++++--------- Mods/Keybinds/Resources/ActionUI.gd | 40 ++++++++++++++++++++-------- 2 files changed, 57 insertions(+), 24 deletions(-) diff --git a/Mods/Keybinds/Keybinds.gd b/Mods/Keybinds/Keybinds.gd index 556e6208..c9ca5738 100644 --- a/Mods/Keybinds/Keybinds.gd +++ b/Mods/Keybinds/Keybinds.gd @@ -76,18 +76,25 @@ func on_ui_change_item(action : int, item : Dictionary, old_item : Dictionary): InputMap.erase_action(KEYBIND_PREFIX + item["action_name"]) else: # Delete just our event. - var key_event = _create_key_event(item["key"]) + var key_event = _create_key_event(item) if key_event != null: print_log("Deleting just our event for %s" % item["action_name"]) InputMap.action_erase_event(KEYBIND_PREFIX + item["action_name"], key_event) save_settings() -func _create_key_event(key : int) -> InputEventKey: +func _create_key_event(item : Dictionary) -> InputEventKey: + var key : int = item["key"] + var alt_pressed : bool = item.get("modifier_alt", false) + var ctrl_pressed : bool = item.get("modifier_ctrl", false) + var meta_pressed : bool = item.get("difier_meta", false) if key == -1: return null var new_key_event = InputEventKey.new() new_key_event.physical_keycode = key + new_key_event.alt_pressed = alt_pressed + new_key_event.ctrl_pressed = ctrl_pressed + new_key_event.meta_pressed = meta_pressed return new_key_event func _create_action(item : Dictionary) -> void: @@ -98,7 +105,7 @@ func _create_action(item : Dictionary) -> void: return print_log("Creating new action and associated event %s" % action) - var key_event = _create_key_event(item["key"]) + var key_event = _create_key_event(item) if not InputMap.has_action(KEYBIND_PREFIX + action): InputMap.add_action(KEYBIND_PREFIX + action) @@ -121,11 +128,13 @@ func _update_action(new_item : Dictionary, old_item : Dictionary) -> void: if old_action != "" and len(existing_events) < 1: InputMap.erase_action(KEYBIND_PREFIX + old_action) _create_action(new_item) - elif new_key != old_key: + elif new_key != old_key or new_item["modifier_alt"] != old_item["modifier_alt"] \ + or new_item["modifier_ctrl"] != old_item["modifier_ctrl"] \ + or new_item["modifier_meta"] != old_item["modifier_meta"]: print_log("New item key is not the same as the old key.") if old_key != -1: print_log("Old item key is not unassigned. Removing the old item key event.") - var old_key_event = _create_key_event(old_key) + var old_key_event = _create_key_event(old_item) if new_action == "": # We need to cycle through all actions and events # and find where the key is used and remove it. @@ -142,23 +151,23 @@ func _update_action(new_item : Dictionary, old_item : Dictionary) -> void: print_log("Adding event for the action name with the correct key.") # We only want to create a new key event if it wasn't reset. - var new_key_event = _create_key_event(new_key) + var new_key_event = _create_key_event(new_item) if new_key_event != null and new_action != "": InputMap.action_add_event(KEYBIND_PREFIX + new_action, new_key_event) func _input(event : InputEvent) -> void: for action in InputMap.get_actions(): - if event.is_action_pressed(action): + if event.is_action_pressed(action, false, true): send_global_mod_message("KeybindsActionPressed", { "action": action.replace(KEYBIND_PREFIX, ""), "event": event }) - #if InputMap.has_action(KEYBIND_PREFIX + "ping") \ - #and event.is_action_pressed(KEYBIND_PREFIX + "ping"): - #print_log("pong!") - #set_status("Pong!") + if InputMap.has_action(KEYBIND_PREFIX + "ping") \ + and event.is_action_pressed(KEYBIND_PREFIX + "ping", false, true): + print_log("pong!") + set_status("Pong!") #if event is InputEventKey: #print_log("Key pressed") @@ -197,11 +206,17 @@ func _create_initial_actions() -> void: key_actions = [ { "key": KEY_P, - "action_name": "ping" + "action_name": "ping", + "modifier_alt": false, + "modifier_ctrl": false, + "modifier_meta": false }, { "key": KEY_Y, - "action_name": "ping" + "action_name": "ping", + "modifier_alt": false, + "modifier_ctrl": true, + "modifier_meta": false }, ] diff --git a/Mods/Keybinds/Resources/ActionUI.gd b/Mods/Keybinds/Resources/ActionUI.gd index 5a6ff30a..d3596faf 100644 --- a/Mods/Keybinds/Resources/ActionUI.gd +++ b/Mods/Keybinds/Resources/ActionUI.gd @@ -2,6 +2,7 @@ extends Control class_name ActionUI var ui_item : Dictionary = {} +var old_item : Dictionary = {} var currently_setting : bool = false signal on_change_item(action : int, item : Dictionary, old_item : Dictionary) @@ -14,15 +15,22 @@ func set_item(item : Dictionary) -> void: var action : String = item["action_name"] if item["key"] != -1: - var key_code : Key = item["key"] - _set_key_bind_display(key_code) + _set_key_bind_display(item) %ActionNameTxt.text = action emit_signal("on_change_item", ChangeAction.INITIAL, item, {}) -func _set_key_bind_display(key_code : Key): +func _set_key_bind_display(item : Dictionary): + var key_code : Key = item["key"] + var alt_pressed = item.get("modifier_alt", false) + var ctrl_pressed = item.get("modifier_ctrl", false) + var meta_pressed = item.get("modifier_meta", false) + var input_event = InputEventKey.new() input_event.physical_keycode = key_code + input_event.alt_pressed = alt_pressed + input_event.ctrl_pressed = ctrl_pressed + input_event.meta_pressed = meta_pressed #input_event.get_modifiers_mask() #if has_mod: #if mod_mask & KeyModifierMask.KEY_CODE_MASK: @@ -37,11 +45,14 @@ func _set_key_bind_display(key_code : Key): func blank_item() -> void: ui_item = { "key": -1, + "modifier_alt": false, + "modifier_ctrl": false, + "modifier_meta": false, "action_name": "" } func _on_action_name_txt_text_changed(new_text : String) -> void: - var old_item = ui_item.duplicate() + old_item = ui_item.duplicate() ui_item["action_name"] = new_text emit_signal("on_change_item", ChangeAction.ACTION_NAME, ui_item, old_item) @@ -50,22 +61,29 @@ func _on_delete_btn_pressed() -> void: queue_free() func _on_reset_btn_pressed() -> void: - var old_item = ui_item.duplicate() + old_item = ui_item.duplicate() ui_item["key"] = -1 emit_signal("on_change_item", ChangeAction.KEY_BIND, ui_item, old_item) %KeybindDisplay.text = "Empty" func _input(event : InputEvent): if currently_setting and event is InputEventKey: + var key_event : InputEventKey = event + if key_event.physical_keycode == KEY_CTRL \ + or key_event.physical_keycode == KEY_ALT \ + or key_event.physical_keycode == KEY_META: + # Default, probably only has modifier applied. + return currently_setting = false + old_item = ui_item.duplicate() + ui_item["key"] = event.physical_keycode + ui_item["modifier_alt"] = event.alt_pressed + ui_item["modifier_ctrl"] = event.ctrl_pressed + ui_item["modifier_meta"] = event.meta_pressed %SetBtn.text = "Set" - var new_key = event.physical_keycode - var old_item = ui_item.duplicate() - ui_item["key"] = new_key emit_signal("on_change_item", ChangeAction.KEY_BIND, ui_item, old_item) - _set_key_bind_display(new_key) + _set_key_bind_display(ui_item) func _on_set_btn_pressed() -> void: currently_setting = true - if currently_setting: - %SetBtn.text = "Press Key" + %SetBtn.text = "Press Keys" From ac47376f9d65de13f6d38d8a2ee22c8903720b2f Mon Sep 17 00:00:00 2001 From: Ellie Date: Thu, 13 Nov 2025 15:47:51 +1030 Subject: [PATCH 11/12] Fix typo in keybinds modifier variable name --- Mods/Keybinds/Keybinds.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mods/Keybinds/Keybinds.gd b/Mods/Keybinds/Keybinds.gd index c9ca5738..2b1f1adf 100644 --- a/Mods/Keybinds/Keybinds.gd +++ b/Mods/Keybinds/Keybinds.gd @@ -87,7 +87,7 @@ func _create_key_event(item : Dictionary) -> InputEventKey: var key : int = item["key"] var alt_pressed : bool = item.get("modifier_alt", false) var ctrl_pressed : bool = item.get("modifier_ctrl", false) - var meta_pressed : bool = item.get("difier_meta", false) + var meta_pressed : bool = item.get("modifier_meta", false) if key == -1: return null var new_key_event = InputEventKey.new() From 159574e789f43addf37d5e7019870a76e904fb5d Mon Sep 17 00:00:00 2001 From: Ellie Date: Thu, 13 Nov 2025 16:07:24 +1030 Subject: [PATCH 12/12] Add shift key modifier support --- Mods/Keybinds/Keybinds.gd | 28 ++++++++++++++++------------ Mods/Keybinds/Resources/ActionUI.gd | 10 ++++++---- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/Mods/Keybinds/Keybinds.gd b/Mods/Keybinds/Keybinds.gd index 2b1f1adf..3ecfbd2a 100644 --- a/Mods/Keybinds/Keybinds.gd +++ b/Mods/Keybinds/Keybinds.gd @@ -88,6 +88,7 @@ func _create_key_event(item : Dictionary) -> InputEventKey: var alt_pressed : bool = item.get("modifier_alt", false) var ctrl_pressed : bool = item.get("modifier_ctrl", false) var meta_pressed : bool = item.get("modifier_meta", false) + var shift_pressed : bool = item.get("modifier_shift", false) if key == -1: return null var new_key_event = InputEventKey.new() @@ -95,6 +96,7 @@ func _create_key_event(item : Dictionary) -> InputEventKey: new_key_event.alt_pressed = alt_pressed new_key_event.ctrl_pressed = ctrl_pressed new_key_event.meta_pressed = meta_pressed + new_key_event.shift_pressed = shift_pressed return new_key_event func _create_action(item : Dictionary) -> void: @@ -128,8 +130,10 @@ func _update_action(new_item : Dictionary, old_item : Dictionary) -> void: if old_action != "" and len(existing_events) < 1: InputMap.erase_action(KEYBIND_PREFIX + old_action) _create_action(new_item) - elif new_key != old_key or new_item["modifier_alt"] != old_item["modifier_alt"] \ + elif new_key != old_key \ + or new_item["modifier_alt"] != old_item["modifier_alt"] \ or new_item["modifier_ctrl"] != old_item["modifier_ctrl"] \ + or new_item["modifier_shift"] != old_item["modifier_shift"] \ or new_item["modifier_meta"] != old_item["modifier_meta"]: print_log("New item key is not the same as the old key.") if old_key != -1: @@ -163,19 +167,17 @@ func _input(event : InputEvent) -> void: "action": action.replace(KEYBIND_PREFIX, ""), "event": event }) - + # This is one way to do actions. The other is with global mod data. if InputMap.has_action(KEYBIND_PREFIX + "ping") \ and event.is_action_pressed(KEYBIND_PREFIX + "ping", false, true): - print_log("pong!") + print_log("Input map pong!") set_status("Pong!") - #if event is InputEventKey: - #print_log("Key pressed") - ##if event.physical_keycode in key_actions: - #var value = _get_key_action_by_input(event.physical_keycode) - #if value == null: - #return - #print_log(value["action_name"]) + # The alternative approach is commented below. + #func _handle_global_mod_message(key : String, values : Dictionary): + #if key == "KeybindsActionPressed" and values["action"] == "ping": + #print_log("Global mod message pong!") + #set_status("Pong!") func _get_key_action_by_item(item : Dictionary): for i in key_actions: @@ -209,14 +211,16 @@ func _create_initial_actions() -> void: "action_name": "ping", "modifier_alt": false, "modifier_ctrl": false, - "modifier_meta": false + "modifier_meta": false, + "modifier_shift": false }, { "key": KEY_Y, "action_name": "ping", "modifier_alt": false, "modifier_ctrl": true, - "modifier_meta": false + "modifier_meta": false, + "modifier_shift": false }, ] diff --git a/Mods/Keybinds/Resources/ActionUI.gd b/Mods/Keybinds/Resources/ActionUI.gd index d3596faf..eefd7e21 100644 --- a/Mods/Keybinds/Resources/ActionUI.gd +++ b/Mods/Keybinds/Resources/ActionUI.gd @@ -25,16 +25,15 @@ func _set_key_bind_display(item : Dictionary): var alt_pressed = item.get("modifier_alt", false) var ctrl_pressed = item.get("modifier_ctrl", false) var meta_pressed = item.get("modifier_meta", false) + var shift_pressed = item.get("modifier_shift", false) var input_event = InputEventKey.new() input_event.physical_keycode = key_code input_event.alt_pressed = alt_pressed input_event.ctrl_pressed = ctrl_pressed input_event.meta_pressed = meta_pressed - #input_event.get_modifiers_mask() - #if has_mod: - #if mod_mask & KeyModifierMask.KEY_CODE_MASK: - #pass + input_event.shift_pressed = shift_pressed + var display_bind = OS.get_keycode_string( DisplayServer.keyboard_get_label_from_physical( input_event.get_physical_keycode_with_modifiers())) @@ -48,6 +47,7 @@ func blank_item() -> void: "modifier_alt": false, "modifier_ctrl": false, "modifier_meta": false, + "modifier_shift": false, "action_name": "" } @@ -71,6 +71,7 @@ func _input(event : InputEvent): var key_event : InputEventKey = event if key_event.physical_keycode == KEY_CTRL \ or key_event.physical_keycode == KEY_ALT \ + or key_event.physical_keycode == KEY_SHIFT \ or key_event.physical_keycode == KEY_META: # Default, probably only has modifier applied. return @@ -80,6 +81,7 @@ func _input(event : InputEvent): ui_item["modifier_alt"] = event.alt_pressed ui_item["modifier_ctrl"] = event.ctrl_pressed ui_item["modifier_meta"] = event.meta_pressed + ui_item["modifier_shift"] = event.shift_pressed %SetBtn.text = "Set" emit_signal("on_change_item", ChangeAction.KEY_BIND, ui_item, old_item) _set_key_bind_display(ui_item)