mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 22:26:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			255 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			255 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,
 | |
|     }
 | |
| }
 |