From b13ef309afcb5cbf88580e67b612f7c64359e12f Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sat, 1 Apr 2023 00:02:34 -0600 Subject: [PATCH] Keybind and mod option improvements (#27) * Fix category widget cutoff * Fix keybind reset-to-default * Fix multiple keybinds using the same set of keys * Comment out unimplemented settings * Reposition mod options widgets --- .../mods/dmf/modules/core/keybindings.lua | 117 +++++++++++------- dmf/scripts/mods/dmf/modules/core/options.lua | 12 -- dmf/scripts/mods/dmf/modules/dmf_options.lua | 20 +-- .../modules/ui/options/dmf_options_view.lua | 4 +- .../options/dmf_options_view_definitions.lua | 5 +- .../ui/options/dmf_options_view_settings.lua | 8 +- .../dmf/modules/ui/options/mod_options.lua | 41 +++--- 7 files changed, 114 insertions(+), 93 deletions(-) diff --git a/dmf/scripts/mods/dmf/modules/core/keybindings.lua b/dmf/scripts/mods/dmf/modules/core/keybindings.lua index f001b43..50105af 100644 --- a/dmf/scripts/mods/dmf/modules/core/keybindings.lua +++ b/dmf/scripts/mods/dmf/modules/core/keybindings.lua @@ -150,19 +150,23 @@ local PRIMARY_BINDABLE_KEYS = { }]] } -local OTHER_KEYS = { - -- modifier keys - ["left shift"] = {160, "Shift", "keyboard", 161}, - ["right shift"] = {160, "Shift", "keyboard", 161}, - ["shift"] = {160, "Shift", "keyboard", 161}, - ["left ctrl"] = {162, "Ctrl", "keyboard", 163}, - ["right ctrl"] = {162, "Ctrl", "keyboard", 163}, - ["ctrl"] = {162, "Ctrl", "keyboard", 163}, - ["left alt"] = {164, "Alt", "keyboard", 165}, - ["right alt"] = {164, "Alt", "keyboard", 165}, - ["alt"] = {164, "Alt", "keyboard", 165}, - -- hack for 'dmf.build_keybind_string' function - ["no_button"] = {-1, ""} +local MODIFIER_KEYS = { + ["left shift"] = {160, "shift", "keyboard", 161}, + ["right shift"] = {160, "shift", "keyboard", 161}, + ["shift"] = {160, "shift", "keyboard", 161}, + ["left ctrl"] = {162, "ctrl", "keyboard", 163}, + ["right ctrl"] = {162, "ctrl", "keyboard", 163}, + ["ctrl"] = {162, "ctrl", "keyboard", 163}, + ["left alt"] = {164, "alt", "keyboard", 165}, + ["right alt"] = {164, "alt", "keyboard", 165}, + ["alt"] = {164, "alt", "keyboard", 165}, +} + +-- Both are treated equally in keybinds, but these global keys aren't localized +local MODIFIER_KEYS_LOC_ALIAS = { + keyboard_ctrl = "keyboard_left ctrl", + keyboard_alt = "keyboard_left alt", + keyboard_shift = "keyboard_left shift", } local KEYS_INFO = {} @@ -174,7 +178,7 @@ for input_device_name, input_device_keys in pairs(PRIMARY_BINDABLE_KEYS) do end end -for key_id, key_data in pairs(OTHER_KEYS) do +for key_id, key_data in pairs(MODIFIER_KEYS) do KEYS_INFO[key_id] = key_data end @@ -190,6 +194,15 @@ local CHECK_INPUT_FUNCTIONS = { } } +local KEYS_INPUT_FUNCTIONS = {} + +for key_id, key_data in pairs(KEYS_INFO) do + KEYS_INPUT_FUNCTIONS[key_id] = { + check_pressed = CHECK_INPUT_FUNCTIONS[key_data[3]].PRESSED, + check_released = CHECK_INPUT_FUNCTIONS[key_data[3]].RELEASED + } +end + local _raw_keybinds_data = {} local _keybinds = {} local _pressed_key @@ -239,6 +252,11 @@ local function perform_keybind_action(data, is_pressed) end end + +local function is_modifier_pressed(modifier) + return (Keyboard.button(MODIFIER_KEYS[modifier][1]) + Keyboard.button(MODIFIER_KEYS[modifier][4])) > 0 +end + -- ##################################################################################################################### -- ##### DMF internal functions and variables ########################################################################## -- ##################################################################################################################### @@ -249,9 +267,11 @@ end -- * If several mods bound the same keys, keybind action will be performed for all of them, when keybind is pressed. -- * Keybind is considered released, when its primary key is released. function dmf.check_keybinds() - local ctrl_pressed = (Keyboard.button(KEYS_INFO["ctrl"][1]) + Keyboard.button(KEYS_INFO["ctrl"][4])) > 0 - local alt_pressed = (Keyboard.button(KEYS_INFO["alt"][1]) + Keyboard.button(KEYS_INFO["alt"][4])) > 0 - local shift_pressed = (Keyboard.button(KEYS_INFO["shift"][1]) + Keyboard.button(KEYS_INFO["shift"][4])) > 0 + local pressed_modifiers = { + ctrl = is_modifier_pressed("ctrl"), + alt = is_modifier_pressed("alt"), + shift = is_modifier_pressed("shift") + } if not _pressed_key then for primary_key, keybinds_data in pairs(_keybinds) do @@ -259,26 +279,26 @@ function dmf.check_keybinds() for _, keybind_data in ipairs(keybinds_data) do local all_pressed = true - for enabler, _ in pairs(keybind_data.enablers) do - -- Check that every enabler key is pressed - if OTHER_KEYS[enabler] and - ( - Keyboard.button(KEYS_INFO[enabler][1]) + - Keyboard.button(KEYS_INFO[enabler][4]) - ) <= 0 - or not (Keyboard.button(KEYS_INFO[enabler][1]) > 0) - then + -- Check that every enabler key is pressed + for enabler, _ in pairs(keybind_data.enablers) do + if MODIFIER_KEYS[enabler] then + if not pressed_modifiers[MODIFIER_KEYS[enabler][2]] then + all_pressed = false + break + end + elseif KEYS_INPUT_FUNCTIONS[enabler].check_released(enabler) then all_pressed = false break end end -- Check that no modifier keys are pressed that shouldn't be - if all_pressed and - (not keybind_data.ctrl and ctrl_pressed) and - (not keybind_data.alt and alt_pressed) and - (not keybind_data.shift and shift_pressed) + if all_pressed and ( + (not keybind_data.ctrl and pressed_modifiers.ctrl) or + (not keybind_data.alt and pressed_modifiers.alt) or + (not keybind_data.shift and pressed_modifiers.shift) + ) then all_pressed = false end @@ -293,9 +313,6 @@ function dmf.check_keybinds() end end end - if _pressed_key then - break - end end end end @@ -324,9 +341,9 @@ function dmf.generate_keybinds() local keys = raw_keybind_data.keys local primary_key = keys[1] - local modifier_keys = {} + local enabler_keys = {} for i = 2, #keys do - modifier_keys[keys[i]] = true + enabler_keys[keys[i]] = true end local keybind_data = { @@ -334,18 +351,18 @@ function dmf.generate_keybinds() global = raw_keybind_data.global, trigger = raw_keybind_data.trigger, type = raw_keybind_data.type, - enablers = modifier_keys, - ctrl = modifier_keys["ctrl"] or modifier_keys["left ctrl"] or modifier_keys["right ctrl"], - alt = modifier_keys["alt"] or modifier_keys["left alt"] or modifier_keys["right alt"], - shift = modifier_keys["shift"] or modifier_keys["left shift"] or modifier_keys["right shift"], + enablers = enabler_keys, + ctrl = enabler_keys["ctrl"] or enabler_keys["left ctrl"] or enabler_keys["right ctrl"], + alt = enabler_keys["alt"] or enabler_keys["left alt"] or enabler_keys["right alt"], + shift = enabler_keys["shift"] or enabler_keys["left shift"] or enabler_keys["right shift"], function_name = raw_keybind_data.function_name, view_name = raw_keybind_data.view_name } _keybinds[primary_key] = _keybinds[primary_key] or { - check_pressed = CHECK_INPUT_FUNCTIONS[KEYS_INFO[primary_key][3]].PRESSED, - check_released = CHECK_INPUT_FUNCTIONS[KEYS_INFO[primary_key][3]].RELEASED + check_pressed = KEYS_INPUT_FUNCTIONS[primary_key].check_pressed, + check_released = KEYS_INPUT_FUNCTIONS[primary_key].check_released } table.insert(_keybinds[primary_key], keybind_data) end @@ -394,18 +411,16 @@ end -- Simply tells if key with key_id can be binded as primary key. -- (Used for verifying keybind widgets) function dmf.can_bind_as_primary_key(key_id) - return KEYS_INFO[key_id] and not OTHER_KEYS[key_id] + return KEYS_INFO[key_id] and not MODIFIER_KEYS[key_id] end --- Builds string with readable keys' names to look like "Primary Key + Ctrl + Alt + Shift". +-- Builds string with readable keys' names to look like e.g. "Ctrl+Alt+Shift+". -- (Used in keybind widget) function dmf.build_keybind_string(keys) - local readable_key_names = {} - for _, key_id in ipairs(keys) do - table.insert(readable_key_names, KEYS_INFO[key_id][2]) - end - return table.concat(readable_key_names, " + ") + local key_unassigned_string = Managers.localization:localize("loc_keybind_unassigned") + local keybind_result = dmf.keys_to_keybind_result(keys) + return keybind_result and InputUtils.localized_string_from_key_info(keybind_result) or key_unassigned_string end @@ -465,6 +480,9 @@ function dmf.keys_to_keybind_result(keys) return nil end + if MODIFIER_KEYS_LOC_ALIAS[global_name] then + global_name = MODIFIER_KEYS_LOC_ALIAS[global_name] + end keybind_result.main = global_name end @@ -474,6 +492,9 @@ function dmf.keys_to_keybind_result(keys) local global_name = KEYS_INFO[local_name] and InputUtils.local_to_global_name(local_name, KEYS_INFO[local_name][3]) if global_name then + if MODIFIER_KEYS_LOC_ALIAS[global_name] then + global_name = MODIFIER_KEYS_LOC_ALIAS[global_name] + end keybind_result.enablers[#keybind_result.enablers + 1] = global_name end end diff --git a/dmf/scripts/mods/dmf/modules/core/options.lua b/dmf/scripts/mods/dmf/modules/core/options.lua index 66bf77f..e10fa31 100644 --- a/dmf/scripts/mods/dmf/modules/core/options.lua +++ b/dmf/scripts/mods/dmf/modules/core/options.lua @@ -301,11 +301,6 @@ local allowed_keybind_types = { view_toggle = true, mod_toggle = true } -local allowed_modifier_keys = { - ctrl = true, - alt = true, - shift = true -} local function validate_keybind_data(data) if data.keybind_global and type(data.keybind_global) ~= "boolean" then dmf.throw_error("[widget \"%s\" (keybind)]: 'keybind_global' field must have 'boolean' type", data.setting_id) @@ -344,13 +339,6 @@ local function validate_keybind_data(data) if default_value[1] and not dmf.can_bind_as_primary_key(default_value[1]) then dmf.throw_error("[widget \"%s\" (keybind)]: 'default_value[1]' must be a valid key name", data.setting_id) end - if default_value[2] and not allowed_modifier_keys[default_value[2]] or - default_value[3] and not allowed_modifier_keys[default_value[3]] or - default_value[4] and not allowed_modifier_keys[default_value[4]] - then - dmf.throw_error("[widget \"%s\" (keybind)]: 'default_value [2], [3] and [4]' can be only strings: \"ctrl\", " .. - "\"alt\" and \"shift\" (in no particular order)", data.setting_id) - end local used_keys = {} for _, key in ipairs(default_value) do diff --git a/dmf/scripts/mods/dmf/modules/dmf_options.lua b/dmf/scripts/mods/dmf/modules/dmf_options.lua index 573c591..40848b6 100644 --- a/dmf/scripts/mods/dmf/modules/dmf_options.lua +++ b/dmf/scripts/mods/dmf/modules/dmf_options.lua @@ -38,16 +38,16 @@ dmf_mod_data.options = { keybind_type = "function_call", function_name = "toggle_developer_console" }, - { - setting_id = "show_network_debug_info", - type = "checkbox", - default_value = false - }, - { - setting_id = "log_ui_renderers_info", - type = "checkbox", - default_value = false - } + -- { + -- setting_id = "show_network_debug_info", + -- type = "checkbox", + -- default_value = false + -- }, + -- { + -- setting_id = "log_ui_renderers_info", + -- type = "checkbox", + -- default_value = false + -- } } }, { diff --git a/dmf/scripts/mods/dmf/modules/ui/options/dmf_options_view.lua b/dmf/scripts/mods/dmf/modules/ui/options/dmf_options_view.lua index 8991315..44882c1 100644 --- a/dmf/scripts/mods/dmf/modules/ui/options/dmf_options_view.lua +++ b/dmf/scripts/mods/dmf/modules/ui/options/dmf_options_view.lua @@ -676,7 +676,7 @@ DMFOptionsView.present_category_widgets = function (self, category) local scrollbar_widget_id = "settings_scrollbar" local grid_scenegraph_id = "settings_grid_background" local grid_pivot_scenegraph_id = "settings_grid_content_pivot" - local grid_spacing = _view_settings.grid_spacing + local grid_spacing = _view_settings.settings_grid_spacing self._settings_content_grid = self:_setup_grid(self._settings_content_widgets, self._settings_alignment_list, grid_scenegraph_id, grid_spacing, false) self:_setup_content_grid_scrollbar(self._settings_content_grid, scrollbar_widget_id, grid_scenegraph_id, grid_pivot_scenegraph_id) @@ -745,7 +745,7 @@ DMFOptionsView._setup_category_config = function (self, config) local scrollbar_widget_id = "scrollbar" local grid_scenegraph_id = "background" local grid_pivot_scenegraph_id = "grid_content_pivot" - local grid_spacing = _view_settings.grid_spacing + local grid_spacing = _view_settings.category_grid_spacing self._category_content_grid = self:_setup_grid(self._category_content_widgets, self._category_alignment_list, grid_scenegraph_id, grid_spacing, true) self:_setup_content_grid_scrollbar(self._category_content_grid, scrollbar_widget_id, grid_scenegraph_id, grid_pivot_scenegraph_id) diff --git a/dmf/scripts/mods/dmf/modules/ui/options/dmf_options_view_definitions.lua b/dmf/scripts/mods/dmf/modules/ui/options/dmf_options_view_definitions.lua index e11b819..378b91b 100644 --- a/dmf/scripts/mods/dmf/modules/ui/options/dmf_options_view_definitions.lua +++ b/dmf/scripts/mods/dmf/modules/ui/options/dmf_options_view_definitions.lua @@ -62,9 +62,10 @@ local scenegraph_definition = { grid_width, grid_height }, + -- Move the categories up and left to compensate for removed icons position = { - 180, - 240, + 140, + 190, 1 } }, diff --git a/dmf/scripts/mods/dmf/modules/ui/options/dmf_options_view_settings.lua b/dmf/scripts/mods/dmf/modules/ui/options/dmf_options_view_settings.lua index c2802aa..2af1d39 100644 --- a/dmf/scripts/mods/dmf/modules/ui/options/dmf_options_view_settings.lua +++ b/dmf/scripts/mods/dmf/modules/ui/options/dmf_options_view_settings.lua @@ -5,9 +5,13 @@ local dmf_options_view_settings = { shading_environment = "content/shading_environments/ui/system_menu", grid_size = { 500, - 800 + 820 -- Increased to compensate for upshifted category grid }, - grid_spacing = { + category_grid_spacing = { + 0, + 3 + }, + settings_grid_spacing = { 0, 10 }, diff --git a/dmf/scripts/mods/dmf/modules/ui/options/mod_options.lua b/dmf/scripts/mods/dmf/modules/ui/options/mod_options.lua index 7e1b653..5084242 100644 --- a/dmf/scripts/mods/dmf/modules/ui/options/mod_options.lua +++ b/dmf/scripts/mods/dmf/modules/ui/options/mod_options.lua @@ -249,7 +249,9 @@ _type_template_map["dropdown"] = create_dropdown_template -- ######### Keybind ######### -- ########################### -local set_new_keybind = function (self, keybind_data) +local set_keybind = function (self, keybind_data, keys) + keybind_data.keys = keys + local mod = get_mod(keybind_data.mod_name) dmf.add_mod_keybind( mod, @@ -286,25 +288,30 @@ local create_keybind_template = function (self, params) mod_name = params.mod_name, setting_id = params.setting_id, keys = dmf.keys_to_keybind_result(params.keys), + default_value = dmf.keys_to_keybind_result(params.default_value) or {}, on_activated = function (new_value, old_value) - for i = 1, #_cancel_keys do - local cancel_key = _cancel_keys[i] - if cancel_key == new_value.main then - - -- Prevent unbinding the mod options menu - if params.setting_id ~= "open_dmf_options" then - - -- Unbind the keybind - params.keys = {} - set_new_keybind(self, params) - end + -- Prevent unbinding the mod options menu + if params.setting_id ~= "open_dmf_options" then + -- Unbind the keybind if the new value is empty + if not (new_value and new_value.main) then + set_keybind(self, params, {}) return true end + + -- Unbind the keybind if the new value matches a cancel key + for i = 1, #_cancel_keys do + local cancel_key = _cancel_keys[i] + if cancel_key == new_value.main then + set_keybind(self, params, {}) + return true + end + end end + -- Don't modify the keybind if the new value is a reserved key for i = 1, #_reserved_keys do local reserved_key = _reserved_keys[i] if reserved_key == new_value.main then @@ -312,16 +319,16 @@ local create_keybind_template = function (self, params) end end - -- Get the new keybind + -- Get the keys of the new value local keys = dmf.keybind_result_to_keys(new_value) - -- Bind the new key and prevent unbinding the mod options menu + -- Set the new keybind unless it would unbind the mod options menu if keys and #keys > 0 or params.setting_id ~= "open_dmf_options" then - params.keys = keys - set_new_keybind(self, params) + set_keybind(self, params, keys) + return true end - return true + return false end, get_function = function (template)