Gamepad input still makes UIPageLayout change frames when selected button is moved off-screen/destroy despite GamepadInput being disabled?

So for context, our game’s main UI is in a UIPageLayout. We have a top bar that users can tap/click/use controller input to switch. Tap and clicking the button works as expected, the gamepad can select buttons or use L1 or R1 to proceed to the previous and next page respectively.

For some reason, when a new UI appears on screen, the controller input freaks out and puts me on a random page, I’m not pressing L1 or R1, Gamepad, Touch, and ScrollWheelInput are all false so it shouldn’t be scrolling, right? Does anyone have any ideas why this is happening and/or how to fix?

As you can see in this video, I bought a crate and it freaked out and put me on the Equip page. Then, when I pressed claim, it put me on the teleports page? You can tell I don’t intend to do this as the highlight thing at the top doesn’t move.

Binds are created in the InputManager module which is basically a UserInput/ContextActionService wrapper that ensures inputs are valid and whatnot. I’m just completely lost. I’ve added a print inside of the function that switches which page the user is on and nothing.

Relevant parts from the TopBarSwitcher script:

function module:Focus(nameToFocus: string)
	if nameToFocus == self.SelectedName then
		return
	end
	print('switching page') -- only prints when I expect it to again
	local frameInfo = assert(self._buttons[nameToFocus])
	self.SelectedName = nameToFocus
	self.SelectionChanged:Fire(nameToFocus)
	dropdownMenu.CollapseEvent:Fire();
	(self._uiPageLayout :: UIPageLayout):JumpTo(frameInfo.Frame)
	tweenService:Create(
		self._highlight, 
		TweenInfo.new(self._uiPageLayout.TweenTime, self._uiPageLayout.EasingStyle, self._uiPageLayout.EasingDirection), 
		getHighlightPositionAndSize(frameInfo.Button)
	):Play()
end

function module:CreateBinds()
	self = self :: TopBarSwitcher
	framework.inputManager:BindAction('TopBarSwitcherKeybind', function(name, state, inputObject)
		if state ~= Enum.UserInputState.Begin then
			return
		end
		print('switching?') -- prints only when I expect it to
		if inputObject.KeyCode == Enum.KeyCode.ButtonL1 then
			self._uiPageLayout:Previous()
			self:Focus(self._uiPageLayout.CurrentPage.Name)
		elseif inputObject.KeyCode == Enum.KeyCode.ButtonR1 then
			self._uiPageLayout:Next()
			self:Focus(self._uiPageLayout.CurrentPage.Name)
		end
		return Enum.ContextActionResult.Sink
	end, { Enum.KeyCode.ButtonL1, Enum.KeyCode.ButtonR1 })
end

To create a crate spinner UI:

function module:CreateCrateSpinner(crateInfo: { CrateGUID: string; ActualObject: string; Coins: number?; DecoyObjects: {string}; Dupe: boolean? }, crateType: string, backgroundColour: Color3)
	print(crateInfo)
	local newCrate = openingCrate:Clone()
	local itemsContainer = newCrate:WaitForChild('Items')
	local clipBounds = itemsContainer:WaitForChild('ScrollingFrame'):WaitForChild('ClipBounds')
	local uiPageLayout = clipBounds:WaitForChild('UIPageLayout')
	local realItemData = framework.itemData.Halos[crateInfo.ActualObject] or framework.itemData.Trails[crateInfo.ActualObject] or framework.itemData['Particle Effects'][crateInfo.ActualObject]

	local newLabel = createItemLabel(realItemData) -- function that creates a frame for the cosmetic that should be shown in the spinner
	newLabel.LayoutOrder = 20

	for i = 19, 1, -1 do -- ^same as above but for the decoy objects
		local thisDecoy = crateInfo.DecoyObjects[i]
		local foundItemData = framework.itemData.Halos[thisDecoy] or framework.itemData.Trails[thisDecoy] or framework.itemData['Particle Effects'][thisDecoy]
		local itemLabel = createItemLabel(foundItemData)
		itemLabel.LayoutOrder = i
		itemLabel.Parent = clipBounds
	end

	newLabel.Parent = clipBounds
	newCrate.Parent = framework.MainUI

	local button = uiController:GetUIModule('ButtonGeneric').new(newCrate:WaitForChild('Spin')) -- create a button controller for the spin button
	
	local colour = framework.shopInfo.RarityColours[crateType] -- get colours and whatnot for theming
	
	newCrate:WaitForChild('Background').BackgroundColor3 = backgroundColour
	newCrate:WaitForChild('Sides').BackgroundColor3 = backgroundColour
	newCrate.BackgroundColor3 = backgroundColour
	
	newCrate:WaitForChild('UIStroke').Color = colour
	
	newCrate:WaitForChild('TitleContainer'):WaitForChild('TitleMain').Text = CRATE_TITLE:format(colour:ToHex(), crateType)
	
	tweenService:Create(newCrate, TweenInfo.new(1, Enum.EasingStyle.Bounce, Enum.EasingDirection.Out), {Position = UDim2.fromScale(.5, .5)}):Play() -- part where the frame should go on-screen
	task.wait(0.5)

	fadeIn(button) -- fade in the spin button
	button.MouseButton1Click:Wait() -- in the button controller, a custom click event is created so I can control when the input should be created
	fadeOut(button) -- fade out the fade in button
	task.delay(0.5, button.Destroy, button)

	tweenService:Create(clipBounds, TweenInfo.new(1), {AnchorPoint = Vector2.new(random:NextNumber(0.05, 0.95), 0.5)}):Play() -- to simulate a random offset
	uiPageLayout:JumpToIndex(99) -- finally, spin

	local titleContainer = newCrate:WaitForChild('TitleContainer')

	local now = tick()

    -- irrelevant part omitted 

	task.wait(10)
	local youGotLabel = itemsContainer:WaitForChild('YouGot')
	youGotLabel.Text = formatYouGot(realItemData, crateInfo.Dupe) -- set the text
	tweenService:Create(youGotLabel, TweenInfo.new(0.5), {TextTransparency = 0}):Play()
	
	local okayButton: types.ButtonGeneric, equipButton: types.ButtonGeneric = 
		uiController:GetUIModule('ButtonGeneric').new(newCrate:WaitForChild('Okay')), 
		uiController:GetUIModule('ButtonGeneric').new(newCrate:WaitForChild('EquipNow'))
	
	if crateInfo.Dupe then
		okayButton._frameRef.Position = UDim2.fromScale(0.5, 0.9)
		equipButton._frameRef.Visible = false
	end
	
	fadeIn(okayButton)
	fadeIn(equipButton)
	
	local yieldSignal = framework.signal.new() -- wait until one of the buttons has been clicked
	
	local okConnection = okayButton.MouseButton1Click:Connect(function()
		yieldSignal:Fire()
	end)
	
	local equipConnection = equipButton.MouseButton1Click:Connect(function()
		yieldSignal:Fire()
		framework.net:Fire('EquipCosmetic', { ToEquip = true; Name = crateInfo.ActualObject})
	end)
	
	yieldSignal:Wait()
	framework.net:Fire('CrateFireServer', { GUID = crateInfo.CrateGUID }) -- to stop waiting for the client to spin the crate
	
	tweenService:Create(newCrate, TweenInfo.new(1, Enum.EasingStyle.Back), { Position = UDim2.fromScale(0.5, -0.5) }):Play() -- move crate off-screen and destroy crate frame
	task.delay(1, newCrate.Destroy, newCrate)
end

Does anyone have any ideas?

1 Like

Bumping, I’m still stumped on how to go about fixing.

I suppose I could just disable all the buttons that shouldn’t be selectable with a loop, however this seems very hacky.

Did you ever find a fix for this? Did you end up just using a loop to disable all buttons not visible?

Sorry for late response, I meant to reply giving an update but only remembered just now.

Looking back I think it might have been because I forgot to turn on ClipsDescendants for one of the frames, but I really can’t remember for certain as this was 4ish months ago, sorry.

I’m not too sure if it still is even happening but I wasn’t able to reproduce trying just now. I really don’t know why it would have still switched to another page when all inputs are disabled. Wish I had more information to give, sorry.

1 Like

Wow, yeah, I just forgot to turn on ClipDescendants. It’s a full-screen frame so I didn’t even notice. :sweat_smile: Thanks for the reply!

1 Like