mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-06 00:55:50 +00:00
262 lines
9.0 KiB
Lua
262 lines
9.0 KiB
Lua
local input = require('openmw.input')
|
|
local util = require('openmw.util')
|
|
local async = require('openmw.async')
|
|
local storage = require('openmw.storage')
|
|
|
|
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
|
|
|
|
do -- Actions and Triggers currently unused by builtin scripts
|
|
-- TODO: as more mechanics are dehardcoded, move these declarations to relevant files
|
|
local triggers = {
|
|
Activate = input.ACTION.Activate,
|
|
Console = input.ACTION.Console,
|
|
CycleSpellLeft = input.ACTION.CycleSpellLeft,
|
|
CycleSpellRight = input.ACTION.CycleSpellRight,
|
|
CycleWeaponLeft = input.ACTION.CycleWeaponLeft,
|
|
CycleWeaponRight = input.ACTION.CycleWeaponRight,
|
|
GameMenu = input.ACTION.GameMenu,
|
|
QuickLoad = input.ACTION.QuickLoad,
|
|
QuickSave = input.ACTION.QuickSave,
|
|
Screenshot = input.ACTION.Screenshot,
|
|
ToggleDebug = input.ACTION.ToggleDebug,
|
|
ToggleHUD = input.ACTION.ToggleHUD,
|
|
TogglePostProcessorHUD = input.ACTION.ToggleHUD,
|
|
}
|
|
for i = 1, 9 do
|
|
local key = string.format('QuickKey%s', i)
|
|
triggers[key] = input.ACTION[key]
|
|
end
|
|
for key, action in pairs(triggers) do
|
|
input.registerTrigger {
|
|
key = key,
|
|
l10n = 'OMWControls',
|
|
name = key .. '_name',
|
|
description = key .. '_description',
|
|
}
|
|
bindTrigger(key, action)
|
|
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 devices = {
|
|
keyboard = true,
|
|
mouse = true,
|
|
controller = true
|
|
}
|
|
|
|
local function invalidBinding(binding)
|
|
if not binding.key then
|
|
return 'has no key'
|
|
elseif binding.type ~= 'action' and binding.type ~= 'trigger' then
|
|
return string.format('has invalid type', binding.type)
|
|
elseif binding.type == 'action' and not input.actions[binding.key] then
|
|
return string.format("action %s doesn't exist", binding.key)
|
|
elseif binding.type == 'trigger' and not input.triggers[binding.key] then
|
|
return string.format("trigger %s doesn't exist", binding.key)
|
|
elseif not binding.device or not devices[binding.device] then
|
|
return string.format("invalid device %s", binding.device)
|
|
elseif not binding.button then
|
|
return 'has no button'
|
|
end
|
|
end
|
|
|
|
local boundActions = {}
|
|
local actionBindings = {}
|
|
|
|
local function bindAction(binding, id)
|
|
local action = binding.key
|
|
actionBindings[action] = actionBindings[action] or {}
|
|
actionBindings[action][id] = binding
|
|
if not boundActions[action] then
|
|
boundActions[binding.key] = true
|
|
input.bindAction(action, async:callback(function()
|
|
for _, binding in pairs(actionBindings[action] or {}) do
|
|
if binding.device == 'keyboard' then
|
|
if input.isKeyPressed(binding.button) then
|
|
return true
|
|
end
|
|
elseif binding.device == 'mouse' then
|
|
if input.isMouseButtonPressed(binding.button) then
|
|
return true
|
|
end
|
|
elseif binding.device == 'controller' then
|
|
if input.isControllerButtonPressed(binding.button) then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
return false
|
|
end), {})
|
|
end
|
|
end
|
|
|
|
local triggerBindings = {}
|
|
for device in pairs(devices) do triggerBindings[device] = {} end
|
|
|
|
local function bindTrigger(binding, id)
|
|
local deviceBindings = triggerBindings[binding.device]
|
|
deviceBindings[binding.button] = deviceBindings[binding.button] or {}
|
|
deviceBindings[binding.button][id] = binding
|
|
end
|
|
|
|
local function registerBinding(binding, id)
|
|
local invalid = invalidBinding(binding)
|
|
if invalid then
|
|
print(string.format('Skipping invalid binding %s: %s', id, invalid))
|
|
elseif binding.type == 'action' then
|
|
bindAction(binding, id)
|
|
elseif binding.type == 'trigger' then
|
|
bindTrigger(binding, id)
|
|
end
|
|
end
|
|
|
|
function clearBinding(id)
|
|
for _, deviceBindings in pairs(triggerBindings) do
|
|
for _, buttonBindings in pairs(deviceBindings) do
|
|
buttonBindings[id] = nil
|
|
end
|
|
end
|
|
|
|
for _, bindings in pairs(actionBindings) do
|
|
bindings[id] = nil
|
|
end
|
|
end
|
|
|
|
bindingSection:subscribe(async:callback(function(_, id)
|
|
if not id then return end
|
|
local binding = bindingSection:get(id)
|
|
clearBinding(id)
|
|
if binding ~= nil then
|
|
registerBinding(binding, id)
|
|
end
|
|
return id
|
|
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 buttonTriggers = triggerBindings.keyboard[e.code]
|
|
if not buttonTriggers then return end
|
|
for _, binding in pairs(buttonTriggers) do
|
|
input.activateTrigger(binding.key)
|
|
end
|
|
end,
|
|
onMouseButtonPress = function(button)
|
|
local buttonTriggers = triggerBindings.mouse[button]
|
|
if not buttonTriggers then return end
|
|
for _, binding in pairs(buttonTriggers) do
|
|
input.activateTrigger(binding.key)
|
|
end
|
|
end,
|
|
onControllerButtonPress = function(id)
|
|
local buttonTriggers = triggerBindings.controller[id]
|
|
if not buttonTriggers then return end
|
|
for _, binding in pairs(buttonTriggers) do
|
|
input.activateTrigger(binding.key)
|
|
end
|
|
end,
|
|
}
|
|
}
|