Gamepad APIs: Cross-Platform Button Support

I have implemented the functionality of detecting PlayStation versus Xbox controllers. And, it’s working, to an extent.


Issue 1:
Directional inputs have the same return value. This means, if a player presses a d-pad input, then the code knows it’s a gamepad, but it doesn’t know what type of gamepad. (PlayStation or Xbox? the code is not sure.)


Issue 2:
Can’t have more than one controller plugged in at a time.

Steps:

  1. Play with PS4 remote, move around.
    • The UI updates to show PS4-specific prompts
  2. With PS4 remote still plugged in or connected via Bluetooth, connect an Xbox remote and move around with that.
    • The UI updates to show Xbox-specific prompts
  3. With both remotes connected, switch back to the PS4 remote and move around.
    • You can play the game, but the UI does not update to show PS4-specific prompts. Rather, it thinks the PS4 remote is an Xbox remote as Roblox seems to be relying on the last controller that was connected. (Not the last one to have input.)

This could be an issue with my code, which is below, but I’m not sure.

Anyhow, this means that players, if they want the correct UI prompts to show up, they need to unplug their controller and plug it back in. Or, just only have one remote plugged in at a time.


Code

local userInputService = game:GetService("UserInputService")
local InputTypeChangedRE = game.Workspace.RemoteEventsFolder.Inputs.InputTypeChanged

---

local UserInputTypeSystemModule = {

	gamepadTypeFromNewestInput = "none",
	inputTypeThePlayerIsUsing = "KeyboardAndMouse", --keyboard mouse is default
	gamepadType = "none", -- "none" by default. Can be "Xbox" or "PlayStation"

}

local mouseInputType = {
		Enum.UserInputType.MouseButton1,
		Enum.UserInputType.MouseButton2,
		Enum.UserInputType.MouseButton3,
		Enum.UserInputType.MouseMovement, 
		Enum.UserInputType.MouseWheel	
}

local GamepadInputsList = {
	Enum.KeyCode.ButtonA,
	Enum.KeyCode.ButtonB,
	Enum.KeyCode.ButtonX,
	Enum.KeyCode.ButtonY,

	Enum.KeyCode.ButtonL1,
	Enum.KeyCode.ButtonL2,
	Enum.KeyCode.ButtonL3,

	Enum.KeyCode.ButtonR1,
	Enum.KeyCode.ButtonR2,
	Enum.KeyCode.ButtonR3,

	Enum.KeyCode.ButtonStart,
	Enum.KeyCode.ButtonSelect,
	
	--

	Enum.KeyCode.DPadUp,
	Enum.KeyCode.DPadDown,
	Enum.KeyCode.DPadLeft,
	Enum.KeyCode.DPadRight,
	
	Enum.KeyCode.Thumbstick1,
	Enum.KeyCode.Thumbstick2,


}

local mobileInputType = Enum.UserInputType.Touch

---


local Xbox_ReturnValues_List = {
	
	"ButtonA", -- KeyCode.ButtonA
	"ButtonB", -- KeyCode.ButtonB
	"ButtonX", -- KeyCode.ButtonX
	"ButtonY", -- KeyCode.ButtonY
	"ButtonLB", -- KeyCode.ButtonL1
	"ButtonLT", -- KeyCode.ButtonL2
	"ButtonLS", -- KeyCode.ButtonL3
	"ButtonRB", -- KeyCode.ButtonR1
	"ButtonRT", -- KeyCode.ButtonR2
	"ButtonRS", -- KeyCode.ButtonR3
	"ButtonStart", -- KeyCode.ButtonStart
	"ButtonSelect", -- KeyCode.ButtonSelect 
	
}

local PlayStation_ReturnValues_List = {
	
	"ButtonCross", -- KeyCode.ButtonA
	"ButtonCircle", -- KeyCode.ButtonB
	"ButtonSquare", -- KeyCode.ButtonX
	"ButtonTriangle", -- KeyCode.ButtonY
	"ButtonL1", -- KeyCode.ButtonL1
	"ButtonL2", -- KeyCode.ButtonL2
	"ButtonL3", -- KeyCode.ButtonL3
	"ButtonR1", -- KeyCode.ButtonR1
	"ButtonR2", -- KeyCode.ButtonR2
	"ButtonR3", -- KeyCode.ButtonR3
	"ButtonOptions", -- KeyCode.ButtonStart
	
	"ButtonTouchpad", -- KeyCode.ButtonSelect 
	"ButtonShare", -- KeyCode.ButtonSelect 

}

-- Note: Directional inputs have the same return value. This means, if a player presses a d-pad input, then the code knows it's a gamepad, but it doesn't know what type of gamepad. (PlayStation or Xbox, not sure.) 

---

userInputService.InputBegan:Connect(function(input)
	
	--print(input.KeyCode)
	
	-- Keyboard & Mouse Input: --
	if input.UserInputType == Enum.UserInputType.Keyboard then -- Keyboard inputs --
		if UserInputTypeSystemModule.inputTypeThePlayerIsUsing == "Gamepad" or UserInputTypeSystemModule.inputTypeThePlayerIsUsing == "Touch" then
			print("New InputType detected: Keyboard and Mouse")
			UserInputTypeSystemModule.inputTypeThePlayerIsUsing = "KeyboardAndMouse"
			InputTypeChangedRE:FireServer(UserInputTypeSystemModule.inputTypeThePlayerIsUsing)
			userInputService.MouseIconEnabled = true
			script.Parent:WaitForChild("IngameUI").MobileButtons.Visible = false
			return
		end
	end
	for i, mouseInputs in pairs (mouseInputType) do -- Mouse inputs --
		if input.UserInputType == mouseInputs  then
			if UserInputTypeSystemModule.inputTypeThePlayerIsUsing ~= "KeyboardAndMouse" then
				print("New InputType detected: Keyboard and Mouse")
				UserInputTypeSystemModule.inputTypeThePlayerIsUsing = "KeyboardAndMouse"
				InputTypeChangedRE:FireServer(UserInputTypeSystemModule.inputTypeThePlayerIsUsing)
				userInputService.MouseIconEnabled = true
				script.Parent:WaitForChild("IngameUI").MobileButtons.Visible = false
				return
			end
		end
	end
	----
	
		
	-- Gamepad Input: --

	for i, gamepadInput in pairs (GamepadInputsList) do -- Controller button inputs --
		if input.KeyCode == gamepadInput  then 
									
			if UserInputTypeSystemModule.inputTypeThePlayerIsUsing ~= "Gamepad" then
				print("New InputType detected: Gamepad")
				UserInputTypeSystemModule.inputTypeThePlayerIsUsing = "Gamepad"
				InputTypeChangedRE:FireServer(UserInputTypeSystemModule.inputTypeThePlayerIsUsing)
				userInputService.MouseIconEnabled = false
				script.Parent:WaitForChild("IngameUI").MobileButtons.Visible = false
			end
			
			local stringForKeyCodePressed = userInputService:GetStringForKeyCode(gamepadInput)
			
			for i, retunValue_Xbox in pairs(Xbox_ReturnValues_List) do
				if retunValue_Xbox == stringForKeyCodePressed then
					print(retunValue_Xbox,stringForKeyCodePressed)
					UserInputTypeSystemModule.gamepadTypeFromNewestInput = "Xbox"
				end
			end
			
			for i, returnValue_PlayStation in pairs(PlayStation_ReturnValues_List) do
				if returnValue_PlayStation == stringForKeyCodePressed then
					print(returnValue_PlayStation,stringForKeyCodePressed)
					UserInputTypeSystemModule.gamepadTypeFromNewestInput = "PlayStation"
				end
			end			
			
			if UserInputTypeSystemModule.gamepadTypeFromNewestInput ~= UserInputTypeSystemModule.gamepadType then
				-- player is now using a different type of gamepad than before
				
				UserInputTypeSystemModule.gamepadType = UserInputTypeSystemModule.gamepadTypeFromNewestInput
				InputTypeChangedRE:FireServer(UserInputTypeSystemModule.inputTypeThePlayerIsUsing)

				print(UserInputTypeSystemModule.gamepadType)
			end
					
		end
	end
	----
	
	
	-- Touchscreen input: --
	if input.UserInputType == Enum.UserInputType.Touch then
		if UserInputTypeSystemModule.inputTypeThePlayerIsUsing ~= "Touch" then -- if not mobile/touch input already, make it.
			UserInputTypeSystemModule.gamepadTypeFromNewestInput = "none"
			print("New InputType detected: Touch")
			UserInputTypeSystemModule.inputTypeThePlayerIsUsing = "Touch"
			InputTypeChangedRE:FireServer(UserInputTypeSystemModule.inputTypeThePlayerIsUsing)
			script.Parent:WaitForChild("IngameUI").MobileButtons.Visible = true
			
			local JumpButton_Path = script.Parent.TouchGui.TouchControlFrame:WaitForChild("JumpButton")
			JumpButton_Path.Position = UDim2.fromScale(0.845, 0.715)
			--JumpButton_Path.Size = UDim2.new(JumpButton_Path.Size.X*1.2,JumpButton_Path.Size.Y*1.2)
			
			local ToggleMobileButton_RemoteEvent = game.Workspace.RemoteEventsFolder.UI.ToggleMobileButtons
			ToggleMobileButton_RemoteEvent.OnClientEvent:Connect(function(whatButtonShouldBeToggled,toggleState)
				if whatButtonShouldBeToggled == "JumpButton" then
					if toggleState == false then
						JumpButton_Path.Visible = false
						print("Mobile Jump button toggled OFF")
					elseif toggleState == true then
						JumpButton_Path.Visible = true
						print("Mobile Jump button toggled ON")
					end
				end
			end)
			
			return
		end
	end
	----

end)

return UserInputTypeSystemModule


Here’s a link to my game: PB & Jay | In-dev - Roblox

2 Likes

It would be wasted effort to have all developers spend hours making an icons module to represent pretty keyboard and console icons. There’s already icons for keys in the escape menu which look better. We should be able to access different styles like that!

Enum.KeyCodeStyle.Solid -- current
Enum.KeyCodeStyle.Dark
Enum.KeyCodeStyle.Light
Enum.KeyCodeStyle.Outline -- escape menu, playerlist, etc
Enum.KeyCodeStyle.Legacy -- icons still used in old coregui

If we have to just code our own keymapping, I’d just use my own system entirely.

3 Likes

PlayStation Screenshot 2023-09-29 093213

Xbox

Works for me when i plugged my PS4 Controller to my PC

1 Like

-- that’s entirely a you problem if you can’t learn which way is east and which is west, especially if you would be working with those terms regularly
-- every tool i use outside of roblox calls generic face buttons by NSEW, and having a name as long as “buttondirectionright” for one of the most commonly used buttons, let alone how easy it is to be confused with the d-pad, is just objectively a downgrade

https://devforum.roblox.com/t/vector-images-stretchable/24352/15

Yeah… I don’t think they’ll revisit.

Do this next

Will we be able to use the touchpad? I see a bunch of things that will be easier to do (and code) with a touchpad instead of the default layout.

I implemented this API in a weekly patch and it seems the MS Store client never got this API, I’m getting error reports of GetImageForKeyCode is not a valid member of UserInputService from the handful of users using the MS Store client.

4 Likes

On the subject, any chance of a gamepad gyroscope API? :thinking: I remember the idea getting shot down a few years back since only Xbox controllers (which don’t have a gyroscope) were officially supported - but with the PlayStation launch I’m hoping the team can revisit.

6 Likes

Hey Roblox Staff, I just wanted to mention that when the game releases on PS5, I think it would be cool if you allowed game developers to access the PS5 Dualsense Controller Adaptive Triggers through the scripting. Same thing if PC players use the PS5 Dualsense on PC.

4 Likes

Are we able to script the controllers vibrate? (I forgot what the vibrate is normaly called)

This may have already been addressed so I do apologize if this reply is redundant.

On future platforms that Roblox decides to ship on, will the mappings for that platform’s KeyCodes be based on that platform’s UX, or will it be based on button placement?

My current fear is that without introducing new KeyCodes for new platforms and instead just remapping new platforms to the Xbox platform, you’ll eventually run into the issue where for example, on a Nintendo Switch the A/B buttons are inverted in relation to an Xbox controller - however, ButtonA is still to confirm and ButtonB is to cancel. If ButtonA on Xbox is directly mapped based on location to ButtonB on Nintendo Switch, it becomes impossible to fix the UX as developers will be unable to rebind anything using ContextActionService.

Hi,

Please check out this HapticService | Documentation - Roblox Creator Hub

1 Like

Hi!

This is a great question, currently the idea is to map the current abxy key codes in the Xbox layout to whatever new platform Roblox may ship to. This would be KeyCode.ButtonA would map to the B button on the switch controller and the API listed here will correctly give you the image to display. In this way, your experience mappings will “just work”. A Switch controller connected to a PC and playing Roblox should work this way already.

There are no plans to release key codes per platform, this adds work for every developer to support new platforms and would require older experiences to be updated, many of which may not have active development. To keep these older experiences working, the existing keycodes are the ones we will continue to support.

Thanks

3 Likes

image
image
It seems like the buttons on Dialog hasn’t been updated to work with playstation buttons.

2 Likes

Hello,

This would be KeyCode.ButtonA would map to the B button on the switch controller and the API listed here will correctly give you the image to display. In this way, your experience mappings will “just work”.

I understand how this would “just work” for returning the images to display, however my concern lies within utilizing ContextActionService to bind certain actions and menus within my experience. You directly stated ButtonA would be mapped to ButtonB on a Switch and no new KeyCodes would be created, meaning as a developer we will basically just have to bind our confirm actions to ButtonA for Xbox and anyone on a Switch will just have to deal with a horrible user experience - as they expect opposite behavior from those buttons.

Surely you would want to prioritize maintaining the expected user experience on new platforms otherwise you’re directly inhibiting the success of Roblox to a degree as it’s brought to these new platforms.

this adds work for every developer to support new platforms

As a developer, I could Ctrl+F my code and search for anywhere I utilize ContextActionService and simply add KeyCode.ButtonCross next to anywhere I currently have KeyCode.ButtonA.

and would require older experiences to be updated

This is the only real concern I could see with the introduction of new KeyCodes. Old KeyCodes could retain functionality but be deprecated and removed from the public API just as many other things have been in the past, and any old experiences utilizing KeyCode.ButtonA alone could then fall into a “failsafe” where ButtonCross on PlayStation and ButtonB on Switch are default binded. This would result in 0 work for developers and would simply require a bit more creativity on the Roblox side.

A portion of my experience’s success is reliant on my UX, people have entire careers in solely UX, however if I have no control over fixing my UX, then why would I bother with releasing my experience on these new platforms as I’m inherently going to worsen not only my player retention, but also my Like:Dislike ratio.

Thanks for the report, we’ll look into it.

1 Like

I understand where you’re coming from and appreciate the detailed feedback. For now we’re interested in keeping the button layouts the same rather than the actual images that appear as well as maintainable long term solutions. I suggest posting these concerns in a feature request so that it is logged for future reference.

Thanks!

1 Like

Heres a spritesheet for playstation buttons i put together
PS4 Spritesheet

ill probably put one together for nintendo switch if roblox comes out to that

14 Likes

Also by the way controller haptics don’t work with the PlayStation Controller