diff --git a/core/input/input.cpp b/core/input/input.cpp index cf8d71b9a74..d481acf0055 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -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("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); ClassDB::bind_method(D_METHOD("get_joy_vibration_duration", "device"), &Input::get_joy_vibration_duration); @@ -1498,6 +1499,11 @@ String Input::get_joy_guid(int p_device) const { return joy_names[p_device].uid; } +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); +} + TypedArray Input::get_connected_joypads() { TypedArray ret; HashMap::Iterator elem = joy_names.begin(); @@ -1542,6 +1548,27 @@ Input::Input() { } } + String env_ignore_devices = OS::get_singleton()->get_environment("SDL_GAMECONTROLLER_IGNORE_DEVICES"); + if (!env_ignore_devices.is_empty()) { + Vector entries = env_ignore_devices.split(","); + for (int i = 0; i < entries.size(); i++) { + Vector vid_pid = entries[i].split("/"); + + if (vid_pid.size() < 2) { + continue; + } + + print_verbose(vformat("Device Ignored -- Vendor: %s Product: %s", vid_pid[0], vid_pid[1])); + const uint16_t vid_unswapped = vid_pid[0].hex_to_int(); + const uint16_t pid_unswapped = vid_pid[1].hex_to_int(); + const uint16_t vid = BSWAP16(vid_unswapped); + const uint16_t pid = BSWAP16(pid_unswapped); + + uint32_t full_id = (((uint32_t)vid) << 16) | ((uint16_t)pid); + ignored_device_ids.insert(full_id); + } + } + legacy_just_pressed_behavior = GLOBAL_DEF("input_devices/compatibility/legacy_just_pressed_behavior", false); if (Engine::get_singleton()->is_editor_hint()) { // Always use standard behavior in the editor. diff --git a/core/input/input.h b/core/input/input.h index 9cc596ee903..ec16871b728 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -154,6 +154,9 @@ private: VelocityTrack mouse_velocity_track; HashMap touch_velocity_track; HashMap joy_names; + + HashSet ignored_device_ids; + int fallback_mapping = -1; CursorShape default_shape = CURSOR_ARROW; @@ -328,6 +331,7 @@ public: 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; void set_fallback_mapping(String p_guid); void flush_buffered_events(); diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index cea8e66e528..bed65e277da 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -343,6 +343,15 @@ [b]Note:[/b] This value can be immediately overwritten by the hardware sensor value on Android and iOS. + + + + + + Queries whether an input device should be ignored or not. Devices can be ignored by setting the environment variable [code]SDL_GAMECONTROLLER_IGNORE_DEVICES[/code]. Read the [url=https://wiki.libsdl.org/SDL2]SDL documentation[/url] for more information. + [b]Note:[/b] Some 3rd party tools can contribute to the list of ignored devices. For example, [i]SteamInput[/i] creates virtual devices from physical devices for remapping purposes. To avoid handling the same input device twice, the original device is added to the ignore list. + + diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp index ab79885fb48..363fd7cd4d4 100644 --- a/platform/linuxbsd/joypad_linux.cpp +++ b/platform/linuxbsd/joypad_linux.cpp @@ -391,6 +391,16 @@ void JoypadLinux::open_joypad(const char *p_path) { return; } + uint16_t vendor = BSWAP16(inpid.vendor); + uint16_t product = BSWAP16(inpid.product); + uint16_t version = BSWAP16(inpid.version); + + if (input->should_ignore_device(vendor, product)) { + // This can be true in cases where Steam is passing information into the game to ignore + // original gamepads when using virtual rebindings (See SteamInput). + return; + } + MutexLock lock(joypads_mutex[joy_num]); Joypad &joypad = joypads[joy_num]; joypad.reset(); @@ -399,10 +409,6 @@ 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) { - uint16_t vendor = BSWAP16(inpid.vendor); - uint16_t product = BSWAP16(inpid.product); - uint16_t version = BSWAP16(inpid.version); - 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); } else {