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 the ability to get per-platform information for joypads #78539

Merged
merged 1 commit into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion core/input/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_joy_axis", "device", "axis"), &Input::get_joy_axis);
ClassDB::bind_method(D_METHOD("get_joy_name", "device"), &Input::get_joy_name);
ClassDB::bind_method(D_METHOD("get_joy_guid", "device"), &Input::get_joy_guid);
ClassDB::bind_method(D_METHOD("get_joy_info", "device"), &Input::get_joy_info);
ClassDB::bind_method(D_METHOD("should_ignore_device", "vendor_id", "product_id"), &Input::should_ignore_device);
ClassDB::bind_method(D_METHOD("get_connected_joypads"), &Input::get_connected_joypads);
ClassDB::bind_method(D_METHOD("get_joy_vibration_strength", "device"), &Input::get_joy_vibration_strength);
Expand Down Expand Up @@ -437,11 +438,12 @@ static String _hex_str(uint8_t p_byte) {
return ret;
}

void Input::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid) {
void Input::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid, Dictionary p_joypad_info) {
_THREAD_SAFE_METHOD_
Joypad js;
js.name = p_connected ? p_name : "";
js.uid = p_connected ? p_guid : "";
js.info = p_connected ? p_joypad_info : Dictionary();

if (p_connected) {
String uidname = p_guid;
Expand Down Expand Up @@ -1499,6 +1501,11 @@ String Input::get_joy_guid(int p_device) const {
return joy_names[p_device].uid;
}

Dictionary Input::get_joy_info(int p_device) const {
ERR_FAIL_COND_V(!joy_names.has(p_device), Dictionary());
return joy_names[p_device].info;
}

bool Input::should_ignore_device(int p_vendor_id, int p_product_id) const {
uint32_t full_id = (((uint32_t)p_vendor_id) << 16) | ((uint16_t)p_product_id);
return ignored_device_ids.has(full_id);
Expand Down
4 changes: 3 additions & 1 deletion core/input/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ class Input : public Object {
HatMask last_hat = HatMask::CENTER;
int mapping = -1;
int hat_current = 0;
Dictionary info;
};

VelocityTrack mouse_velocity_track;
Expand Down Expand Up @@ -276,7 +277,7 @@ class Input : public Object {
Vector2 get_joy_vibration_strength(int p_device);
float get_joy_vibration_duration(int p_device);
uint64_t get_joy_vibration_timestamp(int p_device);
void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = "");
void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = "", Dictionary p_joypad_info = Dictionary());

Vector3 get_gravity() const;
Vector3 get_accelerometer() const;
Expand Down Expand Up @@ -332,6 +333,7 @@ class Input : public Object {
bool is_joy_known(int p_device);
String get_joy_guid(int p_device) const;
bool should_ignore_device(int p_vendor_id, int p_product_id) const;
Dictionary get_joy_info(int p_device) const;
void set_fallback_mapping(String p_guid);

void flush_buffered_events();
Expand Down
14 changes: 14 additions & 0 deletions doc/classes/Input.xml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,20 @@
Returns a SDL2-compatible device GUID on platforms that use gamepad remapping, e.g. [code]030000004c050000c405000000010000[/code]. Returns [code]"Default Gamepad"[/code] otherwise. Godot uses the [url=https://github.com/gabomdq/SDL_GameControllerDB]SDL2 game controller database[/url] to determine gamepad names and mappings based on this GUID.
</description>
</method>
<method name="get_joy_info" qualifiers="const">
<return type="Dictionary" />
<param index="0" name="device" type="int" />
<description>
Returns a dictionary with extra platform-specific information about the device, e.g. the raw gamepad name from the OS or the Steam Input index.
EIREXE marked this conversation as resolved.
Show resolved Hide resolved
On Windows the dictionary contains the following fields:
[code]xinput_index[/code]: The index of the controller in the XInput system.
On Linux:
[code]raw_name[/code]: The name of the controller as it came from the OS, before getting renamed by the godot controller database.
[code]vendor_id[/code]: The USB vendor ID of the device.
[code]product_id[/code]: The USB product ID of the device.
[code]steam_input_index[/code]: The Steam Input gamepad index, if the device is not a Steam Input device this key won't be present.
</description>
</method>
<method name="get_joy_name">
<return type="String" />
<param index="0" name="device" type="int" />
Expand Down
25 changes: 24 additions & 1 deletion platform/linuxbsd/joypad_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@
static const char *ignore_str = "/dev/input/js";
#endif

// On Linux with Steam Input Xbox 360 devices have an index appended to their device name, this index is
// the Steam Input gamepad index
#define VALVE_GAMEPAD_NAME_PREFIX "Microsoft X-Box 360 pad "
// IDs used by Steam Input virtual controllers.
// See https://partner.steamgames.com/doc/features/steam_controller/steam_input_gamepad_emulation_bestpractices
#define VALVE_GAMEPAD_VID 0x28DE
#define VALVE_GAMEPAD_PID 0x11FF

JoypadLinux::Joypad::~Joypad() {
for (int i = 0; i < MAX_ABS; i++) {
if (abs_info[i]) {
Expand Down Expand Up @@ -411,8 +419,23 @@ void JoypadLinux::open_joypad(const char *p_path) {
setup_joypad_properties(joypad);
sprintf(uid, "%04x%04x", BSWAP16(inpid.bustype), 0);
if (inpid.vendor && inpid.product && inpid.version) {
Dictionary joypad_info;
joypad_info["vendor_id"] = inpid.vendor;
joypad_info["product_id"] = inpid.product;
joypad_info["raw_name"] = name;

sprintf(uid + String(uid).length(), "%04x%04x%04x%04x%04x%04x", vendor, 0, product, 0, version, 0);
input->joy_connection_changed(joy_num, true, name, uid);

if (inpid.vendor == VALVE_GAMEPAD_VID && inpid.product == VALVE_GAMEPAD_PID) {
if (name.begins_with(VALVE_GAMEPAD_NAME_PREFIX)) {
String idx_str = name.substr(strlen(VALVE_GAMEPAD_NAME_PREFIX));
if (idx_str.is_valid_int()) {
joypad_info["steam_input_index"] = idx_str.to_int();
}
}
}

input->joy_connection_changed(joy_num, true, name, uid, joypad_info);
} else {
String uidname = uid;
int uidlen = MIN(name.length(), 11);
Expand Down
4 changes: 3 additions & 1 deletion platform/windows/joypad_windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,9 @@ void JoypadWindows::probe_joypads() {
x_joypads[i].ff_end_timestamp = 0;
x_joypads[i].vibrating = false;
attached_joypads[id] = true;
input->joy_connection_changed(id, true, "XInput Gamepad", "__XINPUT_DEVICE__");
Dictionary joypad_info;
joypad_info["xinput_index"] = (int)i;
input->joy_connection_changed(id, true, "XInput Gamepad", "__XINPUT_DEVICE__", joypad_info);
}
} else if (x_joypads[i].attached) {
x_joypads[i].attached = false;
Expand Down