Virtual Cursor selection is offset/buggy when selecting buttons inside buttons in UIGridLayout

The Problem:
Virtual Cursor does not cooperate well with buttons inside of buttons.
In the repro I’ve provided, there’s a list of buttons on the left side of the screen controlled by a UIGridLayout. Two of these buttons have an additional ImageButton inside of them. This is selectable just fine on PC and mobile, but Virtual Cursor will skip over them or select the wrong one.

Changing the size of the UI or adding padding makes it slightly better, but does not actually fix it. I’d have to make every single UI element gigantic to get around this.

This issue occurs on all platforms; the only requirement for it to break is to use a controller and enable Virtual Cursor mode.

Video:


Repro File:
repro place.rbxl (68.1 KB)

Expected behavior

I expect Virtual Cursor to select the button highest in the hierarchy closest to the center of the cursor, or in other words, act like a mouse on PC.

2 Likes

Let me offer 2 solutions for you:

  1. Set the screenGui ZindexBehavior to ZIndex seems to fix the problem.

image

While I do agree with you on that I think the way Sibling works will make it hard for the virtual cursor to get around that

This issue isn’t just limited to UI Grid Layout. It seems to essentially be any nested layout recently where a button is within a button, regardless of z-index. And it previously wasn’t as prevalent as it has been the past week.

In our game we’ve had Sibling set for ScreenUI Zindex Behavior for a couple months now with just over 10% of console players from the tens of thousands that play daily (roughly 2K of those console), and they’ve only just started encountering virtual cursor issues with our existing menu on interacting with a UI Layout of image buttons in a frame atop a text button row for a list of items to equip in a scroll-frame. And it’s intermittent on the row and screen location as to whether it works correctly or not at all even though they’re all sized the same.

Mind you, this has worked fine all of October and into November with no menu changes, and now the past week we’re getting mass reports. And of course, it’s not a platform specific issue. It’s simply the console players who are essentially the ones who mostly need to use a controller. But I can easily reproduce this behavior on my laptop or mobile device by connecting my controller.

I think I have a solution at least for my circumstance that may also work for you as well. In my case of having the Scrollframe of TextButton rows with a Frame under each TextButton that has the Image Layout of ImageButtons, I changed the Active property for them all and got a better result.

What I’ve done is in the Activate connection of the selected TextButton row, I have a function that sets the Active property to false for all other TexButton rows. And then I have its MouseLeave connection have a function that makes it so all the other TextButtons can become true for the Active property again. That coupled with the Frame that has the UILayout of ImageButtons being set with its size scale of X and Y to be 1.2 so its slightly larger than the ImageButton row seems to make it so the ImageButtons for the selected TextButton always work now for the Virtual Cursor.

for index1, rowbutton in pairs(ScrollFrame:GetChildren()) do

	-- Make it so only the clicked button is active
	rowbutton.Activated:Connect(function()
		for index2, button in pairs(ScrollFrame:GetChildren()) do
			if button:IsA("TextButton") then
				if button ~= rowbutton then
					button.Active = false
				else
					button.Active = true
				end
			end
		end
	end)

	-- Make it so all other buttons become active in scroll frame
	rowbutton.MouseLeave:Connect(function()
		for index, button in pairs(ScrollFrame:GetChildren()) do
			if button:IsA("TextButton") then
				if button ~= rowbutton then
					button.Active = true
				else
					button.Active = false
				end
			end
		end
	end)

	-- Added protection to ensure we don't leave the previously active button inactive
	rowbutton.MouseEnter:Connect(function()
		for index, button in pairs(ScrollFrame:GetChildren()) do
			if button:IsA("TextButton") then
				button.Active = true
			end
		end
	end)

end

Thanks for the report! We’ll follow up when we have an update for you.