Hook mobile thumbstick input to UserInputService events

As a Roblox developer, it is currently too hard to listen to mobile thumbstick input as there is no event for it.

If Roblox is able to address this issue, it would improve my development experience because I currently need to do some ugly workaround to listen to the dynamic thumbstick or build a custom dynamic thumbstick which is quite a lot of work.

In an ideal case the listening to the dynamic thumbstick events should be as listening to the gamepad thumbstick events using UserInputService.InputChanged.

This is the place in the CoreScripts where I would like the event to be emitted: Core-Scripts/DynamicThumbstick.lua at master · Roblox/Core-Scripts · GitHub

4 Likes

Ended up writing a script that emits an when player provides input to Dynamic Thumbstick, not the cleanest code but it does work.

I dumped it in PlayerScripts and the script expects to have an event called “InputChanged”, the Vector2 is scaled from -1 to 1.

local Players = game:GetService("Players")

local playerGUI = Players.LocalPlayer.PlayerGui 

local function hookDynamicThumbstick(gui)
    local touchControlFrame 		= gui:WaitForChild("TouchControlFrame")
    local dynamicThumbstickFrame 	= touchControlFrame:WaitForChild("DynamicThumbstickFrame")
    local thumbstickStart 			= dynamicThumbstickFrame:WaitForChild("ThumbstickStart")
    local thumbstickEnd 			= dynamicThumbstickFrame:WaitForChild("ThumbstickEnd")
    
    -- Config values pulled from DynamicThumbstick.lua
    -- https://github.com/Roblox/Core-Scripts/blob/master/PlayerScripts/StarterPlayerScripts/ControlScript/MasterControl/DynamicThumbstick.lua#L400
    local ThumbstickSize = 45
    local ThumbstickRingSize = 20
    local MiddleSize = 10
    local MiddleSpacing = MiddleSize + 4
    local RadiusOfDeadZone = 2
    local RadiusOfMaxSpeed = 50

    local screenSize = touchControlFrame.AbsoluteSize
    local isBigScreen = math.min(screenSize.x, screenSize.y) > 500
    if isBigScreen then
        ThumbstickSize = ThumbstickSize * 2
        ThumbstickRingSize = ThumbstickRingSize * 2
        MiddleSize = MiddleSize * 2
        MiddleSpacing = MiddleSpacing * 2
        RadiusOfDeadZone = RadiusOfDeadZone * 2
        RadiusOfMaxSpeed = RadiusOfMaxSpeed * 2
    end
    
    local function reportThumbstickPosition(position)
        script.InputChanged:Fire(position)
    end
    
    thumbstickEnd:GetPropertyChangedSignal("Position"):Connect(function()
        local movementVector = thumbstickStart.AbsolutePosition - thumbstickEnd.AbsolutePosition 
        
        if movementVector.Magnitude < RadiusOfDeadZone then
            reportThumbstickPosition(Vector2.new())
        else
            local scaledMovement = movementVector.Unit * math.min(movementVector.Magnitude, 1)						
            reportThumbstickPosition(Vector2.new(-scaledMovement.X, scaledMovement.Y)) -- Flip X so left is -1 and right 1 to match Xbox
        end
    end)
    
    thumbstickEnd:GetPropertyChangedSignal("ImageTransparency"):Connect(function()
        if thumbstickEnd.ImageTransparency == 1 then
            reportThumbstickPosition(Vector2.new())
        end
    end)
end

if playerGUI:FindFirstChild("TouchGui") then
    hookDynamicThumbstick(playerGUI.TouchGui)
end

playerGUI.ChildAdded:Connect(function(child)
    if child.Name == "TouchGui" then
        hookDynamicThumbstick(child)
    end
end)