More options for sinking input on GuiObjects

To sink input on a GuiObject we can set its Active property. This will cause the GuiObject to sink all input that it receives (except other GuiObjects in the same 2D screen which will still receive the input for some reason). TextButtons, ImageButtons, and ScrollingFrames will also sink some input even when not Active.

However, there are times when I want to selectively sink specific inputs, and the engine has no capability to do that (in a robust way).

An example use case is allowing players on desktop to rotate their camera (right click) while their mouse is hovering over a SurfaceGui with some clickable GuiObject (left click).

If the GuiObject sinks the right click input then the player will be unable to rotate their camera and will need to manually readjust themselves by moving their cursor, moving their character or zooming the camera.

If the GuiObject does not sink input then objects underneath the clickable GuiObject will receive the click and hover inputs (in some cases that can be fixed easily, in other cases it could involve a lot of work reimplementing features of the engine or doing a complete restructure of the UI part of the codebase).

Here are two typical hacky solutions (both using non-button GuiObjects with Active = false):

  • Manually code the relevant input detection logic from the ground up

  • Rely on GuiObject.InputBegan executing before ContextActionService callbacks, and in the GuiObject.InputBegan callback set a flag which the ContextActionService callback for the same input running later will consume and sink the input.

    • But this will only sink the input for subsequent ContextActionService and UserInputService callbacks, so anything before that first ContextActionService callback will still receive the original input as if it weren’t sunk (in particular, other GuiObjects will still see the input, and we can’t control the order they execute).
    • And, this only works on SurfaceGuis that have AlwaysOnTop = true. If AlwaysOnTop = false then the GuiObject’s input callbacks will run after ContextActionService callbacks.

Ideally I’d like to see GUI related input processing become as flexible as ContextActionService so that we don’t need to go to these lengths.