Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Input.get_joy_type() to get controller type #8519

Open
timothyqiu opened this issue Nov 25, 2023 · 5 comments
Open

Add Input.get_joy_type() to get controller type #8519

timothyqiu opened this issue Nov 25, 2023 · 5 comments

Comments

@timothyqiu
Copy link
Member

Describe the project you are working on

Platformer.

Describe the problem or limitation you are having in your project

When interaction is available, an interaction key icon is shown above the player.

I want it to display A when Switch controller is used, display B when XBox controller is used, and display Circle when PlayStation controller is used. Otherwise defaults to a generic icon (highlighted east key among the four keys).

The only way to distinguish between these controller types seems to be Input.get_joy_name().

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Add Input.get_joy_type() that returns either:

  • one of JOY_TYPE_UNKNOWN, JOY_TYPE_XBOX, JOY_TYPE_PLAYSTATION, and JOY_TYPE_NINTENDO.
  • a normalized string for easy extention like {family}-{model}

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Use something like this mapping: https://github.com/libsdl-org/SDL/blob/main/src/joystick/controller_list.h

But I'm not sure what the CONTROLLER_ID is in Godot.

If this enhancement will not be used often, can it be worked around with a few lines of script?

Partially. Using good old way of parsing Input.get_joy_name() can detect some controllers.

Controller icon libraries using this method already exist in AssetLib. But how they parse the name differ and are quite basic (e.g. not able to detect common non-official controllers).

Is there a reason why this should be core and not an add-on in the asset library?

Parsing names are not reliable. Probably needs information that is not exposed.

@KoBeWi
Copy link
Member

KoBeWi commented Nov 25, 2023

I want it to display A when Switch controller is used, display B when XBox controller is used, and display Circle when PlayStation controller is used.

These controllers have easily recognizable names when used with get_joy_name(). I don't know how else the function you propose would be implemented.

Which means that you can use this code:
https://github.com/KoBeWi/Godot-Action-Icon/blob/13406c2e23eb8f1f4637f6b6d5e93398d0676533/addons/ActionIcon/ActionIcon.gd#L353-L364

@timothyqiu
Copy link
Member Author

timothyqiu commented Nov 26, 2023

I don't think it's that easy.

Here is another plugin that tries to recognize controller type by name: https://github.com/rsubtil/controller_icons/blob/38d66dd664840c7b7148533dcc67e336da886073/addons/controller_icons/Mapper.gd#L35

Godot recognizes 4051 controllers. You guys disagree with each other for at least 45 of them if unknown result returned from the latter is treated as XBox. Otherwise, you only reach an agreement for 11% of these controllers.

And both of these two plugins recognize my "8BitDo SN30 Pro", which is in the list of controllers recognized by Godot, as an XBox controller, but it's in fact a Nintendo controller.

No matter whether name parsing is the only way to implement this:

  • It's not that easy. Lots of corner cases for commonly used controllers.
  • Plugins don't agree with each other, so it's confusing which one to use (which one is correct / more accurate).
  • If there's a pattern that most plugins agree to use, then why not include it in the engine?

Footnotes

  1. As listed in gamecontrollerdb.txt and godotcontrollerdb.txt.

@Calinou
Copy link
Member

Calinou commented Nov 27, 2023

Indeed, many 3rd-party controller brands like SCUF feature layouts that are 100% compatible with a standard controller type (Xbox in SCUF's case). However, I don't think gamecontrollerdb.txt stores exact information on this.

Also, it begs the question of how accurate the controller type should be. Should it report the precise generation (e.g. distinguish PS4 and PS51, Xbox 360 and Xbox One/Series2)? These should preferably have different button prompt icons to best match the actual controller.

Footnotes

  1. Buttons are colored on PS4, not on PS5.

  2. ABXY button colors are different.

@stephanbogner
Copy link

I came to the same conclusion (@timothyqiu) that it's not as trivial. A while ago I opened a discussion on a related topic.

A few remarks:

1.) Interplay between InputMap, Input and Action

Another argument why this should be core is that InputMap, Input (Device) and Action need to work together here:

  1. Show an image of the correct controller (requires the player's current input device)
  2. Show the correct input prompt to the user (requires the player's current input device, the required action and the input map configuration)

2.) joy_type also for joypads, not just input:

get_joy_type() should exist as well for joypads
→ Allows you to show an appropriate icon / logo for a connected joypad

3.) Additonals details, not just type

The returned value could also be a class that contains more details. Something like:

  • Family / platform: Nintendo
  • Generation / console: Nintendo Switch
  • Controller: Joy-Con or Nintendo Switch Pro Controller

→ If you only want to differentiate between Playstation, Xbox and Nintendo the family is enough. If you want to be more precise, you can use the other values. (Related to what @Calinou wrote)

4.) All lowercase vs. common writing

I am not sure yet but it might be good to store values how they are normally/officially written: Joy-Con vs. joycon
→ Would allow you to display information to the player in how they commonly read it

5.) Get the button name

Some functionality should exist to get the button's name. It could be based on Input but more likely it would be should be based on InputMap by joy_type/platform.

Note: Actions can be bound to multiple buttons so this would likely be an array, so take it as a simplification

  • InputMap.get_button_name('jump', 'playstation-5-controller')circle
  • InputMap.get_button_name('jump', 'xbox-series-controller')B
  • InputMap.get_button_name('attack', 'playstation-5-controller')cross
  • InputMap.get_button_name('attack', 'xbox-series-controller')A

→ This would allow to display correct input prompts even without images

I currently have it the other way round where I have images called lower_action_button.png which are then different for each platform.

6.) Sticks

It gets even more complicated when it comes to sticks because 1 stick is normally split into up, down, left, right. This makes sense because you can bind it how you want (especially on PC and regarding a11y) but makes things more complicated when it comes to showing input prompts.

Final thoughts

  • I think the biggest chunk of work would be to map the SDL_GameControllerDB's device IDs to the appropriate controller type / family / generation (see my discussion point for more but older thoughts)
  • The rest of the work would be exposing that information in various places in the API which would shouldn't be too hard

@Rubonnek
Copy link
Member

Rubonnek commented May 3, 2024

But I'm not sure what the CONTROLLER_ID is in Godot.

Turns out it's currently possible to extract the vendor id (nVID) and the product id (nPID) but only in Linux with Godot:

	var dict : Dictionary = Input.get_joy_info(0)
	print("nVID: 0x%04x" % dict["vendor_id"])
	print("nPID: 0x%04x" % dict["product_id"])

In Windows this is not currently exposed, but I believe those values are already extracted in joypad_windows.cpp. Seems like it's a matter of passing those values through the joy_connection_changed call through a dictionary for consistency.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants