Add a first class way to sink mouse input in a UI without showing a hover cursor

As a developer it is currently impossible to sink mouse input without showing the “hovering over button” cursor without hacks that are each suboptimal in their own way.

In My Movie, the bulk of our game happens in a full screen UI, the video editor. However any UI behind the video editor (such as in world) is still possible to click. Watch my cursor as it, from my point of view, randomly changes to a hover mouse.

Yikes, that’s the toggle mic button!


Scary thing to click on without knowing!

Today, the only way to sink mouse input is to use a big button (or otherwise Active) element that covers the area. But this replaces the mouse with that same hover icon, making for a very janky experience as it becomes harder for a user to know what is actually interactive. Furthermore, active elements explicitly override any custom mouse icon you set, so you cannot even easily work around this.

Bad Solutions

  1. Turn the mouse icon off, and render an ImageLabel where it’s supposed to be

This means I have to track whether or not we’re hovering over something active on my own, but it also means it will never overlap any core UI, such as the top bar. It also means I have to recreate any other contextual events, such as hovering over a TextBox changing to the I-bar cursor.

  1. Don’t use buttons anywhere and only use UserInputService

This is not only a nightmare to work with, but also it doesn’t help when Roblox adds their own world buttons, in this case the toggle voice button.


The way I deal with this is:

  1. Create a ScrollingFrame that covers the entire background:
    Active = false
    BackgroundTransparency = 1
    CanvasSize = [0, 0, 0, 0]
    ElasticBehavior = Never
    ScrollBarThickness = 0
    ScrollingEnabled = true
    Selectable = false

  2. And a TextButton inside the ScrollingFrame:
    Active = false
    BackgroundTransparency = 1
    Size = [1, 0, 1, 0]
    Text = (empty string)
    Selectable = false

The TextButton with Active = false will sink input without constantly showing the hover cursor.

GuiButtons can override the Active property, so in this case the Active property pretty much only determines if the hover cursor should appear or not.

The TextButton and ScrollingFrame both work together to prevent camera movement.

The ScrollingFrame prevents zooming+panning the camera with a touch screen (mostly), and also prevents zooming with a mouse wheel.

Meanwhile, the TextButton prevents panning the camera with right-click. It doesn’t do anything on a touch screen, which is why you need the ScrollingFrame.

Yes, this is a hack, but it’s the best way I know of doing it without making anything too complicated.

Unfortunately this does not prevent clicking the mic button. You can still click the mic button over any other GUI that sinks input, probably because the CoreGui always renders over the PlayerGui.

1 Like