mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-27 06:26:37 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			191 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			191 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| local core = require('openmw.core')
 | |
| local input = require('openmw.input')
 | |
| local storage = require('openmw.storage')
 | |
| local ui = require('openmw.ui')
 | |
| local util = require('openmw.util')
 | |
| local async = require('openmw.async')
 | |
| local I = require('openmw.interfaces')
 | |
| 
 | |
| local settingsGroup = 'SettingsOMWControls'
 | |
| 
 | |
| local function boolSetting(key, default)
 | |
|     return {
 | |
|         key = key,
 | |
|         renderer = 'checkbox',
 | |
|         name = key,
 | |
|         description = key .. 'Description',
 | |
|         default = default,
 | |
|     }
 | |
| end
 | |
| 
 | |
| I.Settings.registerPage({
 | |
|     key = 'OMWControls',
 | |
|     l10n = 'OMWControls',
 | |
|     name = 'ControlsPage',
 | |
|     description = 'ControlsPageDescription',
 | |
| })
 | |
| 
 | |
| I.Settings.registerGroup({
 | |
|     key = settingsGroup,
 | |
|     page = 'OMWControls',
 | |
|     l10n = 'OMWControls',
 | |
|     name = 'MovementSettings',
 | |
|     permanentStorage = true,
 | |
|     settings = {
 | |
|         boolSetting('alwaysRun', false),
 | |
|         boolSetting('toggleSneak', false), -- TODO: consider removing this setting when we have the advanced binding UI
 | |
|         boolSetting('smoothControllerMovement', true),
 | |
|     },
 | |
| })
 | |
| 
 | |
| local interfaceL10n = core.l10n('interface')
 | |
| 
 | |
| local bindingSection = storage.playerSection('OMWInputBindings')
 | |
| 
 | |
| local recording = nil
 | |
| 
 | |
| local mouseButtonNames = {
 | |
|     [1] = 'Left',
 | |
|     [2] = 'Middle',
 | |
|     [3] = 'Right',
 | |
|     [4] = '4',
 | |
|     [5] = '5',
 | |
| }
 | |
| 
 | |
| -- TODO: support different controllers, use icons to render controller buttons
 | |
| local controllerButtonNames = {
 | |
|     [-1] = 'Invalid',
 | |
|     [input.CONTROLLER_BUTTON.A] = "A",
 | |
|     [input.CONTROLLER_BUTTON.B] = "B",
 | |
|     [input.CONTROLLER_BUTTON.X] = "X",
 | |
|     [input.CONTROLLER_BUTTON.Y] = "Y",
 | |
|     [input.CONTROLLER_BUTTON.Back] = "Back",
 | |
|     [input.CONTROLLER_BUTTON.Guide] = "Guide",
 | |
|     [input.CONTROLLER_BUTTON.Start] = "Start",
 | |
|     [input.CONTROLLER_BUTTON.LeftStick] = "Left Stick",
 | |
|     [input.CONTROLLER_BUTTON.RightStick] = "Right Stick",
 | |
|     [input.CONTROLLER_BUTTON.LeftShoulder] = "LB",
 | |
|     [input.CONTROLLER_BUTTON.RightShoulder] = "RB",
 | |
|     [input.CONTROLLER_BUTTON.DPadUp] = "D-pad Up",
 | |
|     [input.CONTROLLER_BUTTON.DPadDown] = "D-pad Down",
 | |
|     [input.CONTROLLER_BUTTON.DPadLeft] = "D-pad Left",
 | |
|     [input.CONTROLLER_BUTTON.DPadRight] = "D-pad Right",
 | |
| }
 | |
| 
 | |
| local function bindingLabel(recording, binding)
 | |
|     if recording then
 | |
|         return interfaceL10n('N/A')
 | |
|     elseif not binding or not binding.button then
 | |
|         return interfaceL10n('None')
 | |
|     elseif binding.device == 'keyboard' then
 | |
|         return input.getKeyName(binding.button)
 | |
|     elseif binding.device == 'mouse' then
 | |
|         return string.format('Mouse %s', mouseButtonNames[binding.button] or 'Unknown')
 | |
|     elseif binding.device == 'controller' then
 | |
|         return string.format('Controller %s', controllerButtonNames[binding.button] or 'Unknown')
 | |
|     else
 | |
|         return 'Unknown'
 | |
|     end
 | |
| end
 | |
| 
 | |
| local inputTypes = {
 | |
|     action = input.actions,
 | |
|     trigger = input.triggers,
 | |
| }
 | |
| 
 | |
| 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 then error('inputBinding: argument with "key" and "type" is required') end
 | |
|     if not arg.type then error('inputBinding: type argument is required') end
 | |
|     if not inputTypes[arg.type] then error('inputBinding: type must be "action" or "trigger"') end
 | |
|     if not arg.key then error('inputBinding: key argument is required') end
 | |
|     local info = inputTypes[arg.type][arg.key]
 | |
|     if not info then print(string.format('inputBinding: %s %s not found', arg.type, arg.key)) 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 = bindingLabel(recording and recording.id == id, binding)
 | |
| 
 | |
|     local recorder = {
 | |
|         template = I.MWUI.templates.textNormal,
 | |
|         props = {
 | |
|             text = label,
 | |
|         },
 | |
|         events = {
 | |
|             mouseClick = async:callback(function()
 | |
|                 if recording ~= nil then return end
 | |
|                 if binding ~= nil then bindingSection:set(id, nil) end
 | |
|                 recording = {
 | |
|                     id = id,
 | |
|                     arg = arg,
 | |
|                     refresh = function() set(id) end,
 | |
|                 }
 | |
|                 recording.refresh()
 | |
|             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 function bindButton(device, button)
 | |
|     if recording == nil then return end
 | |
|     local binding = {
 | |
|         device = device,
 | |
|         button = button,
 | |
|         type = recording.arg.type,
 | |
|         key = recording.arg.key,
 | |
|     }
 | |
|     bindingSection:set(recording.id, binding)
 | |
|     local refresh = recording.refresh
 | |
|     recording = nil
 | |
|     refresh()
 | |
| end
 | |
| 
 | |
| return {
 | |
|     engineHandlers = {
 | |
|         onKeyPress = function(key)
 | |
|             bindButton(key.code ~= input.KEY.Escape and 'keyboard' or nil, key.code)
 | |
|         end,
 | |
|         onMouseButtonPress = function(button)
 | |
|             bindButton('mouse', button)
 | |
|         end,
 | |
|         onControllerButtonPress = function(id)
 | |
|             bindButton('controller', id)
 | |
|         end,
 | |
|     }
 | |
| }
 |