local StickConfigScene = SCENE:extend() StickConfigScene.title = "Controller Config" local buttonList1, buttonList2 = {}, {} local configurable_inputs = { "menu_decide", "menu_back", "left", "right", "up", "down", "rotate_left", "rotate_left2", "rotate_right", "rotate_right2", } local input_names = { menu_decide='Confirm Selection', menu_back = 'Go Back', left='Left', right='Right', up='Up', down='Down', rotate_left='Rotate Counter-clockwise', rotate_left2='Rotate Counter-clockwise (2)', rotate_right='Rotate Clockwise', rotate_right2='Rotate Clockwise (2)' } local function newSetInputs() local set_inputs = {} for i, input in ipairs(configurable_inputs) do set_inputs[input] = false end return set_inputs end function StickConfigScene:new() self.input_state = 1 self.set_inputs = newSetInputs() self.new_input = {} self.axis_timer = 0 BUTTON.reset(buttonList1, buttonList2) buttonList1 = { -- Configuring BUTTON.new{ text = CHAR.icon.fastForward.." SKIP", x = 40, y = 300, w = 100, h = 30, codeWhenReleased = function() self:onInputPress{type = "key", scancode = "tab"} end }, BUTTON.new{ text = CHAR.icon.cross_thick.." Cancel", x = 150, y = 300, w = 100, h = 30, codeWhenReleased = function() self:onInputPress{type = "key", scancode = "escape"} end }, } buttonList2 = { -- Confirming BUTTON.new{ text = CHAR.icon.checkMark.." CONFIRM", x = 40, y = 300, w = 100, h = 30, codeWhenReleased = function() self:onInputPress{type = "key", scancode = "return"} end }, BUTTON.new{ text = CHAR.icon.retry_spin.." Restart", x = 150, y = 300, w = 100, h = 30, codeWhenReleased = function() self:onInputPress{type = "key", scancode = "delete"} end }, BUTTON.new{ text = CHAR.icon.cross_thick.." Cancel", x = 260, y = 300, w = 100, h = 30, codeWhenReleased = function() self:onInputPress{type = "key", scancode = "escape"} end } } end function StickConfigScene:update() end function StickConfigScene:render() MainBackground() BUTTON.draw(self.input_state > #configurable_inputs and buttonList2 or buttonList1) for i, input in ipairs(configurable_inputs) do drawText(input_names[input], 40, 60 + i * 20, 200, "left") if self.set_inputs[input] then drawText(self.set_inputs[input], 240, 60 + i * 20, 300, "left") end end if self.input_state > #configurable_inputs then drawText("Press enter/Confirm Selection to confirm, delete/backspace to retry" .. (SETTINGS.input.joysticks and ", esc/Go Back to cancel" or ""), 0, 0, 1000) else drawText("Press joystick input for " .. input_names[configurable_inputs[self.input_state]] .. ", tab to skip, escape to cancel", 0, 0, 1000) end self.axis_timer = self.axis_timer + 1 end local function addJoystick(input, name) if not input[name] then input[name] = {} end end ---@param e SCENE_onInput function StickConfigScene:onInputPress(e) if e.type == "mouse" or e.type == "touch" then BUTTON.press(self.input_state > #configurable_inputs and buttonList2 or buttonList1, e.x, e.y, e.id) elseif e.type == "key" then -- function keys, escape, and tab are reserved and can't be remapped if e.scancode == "escape" or (self.input_state > #configurable_inputs and e.input == "menu_back") then SCENE = InputConfigScene(SETTINGS.firstTime) elseif self.input_state > #configurable_inputs then if e.scancode == "return" or e.input == "menu_decide" then SETTINGS.input.keys = self.new_input SCENE = SETTINGS.firstTime and TitleScene() or InputConfigScene() SETTINGS.firstTime = false elseif e.scancode == "delete" or e.scancode == "backspace" then self:new() -- retry end else -- Other keys - skip self.set_inputs[configurable_inputs[self.input_state]] = "skipped" self.input_state = self.input_state + 1 end elseif string.sub(e.type, 1, 3) == "joy" then if self.input_state <= #configurable_inputs then if e.type == "joybutton" then addJoystick(self.new_input, e.name) if not self.new_input[e.name].buttons then self.new_input[e.name].buttons = {} end if self.new_input[e.name].buttons[e.button] then return end self.set_inputs[configurable_inputs[self.input_state]] = "jbtn " .. e.button .. " " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") self.new_input[e.name].buttons[e.button] = configurable_inputs[self.input_state] self.input_state = self.input_state + 1 elseif e.type == "joyaxis" then if (e.axis ~= self.last_axis or self.axis_timer > 30) and math.abs(e.value) >= 1 then addJoystick(self.new_input, e.name) if not self.new_input[e.name].axes then self.new_input[e.name].axes = {} end if not self.new_input[e.name].axes[e.axis] then self.new_input[e.name].axes[e.axis] = {} end if ( self.new_input[e.name].axes[e.axis][e.value >= 1 and "positive" or "negative"] ) then return end self.set_inputs[configurable_inputs[self.input_state]] = "jaxis " .. (e.value >= 1 and "+" or "-") .. e.axis .. " " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") self.new_input[e.name].axes[e.axis][e.value >= 1 and "positive" or "negative"] = configurable_inputs[self.input_state] self.input_state = self.input_state + 1 self.last_axis = e.axis self.axis_timer = 0 end elseif e.type == "joyhat" then if e.direction ~= "c" then addJoystick(self.new_input, e.name) if not self.new_input[e.name].hats then self.new_input[e.name].hats = {} end if not self.new_input[e.name].hats[e.hat] then self.new_input[e.name].hats[e.hat] = {} end if self.new_input[e.name].hats[e.hat][e.direction] then return end self.set_inputs[configurable_inputs[self.input_state]] = "jhat " .. e.hat .. " " .. e.direction .. " " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") self.new_input[e.name].hats[e.hat][e.direction] = configurable_inputs[self.input_state] self.input_state = self.input_state + 1 end end end end end function StickConfigScene:onInputRelease(e) if e.type == "mouse" or e.type == "touch" then BUTTON.release(self.input_state > #configurable_inputs and buttonList2 or buttonList1, e.x, e.y, e.id) end end function StickConfigScene:onInputMove(e) if e.type == "mouse" then BUTTON.checkHovering(self.input_state > #configurable_inputs and buttonList2 or buttonList1, e.x, e.y) end end return StickConfigScene