You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/files/data/scripts/omw/input/actionbindings.lua

256 lines
7.9 KiB
Lua

local core = require('openmw.core')
local input = require('openmw.input')
local util = require('openmw.util')
local async = require('openmw.async')
local storage = require('openmw.storage')
local ui = require('openmw.ui')
local I = require('openmw.interfaces')
local actionPressHandlers = {}
local function onActionPress(id, handler)
actionPressHandlers[id] = actionPressHandlers[id] or {}
table.insert(actionPressHandlers[id], handler)
end
local function bindHold(key, actionId)
input.bindAction(key, async:callback(function()
return input.isActionPressed(actionId)
end), {})
end
local function bindMovement(key, actionId, axisId, direction)
input.bindAction(key, async:callback(function()
local actionActive = input.isActionPressed(actionId)
local axisActive = input.getAxisValue(axisId) * direction > 0
return (actionActive or axisActive) and 1 or 0
end), {})
end
local function bindTrigger(key, actionid)
onActionPress(actionid, function()
input.activateTrigger(key)
end)
end
bindTrigger('AlwaysRun', input.ACTION.AlwaysRun)
bindTrigger('ToggleSneak', input.ACTION.Sneak)
bindTrigger('ToggleWeapon', input.ACTION.ToggleWeapon)
bindTrigger('ToggleSpell', input.ACTION.ToggleSpell)
bindTrigger('Jump', input.ACTION.Jump)
bindTrigger('AutoMove', input.ACTION.AutoMove)
bindTrigger('Inventory', input.ACTION.Inventory)
bindTrigger('Journal', input.ACTION.Journal)
bindTrigger('QuickKeysMenu', input.ACTION.QuickKeysMenu)
bindHold('TogglePOV', input.ACTION.TogglePOV)
bindHold('Sneak', input.ACTION.Sneak)
bindHold('Run', input.ACTION.Run)
input.bindAction('Run', async:callback(function(_, value)
local controllerInput = util.vector2(
input.getAxisValue(input.CONTROLLER_AXIS.MoveForwardBackward),
input.getAxisValue(input.CONTROLLER_AXIS.MoveLeftRight)
):length2()
return value or controllerInput > 0.25
end), {})
input.bindAction('Use', async:callback(function()
-- The value "0.6" shouldn't exceed the triggering threshold in BindingsManager::actionValueChanged.
-- TODO: Move more logic from BindingsManager to Lua and consider to make this threshold configurable.
return input.isActionPressed(input.ACTION.Use) or input.getAxisValue(input.CONTROLLER_AXIS.TriggerRight) >= 0.6
end), {})
bindMovement('MoveBackward', input.ACTION.MoveBackward, input.CONTROLLER_AXIS.MoveForwardBackward, 1)
bindMovement('MoveForward', input.ACTION.MoveForward, input.CONTROLLER_AXIS.MoveForwardBackward, -1)
bindMovement('MoveRight', input.ACTION.MoveRight, input.CONTROLLER_AXIS.MoveLeftRight, 1)
bindMovement('MoveLeft', input.ACTION.MoveLeft, input.CONTROLLER_AXIS.MoveLeftRight, -1)
do
local zoomInOut = 0
onActionPress(input.ACTION.ZoomIn, function()
zoomInOut = zoomInOut + 1
end)
onActionPress(input.ACTION.ZoomOut, function()
zoomInOut = zoomInOut - 1
end)
input.bindAction('Zoom3rdPerson', async:callback(function(dt, _, togglePOV)
local Zoom3rdPerson = zoomInOut * 10
if togglePOV then
local triggerLeft = input.getAxisValue(input.CONTROLLER_AXIS.TriggerLeft)
local triggerRight = input.getAxisValue(input.CONTROLLER_AXIS.TriggerRight)
local controllerZoom = (triggerRight - triggerLeft) * 100 * dt
Zoom3rdPerson = Zoom3rdPerson + controllerZoom
end
zoomInOut = 0
return Zoom3rdPerson
end), { 'TogglePOV' })
end
local bindingSection = storage.playerSection('OMWInputBindings')
local keyboardPresses = {}
local keybordHolds = {}
local boundActions = {}
local function bindAction(action)
if boundActions[action] then return end
boundActions[action] = true
input.bindAction(action, async:callback(function()
if keybordHolds[action] then
for _, binding in pairs(keybordHolds[action]) do
if input.isKeyPressed(binding.code) then return true end
end
end
return false
end), {})
end
local function registerBinding(binding, id)
if not input.actions[binding.key] and not input.triggers[binding.key] then
print(string.format('Skipping binding for unknown action or trigger: "%s"', binding.key))
return
end
if binding.type == 'keyboardPress' then
local bindings = keyboardPresses[binding.code] or {}
bindings[id] = binding
keyboardPresses[binding.code] = bindings
elseif binding.type == 'keyboardHold' then
local bindings = keybordHolds[binding.key] or {}
bindings[id] = binding
keybordHolds[binding.key] = bindings
bindAction(binding.key)
else
error('Unknown binding type "' .. binding.type .. '"')
end
end
function clearBinding(id)
for _, boundTriggers in pairs(keyboardPresses) do
boundTriggers[id] = nil
end
for _, boundKeys in pairs(keybordHolds) do
boundKeys[id] = nil
end
end
local function updateBinding(id, binding)
bindingSection:set(id, binding)
clearBinding(id)
if binding ~= nil then
registerBinding(binding, id)
end
return id
end
local interfaceL10n = core.l10n('interface')
I.Settings.registerRenderer('inputBinding', function(id, set, arg)
if type(id) ~= 'string' then error('inputBinding: must have a string default value') end
if not arg.type then error('inputBinding: type argument is required') end
if not arg.key then error('inputBinding: key argument is required') end
local info = input.actions[arg.key] or input.triggers[arg.key]
if not info then return {} end
local l10n = core.l10n(info.key)
local name = {
template = I.MWUI.templates.textNormal,
props = {
text = l10n(info.name),
},
}
local description = {
template = I.MWUI.templates.textNormal,
props = {
text = l10n(info.description),
},
}
local binding = bindingSection:get(id)
local label = binding and input.getKeyName(binding.code) or interfaceL10n('None')
local recorder = {
template = I.MWUI.templates.textEditLine,
props = {
readOnly = true,
text = label,
},
events = {
focusGain = async:callback(function()
if binding == nil then return end
updateBinding(id, nil)
set(id)
end),
keyPress = async:callback(function(key)
if binding ~= nil or key.code == input.KEY.Escape then return end
local newBinding = {
code = key.code,
type = arg.type,
key = arg.key,
}
updateBinding(id, newBinding)
set(id)
end),
},
}
local row = {
type = ui.TYPE.Flex,
props = {
horizontal = true,
},
content = ui.content {
name,
{ props = { size = util.vector2(10, 0) } },
recorder,
},
}
local column = {
type = ui.TYPE.Flex,
content = ui.content {
row,
description,
},
}
return column
end)
local initiated = false
local function init()
for id, binding in pairs(bindingSection:asTable()) do
registerBinding(binding, id)
end
end
return {
engineHandlers = {
onFrame = function()
if not initiated then
initiated = true
init()
end
end,
onInputAction = function(id)
if not actionPressHandlers[id] then
return
end
for _, handler in ipairs(actionPressHandlers[id]) do
handler()
end
end,
onKeyPress = function(e)
local bindings = keyboardPresses[e.code]
if bindings then
for _, binding in pairs(bindings) do
input.activateTrigger(binding.key)
end
end
end,
}
}