Gamepad APIs: Cross-Platform Button Support

One feature I would absolutely love would be 1. a get image API for keyboard and mouse inputs, so we can show graphics to guide players to the right key presses or mouse clicks. 2. an API for detecting whether a user is on MacOS or Windows (so we can display the correct keys for the user, i.e: windows key vs command key)

2 Likes

and just like that, we’re ready for PlayStation! Great feature, thanks to everyone involved! I’ve been waiting for this to release since Playstation was announced at RDC.

image

3 Likes

what you do to get it like this?

1 Like

Great, here are all of the missing ones;

image



1 Like

nice ill try this with my experiences that support console

1 Like

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