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
This commit is contained in:
Aussiemon 2023-04-01 00:02:34 -06:00 committed by GitHub
parent 836d8e2f88
commit b13ef309af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 114 additions and 93 deletions

View file

@ -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
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+<Primary Key>".
-- (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

View file

@ -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

View file

@ -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
-- }
}
},
{

View file

@ -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)

View file

@ -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
}
},

View file

@ -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
},

View file

@ -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)
-- 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)