mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-24 22:26:37 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			229 lines
		
	
	
	
		
			7.8 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			229 lines
		
	
	
	
		
			7.8 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
 | |
| 
 | |
| 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,
 | |
|     }
 | |
| }
 |