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:
parent
836d8e2f88
commit
b13ef309af
7 changed files with 114 additions and 93 deletions
|
@ -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+<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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
-- }
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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
|
||||
},
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue