otclient-redemption/modules/client_options/keybins.lua
2025-04-12 21:33:19 -03:00

759 lines
23 KiB
Lua

local actionNameLimit = 39
local changedOptions = {}
local changedKeybinds = {}
local changedHotkeys = {}
local presetWindow = nil
local actionSearchEvent
local keyEditWindow = nil
local chatModeGroup
-- controls and keybinds
function addNewPreset()
presetWindow:setText(tr('Add hotkey preset'))
presetWindow.info:setText(tr('Enter a name for the new preset:'))
presetWindow.field:clearText()
presetWindow.field:show()
presetWindow.field:focus()
presetWindow:setWidth(360)
presetWindow.action = 'add'
presetWindow:show()
presetWindow:raise()
presetWindow:focus()
controller.ui:hide()
end
function copyPreset()
presetWindow:setText(tr('Copy hotkey preset'))
presetWindow.info:setText(tr('Enter a name for the new preset:'))
presetWindow.field:clearText()
presetWindow.field:show()
presetWindow.field:focus()
presetWindow.action = 'copy'
presetWindow:setWidth(360)
presetWindow:show()
presetWindow:raise()
presetWindow:focus()
controller.ui:hide()
end
function renamePreset()
presetWindow:setText(tr('Rename hotkey preset'))
presetWindow.info:setText(tr('Enter a name for the preset:'))
presetWindow.field:setText(panels.keybindsPanel.presets.list:getCurrentOption().text)
presetWindow.field:setCursorPos(1000)
presetWindow.field:show()
presetWindow.field:focus()
presetWindow.action = 'rename'
presetWindow:setWidth(360)
presetWindow:show()
presetWindow:raise()
presetWindow:focus()
controller.ui:hide()
end
function removePreset()
presetWindow:setText(tr('Warning'))
presetWindow.info:setText(tr('Do you really want to delete the hotkey preset %s?',
panels.keybindsPanel.presets.list:getCurrentOption().text))
presetWindow.field:hide()
presetWindow.action = 'remove'
presetWindow:setWidth(presetWindow.info:getTextSize().width + presetWindow:getPaddingLeft() +
presetWindow:getPaddingRight())
presetWindow:show()
presetWindow:raise()
presetWindow:focus()
controller.ui:hide()
end
function okPresetWindow()
local presetName = presetWindow.field:getText():trim()
local selectedPreset = panels.keybindsPanel.presets.list:getCurrentOption().text
presetWindow:hide()
show()
if presetWindow.action == 'add' then
Keybind.newPreset(presetName)
panels.keybindsPanel.presets.list:addOption(presetName)
panels.keybindsPanel.presets.list:setCurrentOption(presetName)
elseif presetWindow.action == 'copy' then
if not Keybind.copyPreset(selectedPreset, presetName) then
return
end
panels.keybindsPanel.presets.list:addOption(presetName)
panels.keybindsPanel.presets.list:setCurrentOption(presetName)
elseif presetWindow.action == 'rename' then
if selectedPreset ~= presetName then
panels.keybindsPanel.presets.list:updateCurrentOption(presetName)
if changedOptions['currentPreset'] then
changedOptions['currentPreset'].value = presetName
end
Keybind.renamePreset(selectedPreset, presetName)
end
elseif presetWindow.action == 'remove' then
if Keybind.removePreset(selectedPreset) then
panels.keybindsPanel.presets.list:removeOption(selectedPreset)
end
end
end
function cancelPresetWindow()
presetWindow:hide()
show()
end
function editKeybindKeyDown(widget, keyCode, keyboardModifiers)
keyEditWindow.keyCombo:setText(determineKeyComboDesc(keyCode,
keyEditWindow.alone:isVisible() and KeyboardNoModifier or keyboardModifiers))
local category = nil
local action = nil
if keyEditWindow.keybind then
category = keyEditWindow.keybind.category
action = keyEditWindow.keybind.action
end
local keyCombo = keyEditWindow.keyCombo:getText()
local keyUsed = Keybind.isKeyComboUsed(keyCombo, category, action, getChatMode())
if not keyUsed then
for _, change in ipairs(changedHotkeys) do
if change.primary == keyCombo or change.secondary == keyCombo then
keyUsed = true
break
end
end
end
keyEditWindow.buttons.ok:setEnabled(not keyUsed)
keyEditWindow.used:setVisible(keyUsed)
end
function editKeybind(keybind)
keyEditWindow.buttons.cancel.onClick = function()
disconnect(keyEditWindow, {
onKeyDown = editKeybindKeyDown
})
keyEditWindow:hide()
keyEditWindow:ungrabKeyboard()
show()
end
keyEditWindow.info:setText(tr(
'Click \'Ok\' to assign the keybind. Click \'Clear\' to remove the keybind from \'%s: %s\'.', keybind.category,
keybind.action))
keyEditWindow.alone:setVisible(keybind.alone)
connect(keyEditWindow, {
onKeyDown = editKeybindKeyDown
})
keyEditWindow:show()
keyEditWindow:raise()
keyEditWindow:focus()
keyEditWindow:grabKeyboard()
hide()
end
function editKeybindPrimary(button)
local column = button:getParent()
local row = column:getParent()
local index = row.category .. '_' .. row.action
local keybind = Keybind.getAction(row.category, row.action)
local preset = panels.keybindsPanel.presets.list:getCurrentOption().text
keyEditWindow.keybind = {
category = row.category,
action = row.action
}
keyEditWindow:setText(tr('Edit Primary Key for \'%s\'', string.format('%s: %s', keybind.category, keybind.action)))
keyEditWindow.keyCombo:setText(Keybind.getKeybindKeys(row.category, row.action, getChatMode(), preset).primary)
editKeybind(keybind)
keyEditWindow.buttons.ok.onClick = function()
local keyCombo = keyEditWindow.keyCombo:getText()
column:setText(keyEditWindow.keyCombo:getText())
if not changedKeybinds[preset] then
changedKeybinds[preset] = {}
end
if not changedKeybinds[preset][index] then
changedKeybinds[preset][index] = {}
end
changedKeybinds[preset][index].primary = {
category = row.category,
action = row.action,
keyCombo = keyCombo
}
disconnect(keyEditWindow, {
onKeyDown = editKeybindKeyDown
})
keyEditWindow:hide()
keyEditWindow:ungrabKeyboard()
show()
applyChangedOptions()
end
keyEditWindow.buttons.clear.onClick = function()
if not changedKeybinds[preset] then
changedKeybinds[preset] = {}
end
if not changedKeybinds[preset][index] then
changedKeybinds[preset][index] = {}
end
changedKeybinds[preset][index].primary = {
category = row.category,
action = row.action,
keyCombo = ''
}
column:setText('')
disconnect(keyEditWindow, {
onKeyDown = editKeybindKeyDown
})
keyEditWindow:hide()
keyEditWindow:ungrabKeyboard()
show()
applyChangedOptions()
end
end
function editKeybindSecondary(button)
local column = button:getParent()
local row = column:getParent()
local index = row.category .. '_' .. row.action
local keybind = Keybind.getAction(row.category, row.action)
local preset = panels.keybindsPanel.presets.list:getCurrentOption().text
keyEditWindow.keybind = {
category = row.category,
action = row.action
}
keyEditWindow:setText(tr('Edit Secondary Key for \'%s\'', string.format('%s: %s', keybind.category, keybind.action)))
keyEditWindow.keyCombo:setText(Keybind.getKeybindKeys(row.category, row.action, getChatMode(), preset).secondary)
editKeybind(keybind)
keyEditWindow.buttons.ok.onClick = function()
local keyCombo = keyEditWindow.keyCombo:getText()
column:setText(keyEditWindow.keyCombo:getText())
if not changedKeybinds[preset] then
changedKeybinds[preset] = {}
end
if not changedKeybinds[preset][index] then
changedKeybinds[preset][index] = {}
end
changedKeybinds[preset][index].secondary = {
category = row.category,
action = row.action,
keyCombo = keyCombo
}
disconnect(keyEditWindow, {
onKeyDown = editKeybindKeyDown
})
keyEditWindow:hide()
keyEditWindow:ungrabKeyboard()
show()
applyChangedOptions()
end
keyEditWindow.buttons.clear.onClick = function()
if not changedKeybinds[preset] then
changedKeybinds[preset] = {}
end
if not changedKeybinds[preset][index] then
changedKeybinds[preset][index] = {}
end
changedKeybinds[preset][index].secondary = {
category = row.category,
action = row.action,
keyCombo = ''
}
column:setText('')
disconnect(keyEditWindow, {
onKeyDown = editKeybindKeyDown
})
keyEditWindow:hide()
keyEditWindow:ungrabKeyboard()
show()
applyChangedOptions()
end
end
function resetActions()
changedOptions['resetKeybinds'] = {
value = panels.keybindsPanel.presets.list:getCurrentOption().text
}
updateKeybinds()
applyChangedOptions()
end
function updateKeybinds()
panels.keybindsPanel.tablePanel.keybinds:clearData()
local sortedKeybinds = {}
for index, _ in pairs(Keybind.defaultKeybinds) do
table.insert(sortedKeybinds, index)
end
table.sort(sortedKeybinds, function(a, b)
local keybindA = Keybind.defaultKeybinds[a]
local keybindB = Keybind.defaultKeybinds[b]
if keybindA.category ~= keybindB.category then
return keybindA.category < keybindB.category
end
return keybindA.action < keybindB.action
end)
local comboBox = panels.keybindsPanel.presets.list:getCurrentOption()
if not comboBox then
return
end
for _, index in ipairs(sortedKeybinds) do
local keybind = Keybind.defaultKeybinds[index]
local keys = Keybind.getKeybindKeys(keybind.category, keybind.action, getChatMode(), comboBox.text,
changedOptions['resetKeybinds'])
addKeybind(keybind.category, keybind.action, keys.primary, keys.secondary)
end
end
function updateHotkeys()
panels.keybindsPanel.tablePanel.keybinds:clearData()
local chatMode = getChatMode()
local preset = panels.keybindsPanel.presets.list:getCurrentOption().text
if Keybind.hotkeys[chatMode][preset] then
for _, hotkey in ipairs(Keybind.hotkeys[chatMode][preset]) do
addHotkey(hotkey.hotkeyId, hotkey.action, hotkey.data, hotkey.primary, hotkey.secondary)
end
end
end
function preAddHotkey(action, data)
local preset = panels.keybindsPanel.presets.list:getCurrentOption().text
local chatMode = getChatMode()
local hotkeyId = #changedHotkeys + 1
if Keybind.hotkeys[chatMode] and Keybind.hotkeys[chatMode][preset] then
hotkeyId = hotkeyId + #Keybind.hotkeys[chatMode][preset]
end
table.insert(changedHotkeys, {
hotkeyId = hotkeyId,
action = action,
data = data,
new = true
})
addHotkey(hotkeyId, action, data)
end
function addKeybind(category, action, primary, secondary)
local rawText = string.format('%s: %s', category, action)
local text = string.format('[color=#ffffff]%s:[/color] %s', category, action)
local tooltip = nil
if rawText:len() > actionNameLimit then
tooltip = rawText
-- 15 and 8 are length of color codes
text = text:sub(1, actionNameLimit + 15 + 8) .. '...'
end
local row = panels.keybindsPanel.tablePanel.keybinds:addRow({ {
coloredText = {
text = text,
color = '#c0c0c0'
},
width = 286
}, {
style = 'VerticalSeparator'
}, {
style = 'EditableKeybindsTableColumn',
text = primary,
width = 100
}, {
style = 'VerticalSeparator'
}, {
style = 'EditableKeybindsTableColumn',
text = secondary,
width = 90
} })
row.category = category
row.action = action
if tooltip then
row:setTooltip(tooltip)
end
row:getChildByIndex(3).edit.onClick = editKeybindPrimary
row:getChildByIndex(5).edit.onClick = editKeybindSecondary
end
function clearHotkey(row)
table.insert(changedHotkeys, {
hotkeyId = row.hotkeyId,
remove = true
})
panels.keybindsPanel.tablePanel.keybinds:removeRow(row)
end
function editHotkeyKey(text)
keyEditWindow.buttons.cancel.onClick = function()
disconnect(keyEditWindow, {
onKeyDown = editKeybindKeyDown
})
keyEditWindow:hide()
keyEditWindow:ungrabKeyboard()
show()
end
keyEditWindow.info:setText(tr(
'Click \'Ok\' to assign the keybind. Click \'Clear\' to remove the keybind from \'%s\'.', text))
keyEditWindow.alone:setVisible(false)
connect(keyEditWindow, {
onKeyDown = editKeybindKeyDown
})
keyEditWindow:show()
keyEditWindow:raise()
keyEditWindow:focus()
keyEditWindow:grabKeyboard()
hide()
end
function editHotkeyPrimary(button)
local column = button:getParent()
local row = column:getParent()
local text = row:getChildByIndex(1):getText()
local hotkeyId = row.hotkeyId
local preset = panels.keybindsPanel.presets.list:getCurrentOption().text
keyEditWindow:setText(tr('Edit Primary Key for \'%s\'', text))
keyEditWindow.keyCombo:setText(Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).primary)
editHotkeyKey(text)
keyEditWindow.buttons.ok.onClick = function()
local keyCombo = keyEditWindow.keyCombo:getText()
column:setText(keyEditWindow.keyCombo:getText())
local changed = table.findbyfield(changedHotkeys, 'hotkeyId', hotkeyId)
if changed then
changed.primary = keyCombo
if not changed.secondary then
changed.secondary = Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).secondary
end
changed.editKey = true
else
table.insert(changedHotkeys, {
hotkeyId = hotkeyId,
primary = keyCombo,
secondary = Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).secondary,
editKey = true
})
end
disconnect(keyEditWindow, {
onKeyDown = editKeybindKeyDown
})
keyEditWindow:hide()
keyEditWindow:ungrabKeyboard()
show()
end
keyEditWindow.buttons.clear.onClick = function()
column:setText('')
local changed = table.findbyfield(changedHotkeys, 'hotkeyId', hotkeyId)
if changed then
changed.primary = nil
if not changed.secondary then
changed.secondary = Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).secondary
end
changed.editKey = true
else
table.insert(changedHotkeys, {
hotkeyId = hotkeyId,
secondary = Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).secondary,
editKey = true
})
end
disconnect(keyEditWindow, {
onKeyDown = editKeybindKeyDown
})
keyEditWindow:hide()
keyEditWindow:ungrabKeyboard()
show()
end
end
function editHotkeySecondary(button)
local column = button:getParent()
local row = column:getParent()
local text = row:getChildByIndex(1):getText()
local hotkeyId = row.hotkeyId
local preset = panels.keybindsPanel.presets.list:getCurrentOption().text
keyEditWindow:setText(tr('Edit Secondary Key for \'%s\'', text))
keyEditWindow.keyCombo:setText(Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).secondary)
editHotkeyKey(text)
keyEditWindow.buttons.ok.onClick = function()
local keyCombo = keyEditWindow.keyCombo:getText()
column:setText(keyEditWindow.keyCombo:getText())
if changedHotkeys[hotkeyId] then
if not changedHotkeys[hotkeyId].primary then
changedHotkeys[hotkeyId].primary = Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).primary
end
changedHotkeys[hotkeyId].secondary = keyCombo
changedHotkeys[hotkeyId].editKey = true
else
table.insert(changedHotkeys, {
hotkeyId = hotkeyId,
primary = Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).primary,
secondary = keyCombo,
editKey = true
})
end
disconnect(keyEditWindow, {
onKeyDown = editKeybindKeyDown
})
keyEditWindow:hide()
keyEditWindow:ungrabKeyboard()
show()
end
keyEditWindow.buttons.clear.onClick = function()
column:setText('')
if changedHotkeys[hotkeyId] then
if not changedHotkeys[hotkeyId].primary then
changedHotkeys[hotkeyId].primary = Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).primary
end
changedHotkeys[hotkeyId].secondary = nil
changedHotkeys[hotkeyId].editKey = true
else
table.insert(changedHotkeys, {
hotkeyId = hotkeyId,
primary = Keybind.getHotkeyKeys(hotkeyId, preset, getChatMode()).primary,
editKey = true
})
end
disconnect(keyEditWindow, {
onKeyDown = editKeybindKeyDown
})
keyEditWindow:hide()
keyEditWindow:ungrabKeyboard()
show()
end
end
function searchActions(field, text, oldText)
if actionSearchEvent then
removeEvent(actionSearchEvent)
end
actionSearchEvent = scheduleEvent(performeSearchActions, 200)
end
function performeSearchActions()
local searchText = panels.keybindsPanel.search.field:getText():trim():lower():gsub("%+", "%%+")
local rows = panels.keybindsPanel.tablePanel.keybinds.dataSpace:getChildren()
if searchText:len() > 0 then
for _, row in ipairs(rows) do
row:hide()
end
for _, row in ipairs(rows) do
local actionText = row:getChildByIndex(1):getText():lower()
local primaryText = row:getChildByIndex(3):getText():lower()
local secondaryText = row:getChildByIndex(5):getText():lower()
if actionText:find(searchText) or primaryText:find(searchText) or secondaryText:find(searchText) then
row:show()
end
end
else
for _, row in ipairs(rows) do
row:show()
end
end
removeEvent(actionSearchEvent)
actionSearchEvent = nil
end
function chatModeChange()
changedHotkeys = {}
changedKeybinds = {}
panels.keybindsPanel.search.field:clearText()
updateKeybinds()
end
function getChatMode()
if chatModeGroup:getSelectedWidget() == panels.keybindsPanel.panel.chatMode.on then
return CHAT_MODE.ON
end
return CHAT_MODE.OFF
end
function applyChangedOptions()
local needKeybindsUpdate = false
local needHotkeysUpdate = false
for key, option in pairs(changedOptions) do
if key == 'resetKeybinds' then
Keybind.resetKeybindsToDefault(option.value, option.chatMode)
needKeybindsUpdate = true
end
end
changedOptions = {}
for preset, keybinds in pairs(changedKeybinds) do
for index, keybind in pairs(keybinds) do
if keybind.primary then
if Keybind.setPrimaryActionKey(keybind.primary.category, keybind.primary.action, preset,
keybind.primary.keyCombo, getChatMode()) then
needKeybindsUpdate = true
end
elseif keybind.secondary then
if Keybind.setSecondaryActionKey(keybind.secondary.category, keybind.secondary.action, preset,
keybind.secondary.keyCombo, getChatMode()) then
needKeybindsUpdate = true
end
end
end
end
changedKeybinds = {}
if needKeybindsUpdate then
updateKeybinds()
end
g_settings.save()
end
function presetOption(widget, key, value, force)
if not controller.ui:isVisible() then
return
end
changedOptions[key] = { widget = widget, value = value, force = force }
if key == "currentPreset" then
Keybind.selectPreset(value)
panels.keybindsPanel.presets.list:setCurrentOption(value, true)
end
end
function init_binds()
chatModeGroup = UIRadioGroup.create()
chatModeGroup:addWidget(panels.keybindsPanel.panel.chatMode.on)
chatModeGroup:addWidget(panels.keybindsPanel.panel.chatMode.off)
chatModeGroup.onSelectionChange = chatModeChange
chatModeGroup:selectWidget(panels.keybindsPanel.panel.chatMode.on)
keyEditWindow = g_ui.displayUI("styles/controls/key_edit")
keyEditWindow:hide()
presetWindow = g_ui.displayUI("styles/controls/preset")
presetWindow:hide()
panels.keybindsPanel.presets.add.onClick = addNewPreset
panels.keybindsPanel.presets.copy.onClick = copyPreset
panels.keybindsPanel.presets.rename.onClick = renamePreset
panels.keybindsPanel.presets.remove.onClick = removePreset
panels.keybindsPanel.buttons.newAction:disable()
panels.keybindsPanel.buttons.newAction.onClick = newHotkeyAction
panels.keybindsPanel.buttons.reset.onClick = resetActions
panels.keybindsPanel.search.field.onTextChange = searchActions
panels.keybindsPanel.search.clear.onClick = function() panels.keybindsPanel.search.field:clearText() end
presetWindow.onEnter = okPresetWindow
presetWindow.onEscape = cancelPresetWindow
presetWindow.buttons.ok.onClick = okPresetWindow
presetWindow.buttons.cancel.onClick = cancelPresetWindow
if g_platform.isMobile() then
panels.keybindsPanel.tablePanel:hide()
end
end
function terminate_binds()
if presetWindow then
presetWindow:destroy()
presetWindow = nil
end
if chatModeGroup then
chatModeGroup:destroy()
chatModeGroup = nil
end
if keyEditWindow then
if keyEditWindow:isVisible() then
keyEditWindow:ungrabKeyboard()
disconnect(keyEditWindow, { onKeyDown = editKeybindKeyDown })
end
keyEditWindow:destroy()
keyEditWindow = nil
end
actionSearchEvent = nil
end
function listKeybindsComboBox(value)
local widget = panels.keybindsPanel.presets.list
presetOption(widget, 'currentPreset', value, false)
changedKeybinds = {}
changedHotkeys = {}
applyChangedOptions()
updateKeybinds()
end
function debug()
local currentOptionText = Keybind.currentPreset
local chatMode = Keybind.chatMode
local chatModeText = (chatMode == 1) and "Chat mode ON" or (chatMode == 2) and "Chat mode OFF" or "Unknown chat mode"
print(string.format("The current configuration is: %s, and the mode is: %s", currentOptionText, chatModeText))
end